Skip to content

Commit

Permalink
Merge pull request flutter#1 from ditman/adsense-js-interop
Browse files Browse the repository at this point in the history
Tweaks to the google_adsense package.
  • Loading branch information
sokoloff06 authored Nov 17, 2024
2 parents c509169 + 4175da6 commit 36d2550
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ void main() async {
});

group('initialization', () {
testWidgets('Repeated initialization throws error', (WidgetTester _) async {
adsense.initialize(testClient);
expect(() => adsense.initialize(testClient), throwsA(isA<StateError>()));
});

testWidgets('Initialization adds AdSense snippet to index.html',
(WidgetTester _) async {
// Given
Expand Down
58 changes: 28 additions & 30 deletions packages/google_adsense/lib/src/ad_unit_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import 'package:flutter/foundation.dart';

import '../google_adsense.dart';

/// AdUnit configuration object<br>
/// AdUnit configuration object.
///
/// Arguments:
/// - `adSlot`: See [AdUnitParams.AD_SLOT]
/// - `adFormat`: See [AdUnitParams.AD_FORMAT]
Expand All @@ -18,35 +19,40 @@ import '../google_adsense.dart';
/// - `isFullWidthResponsive`: See [AdUnitParams.FULL_WIDTH_RESPONSIVE]
/// - `isAdTest`: See [AdUnitParams.AD_TEST]
/// - `cssText`: See [AdUnitConfiguration.cssText]
class AdUnitConfiguration {
AdUnitConfiguration._internal({
required String adSlot,
AdFormatType? adFormat,
String? adLayout,
AdFormat? adFormat,
AdLayout? adLayout,
String? adLayoutKey,
MultiplexLayout? multiplexLayout,
MatchedContentUiType? matchedContentUiType,
int? rowsNum,
int? columnsNum,
bool isFullWidthResponsive = true,
bool? isFullWidthResponsive = true,
this.isAdTest = kDebugMode,
this.cssText,
}) : _adUnitParams = _buildParams(<String, String?>{
}) : _adUnitParams = <String, String>{
AdUnitParams.AD_SLOT: adSlot,
AdUnitParams.AD_FORMAT: adFormat?.getAttribute(),
AdUnitParams.AD_LAYOUT: adLayout,
AdUnitParams.AD_LAYOUT_KEY: adLayoutKey,
AdUnitParams.FULL_WIDTH_RESPONSIVE: isFullWidthResponsive.toString(),
AdUnitParams.MATCHED_CONTENT_UI_TYPE: multiplexLayout?.getAttribute(),
AdUnitParams.MATCHED_CONTENT_COLUMNS_NUM: columnsNum?.toString(),
AdUnitParams.MATCHED_CONTENT_ROWS_NUM: rowsNum?.toString(),
});
if (adFormat != null) AdUnitParams.AD_FORMAT: adFormat.toString(),
if (adLayout != null) AdUnitParams.AD_LAYOUT: adLayout.toString(),
if (adLayoutKey != null) AdUnitParams.AD_LAYOUT_KEY: adLayoutKey,
if (isFullWidthResponsive != null)
AdUnitParams.FULL_WIDTH_RESPONSIVE:
isFullWidthResponsive.toString(),
if (matchedContentUiType != null)
AdUnitParams.MATCHED_CONTENT_UI_TYPE:
matchedContentUiType.toString(),
if (columnsNum != null)
AdUnitParams.MATCHED_CONTENT_COLUMNS_NUM: columnsNum.toString(),
if (rowsNum != null)
AdUnitParams.MATCHED_CONTENT_ROWS_NUM: rowsNum.toString(),
};

/// Creates In-article ad unit configuration object
AdUnitConfiguration.multiplexAdUnit({
required String adSlot,
required AdFormatType adFormat,
MultiplexLayout? multiplexLayout,
required AdFormat adFormat,
MatchedContentUiType? matchedContentUiType,
int? rowsNum,
int? columnsNum,
bool isFullWidthResponsive = true,
Expand All @@ -55,7 +61,7 @@ class AdUnitConfiguration {
}) : this._internal(
adSlot: adSlot,
adFormat: adFormat,
multiplexLayout: multiplexLayout,
matchedContentUiType: matchedContentUiType,
rowsNum: rowsNum,
columnsNum: columnsNum,
isFullWidthResponsive: isFullWidthResponsive,
Expand All @@ -65,8 +71,8 @@ class AdUnitConfiguration {
/// Creates In-feed ad unit configuration object
AdUnitConfiguration.inFeedAdUnit({
required String adSlot,
AdFormatType? adFormat,
required String adLayoutKey,
AdFormat? adFormat,
bool isFullWidthResponsive = true,
String? cssText,
bool isAdTest = kDebugMode,
Expand All @@ -81,8 +87,8 @@ class AdUnitConfiguration {
/// Creates In-article ad unit configuration object
AdUnitConfiguration.inArticleAdUnit({
required String adSlot,
AdFormatType? adFormat,
String adLayout = 'in-article',
AdFormat? adFormat,
AdLayout adLayout = AdLayout.IN_ARTICLE,
bool isFullWidthResponsive = true,
String? cssText,
bool isAdTest = kDebugMode,
Expand All @@ -97,7 +103,7 @@ class AdUnitConfiguration {
/// Creates Display ad unit configuration object
AdUnitConfiguration.displayAdUnit({
required String adSlot,
AdFormatType? adFormat,
AdFormat? adFormat,
bool isFullWidthResponsive = true,
String? cssText,
bool isAdTest = kDebugMode,
Expand All @@ -124,12 +130,4 @@ class AdUnitConfiguration {

/// Map containing all additional parameters of this configuration
Map<String, String> get params => _adUnitParams;

static Map<String, String> _buildParams(Map<String, String?> inputParams) {
final Map<String, String?> paramsMap =
Map<String, String?>.from(inputParams);
paramsMap.removeWhere((String key, String? value) => value == null);

return paramsMap.cast<String, String>();
}
}
90 changes: 57 additions & 33 deletions packages/google_adsense/lib/src/ad_unit_params.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,71 +43,95 @@ class AdUnitParams {
static const String AD_TEST = 'adtest';
}

/// Possible values for [AdUnitParams.AD_FORMAT]
/// Possible values for [AdUnitParams.AD_FORMAT].
///
/// See [docs](https://support.google.com/adsense/answer/9183460?hl=en&ref_topic=9183242&sjid=2004567335727763076-EU#:~:text=Specify%20a%20general%20shape%20(desktop%20only)) for details
enum AdFormatType {
enum AdFormat {
/// Default which enables the auto-sizing behavior for the responsive ad unit
AUTO,
AUTO('auto'),

/// Use horizontal shape
HORIZONTAL,
HORIZONTAL('horizontal'),

/// Use rectangle shape
RECTANGLE,
RECTANGLE('rectangle'),

/// Use vertical shape
VERTICAL,
VERTICAL('vertical'),

/// Use horizontal and rectangle shape
HORIZONTAL_RECTANGLE,
HORIZONTAL_RECTANGLE('horizontal,rectangle'),

/// Use horizontal and vertical shape
HORIZONTAL_VERTICAL,
HORIZONTAL_VERTICAL('horizontal,vertical'),

/// Use rectangle and vertical shape
RECTANGLE_VERTICAL,
RECTANGLE_VERTICAL('rectangle,vertical'),

/// Use horizontal, rectangle and vertical shape
HORIZONTAL_RECTANGLE_VERTICAL,
HORIZONTAL_RECTANGLE_VERTICAL('horizontal,rectangle,vertical'),

/// Fluid ads have no fixed size, but rather adapt to fit the creative content they display
FLUID
FLUID('fluid');

const AdFormat(this._adFormat);
final String _adFormat;

@override
String toString() => _adFormat;
}

/// Possible values for [AdUnitParams.AD_LAYOUT].
///
/// TODO: find docs link!
enum AdLayout {
///
IMAGE_TOP('image-top'),

///
IMAGE_MIDDLE('image-middle'),

///
IMAGE_SIDE('image-side'),

///
TEXT_ONLY('text-only'),

///
IN_ARTICLE('in-article');

const AdLayout(this._adLayout);
final String _adLayout;

@override
String toString() => _adLayout;
}

/// Possible values for [AdUnitParams.MATCHED_CONTENT_UI_TYPE]
/// Possible values for [AdUnitParams.MATCHED_CONTENT_UI_TYPE].
///
/// See [docs](https://support.google.com/adsense/answer/7533385?hl=en#:~:text=Change%20the%20layout%20of%20your%20Multiplex%20ad%20unit)
enum MultiplexLayout {
enum MatchedContentUiType {
/// In this layout, the image and text appear alongside each other.
IMAGE_CARD_SIDEBYSIDE,
IMAGE_CARD_SIDEBYSIDE('image_card_sidebyside'),

/// In this layout, the image and text appear alongside each other within a card.
IMAGE_SIDEBYSIDE,
IMAGE_SIDEBYSIDE('image_sidebyside'),

/// In this layout, the image and text are arranged one on top of the other.
IMAGE_STACKED,
IMAGE_STACKED('image_stacked'),

/// In this layout, the image and text are arranged one on top of the other within a card.
IMAGE_CARD_STACKED,
IMAGE_CARD_STACKED('image_card_stacked'),

/// A text-only layout with no image.
TEXT,
TEXT('text'),

/// A text-only layout within a card.
TEXT_CARD
}
TEXT_CARD('text_card');

/// Extension to convert [AdFormatType] enum options into <ins> tag data-attribute names
extension GetCommaSeparatedNames on AdFormatType {
/// Returns corresponding data-attribute
String getAttribute() {
return name.toLowerCase().split('_').join(',');
}
}
const MatchedContentUiType(this._uiType);
final String _uiType;

/// Extension to convert [Multiplex] enum options into <ins> tag data-attribute names
extension GetLowerCaseName on MultiplexLayout {
/// Returns corresponding data-attribute
String getAttribute() {
return name.toLowerCase();
}
@override
String toString() => _uiType;
}
54 changes: 28 additions & 26 deletions packages/google_adsense/lib/src/ad_unit_widget_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,15 @@ class AdUnitWidgetWeb extends AdUnitWidget {
}) : _adSlot = adSlot,
_isAdTest = isAdTest,
_unitParams = unitParams {
_insElement
..className = 'adsbygoogle'
..style.display = 'block';
if (cssText != null && cssText.isNotEmpty) {
_insElement.style.cssText = cssText;
// Allow users to set partial cssText
_insElement.style.cssText += cssText;
}
final Map<String, String> dataAttrs = <String, String>{
AdUnitParams.AD_CLIENT: 'ca-pub-$_adClient',
if (_isAdTest) AdUnitParams.AD_TEST: 'on',
..._unitParams
};
if (_isAdTest) {
dataAttrs.addAll(<String, String>{AdUnitParams.AD_TEST: 'on'});
}
if (_unitParams.isNotEmpty) {
dataAttrs.addAll(_unitParams);
}
for (final String key in dataAttrs.keys) {
_insElement.dataset.setProperty(key.toJS, dataAttrs[key]!.toJS);
}
Expand Down Expand Up @@ -68,7 +62,11 @@ class AdUnitWidgetWeb extends AdUnitWidget {
final Map<String, String> _unitParams;

final web.HTMLElement _insElement =
web.document.createElement('ins') as web.HTMLElement;
(web.document.createElement('ins') as web.HTMLElement)
..className = 'adsbygoogle'
..style.display = 'block'
..style.width = '100%'
..style.height = '100%';

@override
State<AdUnitWidgetWeb> createState() => _AdUnitWidgetWebState();
Expand All @@ -77,7 +75,10 @@ class AdUnitWidgetWeb extends AdUnitWidget {
class _AdUnitWidgetWebState extends State<AdUnitWidgetWeb>
with AutomaticKeepAliveClientMixin {
static int adUnitCounter = 0;
double adHeight = 1.0;
// Make the ad as wide as the available space, so Adsense delivers the best
// possible size.
Size adSize = const Size(double.infinity, 1);
// Size adSize = const Size(600, 1); // It seems ads don't resize, do we need to define fixed sizes for ad units?
late web.HTMLElement adUnitDiv;
static final JSString _adStatusKey = 'adStatus'.toJS;

Expand All @@ -87,22 +88,20 @@ class _AdUnitWidgetWebState extends State<AdUnitWidgetWeb>
@override
Widget build(BuildContext context) {
super.build(context);
return SizedBox(
height: adHeight,
return SizedBox.fromSize(
size: adSize,
child: HtmlElementView.fromTagName(
tagName: 'div', onElementCreated: onElementCreated),
);
}

void onElementCreated(Object element) {
adUnitDiv = element as web.HTMLElement;
log('onElementCreated: $adUnitDiv with style height=${element.offsetHeight} and width=${element.offsetWidth}');
adUnitDiv
..id = 'adUnit${adUnitCounter++}'
..style.height = 'min-content'
..style.textAlign = 'center';
// Adding ins inside of the adUnit
adUnitDiv.append(widget._insElement);
adUnitDiv = element as web.HTMLElement
..id = 'adUnit${adUnitCounter++}'
..append(widget._insElement);

log('onElementCreated: $adUnitDiv with style height=${element.offsetHeight} and width=${element.offsetWidth}');

// TODO(sokoloff06): Make shared
// Using Resize observer to detect element attached to DOM
Expand All @@ -128,12 +127,15 @@ class _AdUnitWidgetWebState extends State<AdUnitWidgetWeb>
if (isLoaded(target)) {
observer.disconnect();
if (isFilled(target)) {
updateWidgetHeight(target.offsetHeight);
updateWidgetSize(Size(
target.offsetWidth.toDouble(),
target.offsetHeight.toDouble(),
));
} else {
// Prevent scrolling issues over empty ad slot
target.style.pointerEvents = 'none';
target.style.height = '0px';
updateWidgetHeight(0);
updateWidgetSize(Size.zero);
}
}
}
Expand Down Expand Up @@ -180,10 +182,10 @@ class _AdUnitWidgetWebState extends State<AdUnitWidgetWeb>
}
}

void updateWidgetHeight(int newHeight) {
debugPrint('listener invoked with height $newHeight');
void updateWidgetSize(Size newSize) {
debugPrint('Resizing AdUnit to $newSize');
setState(() {
adHeight = newHeight.toDouble();
adSize = newSize;
});
}
}
Loading

0 comments on commit 36d2550

Please sign in to comment.