Skip to content

Commit 4cf6def

Browse files
sokoloff06androidseb
authored andcommitted
[google_adsense] (Experimental) AdSense plugin for Flutter Web (flutter#6871)
Google Adsense plugin should allow Flutter Web developers to integrate Adsense more easily and monetize web project. *List which issues are fixed by this PR. You must list at least one issue.* flutter/flutter#40376
1 parent 924b663 commit 4cf6def

35 files changed

+1470
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ packages/flutter_migrate/** @stuartmorgan
1818
packages/flutter_template_images/** @stuartmorgan
1919
packages/go_router/** @chunhtai
2020
packages/go_router_builder/** @chunhtai
21+
packages/google_adsense/** @sokoloff06
2122
packages/google_identity_services_web/** @ditman
2223
packages/google_maps_flutter/** @stuartmorgan
2324
packages/google_sign_in/** @stuartmorgan

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ These are the packages hosted in this repository:
5454
| [flutter\_template\_images](./packages/flutter_template_images/) | [![pub package](https://img.shields.io/pub/v/flutter_template_images.svg)](https://pub.dev/packages/flutter_template_images) | [![pub points](https://img.shields.io/pub/points/flutter_template_images)](https://pub.dev/packages/flutter_template_images/score) | [![popularity](https://img.shields.io/pub/popularity/flutter_template_images)](https://pub.dev/packages/flutter_template_images/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_template_images?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_template_images) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20flutter_template_images?label=)](https://github.com/flutter/packages/labels/p%3A%20flutter_template_images) |
5555
| [go\_router](./packages/go_router/) | [![pub package](https://img.shields.io/pub/v/go_router.svg)](https://pub.dev/packages/go_router) | [![pub points](https://img.shields.io/pub/points/go_router)](https://pub.dev/packages/go_router/score) | [![popularity](https://img.shields.io/pub/popularity/go_router)](https://pub.dev/packages/go_router/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20go_router?label=)](https://github.com/flutter/flutter/labels/p%3A%20go_router) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20go_router?label=)](https://github.com/flutter/packages/labels/p%3A%20go_router) |
5656
| [go\_router\_builder](./packages/go_router_builder/) | [![pub package](https://img.shields.io/pub/v/go_router_builder.svg)](https://pub.dev/packages/go_router_builder) | [![pub points](https://img.shields.io/pub/points/go_router_builder)](https://pub.dev/packages/go_router_builder/score) | [![popularity](https://img.shields.io/pub/popularity/go_router_builder)](https://pub.dev/packages/go_router_builder/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20go_router_builder?label=)](https://github.com/flutter/flutter/labels/p%3A%20go_router_builder) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20go_router_builder?label=)](https://github.com/flutter/packages/labels/p%3A%20go_router_builder) |
57+
| [google\_adsense](./packages/google_adsense/)| [![pub package](https://img.shields.io/pub/v/google_adsense.svg)](https://pub.dev/packages/google_adsense) | [![pub points](https://img.shields.io/pub/points/google_adsense)](https://pub.dev/packages/google_adsense/score) | [![popularity](https://img.shields.io/pub/popularity/google_adsense)](https://pub.dev/packages/google_adsense/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20google_adsense?label=)](https://github.com/flutter/flutter/labels/p%3A%20google_adsense) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20google_adsense?label=)](https://github.com/flutter/packages/labels/p%3A%20google_adsense) |
5758
| [google\_maps\_flutter](./packages/google_maps_flutter/) | [![pub package](https://img.shields.io/pub/v/google_maps_flutter.svg)](https://pub.dev/packages/google_maps_flutter) | [![pub points](https://img.shields.io/pub/points/google_maps_flutter)](https://pub.dev/packages/google_maps_flutter/score) | [![popularity](https://img.shields.io/pub/popularity/google_maps_flutter)](https://pub.dev/packages/google_maps_flutter/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20maps?label=)](https://github.com/flutter/flutter/labels/p%3A%20maps) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20google_maps_flutter?label=)](https://github.com/flutter/packages/labels/p%3A%20google_maps_flutter) |
5859
| [google\_sign\_in](./packages/google_sign_in/) | [![pub package](https://img.shields.io/pub/v/google_sign_in.svg)](https://pub.dev/packages/google_sign_in) | [![pub points](https://img.shields.io/pub/points/google_sign_in)](https://pub.dev/packages/google_sign_in/score) | [![popularity](https://img.shields.io/pub/popularity/google_sign_in)](https://pub.dev/packages/google_sign_in/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20google_sign_in?label=)](https://github.com/flutter/flutter/labels/p%3A%20google_sign_in) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20google_sign_in?label=)](https://github.com/flutter/packages/labels/p%3A%20google_sign_in) |
5960
| [image\_picker](./packages/image_picker/) | [![pub package](https://img.shields.io/pub/v/image_picker.svg)](https://pub.dev/packages/image_picker) | [![pub points](https://img.shields.io/pub/points/image_picker)](https://pub.dev/packages/image_picker/score) | [![popularity](https://img.shields.io/pub/popularity/image_picker)](https://pub.dev/packages/image_picker/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20image_picker?label=)](https://github.com/flutter/flutter/labels/p%3A%20image_picker) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20image_picker?label=)](https://github.com/flutter/packages/labels/p%3A%20image_picker) |

packages/google_adsense/AUTHORS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Below is a list of people and organizations that have contributed
2+
# to the Flutter project. Names should be added to the list like so:
3+
#
4+
# Name/Organization <email address>
5+
6+
Google Inc.
7+
The Chromium Authors

packages/google_adsense/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.0.1
2+
3+
* Initial release.

packages/google_adsense/LICENSE

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright 2013 The Flutter Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/google_adsense/README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# google_adsense
2+
[Google AdSense](https://adsense.google.com/intl/en_us/start/) plugin for Flutter Web
3+
4+
This package initializes AdSense on your website and provides an ad unit `Widget` that can be configured and placed in the desired location in your Flutter web app UI, without having to directly modify the HTML markup of the app directly.
5+
6+
## Disclaimer: Early Access ⚠️
7+
This package is currently in early access and is provided as-is. While it's open source and publicly available, it's likely that you'll need to make additional customizations and configurations to fully integrate it with your Flutter Web App.
8+
Please express interest joining Early Access program using [this form](https://docs.google.com/forms/d/e/1FAIpQLSdN6aOwVkaxGdxbVQFVZ_N4_UCBkuWYa-cS4_rbU_f1jK10Tw/viewform)
9+
10+
## Usage
11+
12+
### Setup your AdSense account
13+
1. [Make sure your site's pages are ready for AdSense](https://support.google.com/adsense/answer/7299563?hl=en&sjid=5790642343077592212-EU&visit_id=638657100661171978-1373860041&ref_topic=1319756&rd=1)
14+
2. [Create your AdSense account](https://support.google.com/adsense/answer/10162?hl=en&sjid=5790642343077592212-EU&visit_id=638657100661171978-1373860041&ref_topic=1250103&rd=1)
15+
16+
### Initialize AdSense
17+
To start displaying ads, initialize the AdSense with your [client/publisher ID](https://support.google.com/adsense/answer/105516?hl=en&sjid=5790642343077592212-EU) (only use numbers).
18+
<?code-excerpt "example/lib/main.dart (init)"?>
19+
```dart
20+
import 'package:google_adsense/experimental/google_adsense.dart';
21+
22+
void main() {
23+
adSense.initialize(
24+
'0123456789012345'); // TODO: Replace with your Publisher ID (pub-0123456789012345) - https://support.google.com/adsense/answer/105516?hl=en&sjid=5790642343077592212-EU
25+
runApp(const MyApp());
26+
}
27+
28+
```
29+
30+
### Enable Auto Ads
31+
In order to start displaying [Auto ads](https://support.google.com/adsense/answer/9261805?hl=en) make sure to configure this feature in your AdSense Console. If you want to display ad units within your app content, continue to the next step
32+
33+
### Display ad unit Widget
34+
35+
1. Create [ad units](https://support.google.com/adsense/answer/9183549?hl=en&ref_topic=9183242&sjid=5790642343077592212-EU) in your AdSense account
36+
2. Use relevant `AdUnitConfiguration` constructor as per table below
37+
38+
| Ad Unit Type | `AdUnitConfiguration` constructor method |
39+
|----------------|--------------------------------------------|
40+
| Display Ads | `AdUnitConfiguration.displayAdUnit(...)` |
41+
| In-feed Ads | `AdUnitConfiguration.inFeedAdUnit(...)` |
42+
| In-article Ads | `AdUnitConfiguration.inArticleAdUnit(...)` |
43+
| Multiplex Ads | `AdUnitConfiguration.multiplexAdUnit(...)` |
44+
45+
3. Translate data-attributes from snippet generated in AdSense Console into constructor arguments as described below:
46+
- drop `data-` prefix
47+
- translate kebab-case to camelCase
48+
- no need to translate `data-ad-client` as it the value was already passed at initialization
49+
50+
For example snippet below
51+
```html
52+
<ins class="adsbygoogle"
53+
style="display:block"
54+
data-ad-client="ca-pub-0123456789012345"
55+
data-ad-slot="1234567890"
56+
data-ad-format="auto"
57+
data-full-width-responsive="true"></ins>
58+
<script>
59+
(adsbygoogle = window.adsbygoogle || []).push({});
60+
</script>
61+
```
62+
translates into
63+
<?code-excerpt "example/lib/main.dart (init-min)"?>
64+
```dart
65+
adSense.initialize(
66+
'0123456789012345'); // TODO: Replace with your Publisher ID (pub-0123456789012345) - https://support.google.com/adsense/answer/105516?hl=en&sjid=5790642343077592212-EU
67+
```
68+
and
69+
<?code-excerpt "example/lib/main.dart (adUnit)"?>
70+
```dart
71+
adSense.adUnit(AdUnitConfiguration.displayAdUnit(
72+
adSlot: '1234567890', // TODO: Replace with your Ad Unit ID
73+
adFormat: AdFormat
74+
.AUTO, // Remove AdFormat to make ads limited by height
75+
))
76+
```
77+
78+
#### Customize ad unit Widget
79+
To [modify your responsive ad code](https://support.google.com/adsense/answer/9183363?hl=en&ref_topic=9183242&sjid=11551379421978541034-EU):
80+
1. Make sure to follow [AdSense policies](https://support.google.com/adsense/answer/1346295?hl=en&sjid=18331098933308334645-EU&visit_id=638689380593964621-4184295127&ref_topic=1271508&rd=1)
81+
2. Use Flutter instruments for [adaptive and responsive design](https://docs.flutter.dev/ui/adaptive-responsive)
82+
83+
For example, when not using responsive `AdFormat` it is recommended to wrap adUnit widget in the `Container` with width and/or height constraints.
84+
Note some [policies and restrictions](https://support.google.com/adsense/answer/9185043?hl=en#:~:text=Policies%20and%20restrictions) related to ad unit sizing:
85+
86+
<?code-excerpt "example/lib/main.dart (constraints)"?>
87+
```dart
88+
Container(
89+
constraints:
90+
const BoxConstraints(maxHeight: 100, maxWidth: 1200),
91+
padding: const EdgeInsets.only(bottom: 10),
92+
child: adSense.adUnit(AdUnitConfiguration.displayAdUnit(
93+
adSlot: '1234567890', // TODO: Replace with your Ad Unit ID
94+
adFormat: AdFormat
95+
.AUTO, // Not using AdFormat to make ad unit respect height constraint
96+
)),
97+
),
98+
```
99+
## Testing and common errors
100+
101+
### Failed to load resource: the server responded with a status of 400
102+
Make sure to set correct values to adSlot and adClient arguments
103+
104+
### Failed to load resource: the server responded with a status of 403
105+
1. When happening in **testing/staging** environment it is likely related to the fact that ads are only filled when requested from an authorized domain. If you are testing locally and running your web app on `localhost`, you need to:
106+
1. Set custom domain name on localhost by creating a local DNS record that would point `127.0.0.1` and/or `localhost` to `your-domain.com`. On mac/linux machines this can be achieved by adding the following records to you /etc/hosts file:
107+
`127.0.0.1 your-domain.com`
108+
`localhost your-domain.com`
109+
2. Specify additional run arguments in IDE by editing `Run/Debug Configuration` or by passing them directly to `flutter run` command:
110+
`--web-port=8080`
111+
`--web-hostname=your-domain.com`
112+
2. When happening in **production** it might be that your domain was not yet approved or was disapproved. Login to your AdSense account to check your domain approval status
113+
114+
### Ad unfilled
115+
116+
There is no deterministic way to make sure your ads are 100% filled even when testing. Some of the way to increase the fill rate:
117+
- Try setting `adTest` parameter to `true`
118+
- Try setting AD_FORMAT to `auto` (default setting)
119+
- Try setting FULL_WIDTH_RESPONSIVE to `true` (default setting)
120+
- Try resizing the window or making sure that ad unit Widget width is less than ~1200px
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## See https://github.com/dart-lang/test/blob/master/pkgs/test/doc/configuration.md#arguments
2+
#override_platforms:
3+
# chrome:
4+
# settings:
5+
# executable: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
6+
# arguments: --no-sandbox
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# google_adsense_example
2+
3+
An example demonstrating google_adsense Flutter plugin usage
4+
5+
## Screenshots
6+
7+
![Screenshot of the test app showing an ad on mobile](../example/images/mobile_screenshot.png)
8+
![Screenshot of the test app showing an ad on desktop](../example/images/desktop_screenshot.jpg)
9+
10+
11+
12+
## Testing
13+
14+
This package uses `package:integration_test` to run its tests in a web browser.
15+
16+
See [Plugin Tests > Web Tests](https://github.com/flutter/flutter/blob/master/docs/ecosystem/testing/Plugin-Tests.md#web-tests)
17+
in the Flutter documentation for instructions to set up and run the tests in this package.
18+
19+
Check [flutter.dev > Integration testing](https://docs.flutter.dev/testing/integration-tests)
20+
for more info.
21+
282 KB
Loading
2.06 MB
Loading

0 commit comments

Comments
 (0)