@capacitor-community/admob 8.2.0 → 8.2.1-beta.pr490.shaf4a3cab095f4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorCommunityAdmob.podspec +1 -1
- package/Package.swift +1 -1
- package/README.md +8 -7
- package/android/build.gradle +5 -1
- package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +88 -0
- package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdExecutor.kt +626 -0
- package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdFeedSessions.kt +35 -0
- package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdPlacementValue.kt +44 -0
- package/android/src/main/java/com/getcapacitor/community/admob/nativeads/NativeAdPluginEvents.kt +11 -0
- package/android/src/main/java/com/getcapacitor/community/admob/nativeads/PluginNativeAdView.kt +187 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +5 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/native-ads/index.d.ts +6 -0
- package/dist/esm/native-ads/index.js +4 -0
- package/dist/esm/native-ads/index.js.map +1 -0
- package/dist/esm/native-ads/native-ad-definitions.interface.d.ts +20 -0
- package/dist/esm/native-ads/native-ad-definitions.interface.js +2 -0
- package/dist/esm/native-ads/native-ad-definitions.interface.js.map +1 -0
- package/dist/esm/native-ads/native-ad-element.d.ts +9 -0
- package/dist/esm/native-ads/native-ad-element.js +53 -0
- package/dist/esm/native-ads/native-ad-element.js.map +1 -0
- package/dist/esm/native-ads/native-ad-event.interface.d.ts +5 -0
- package/dist/esm/native-ads/native-ad-event.interface.js +2 -0
- package/dist/esm/native-ads/native-ad-event.interface.js.map +1 -0
- package/dist/esm/native-ads/native-ad-feed.d.ts +72 -0
- package/dist/esm/native-ads/native-ad-feed.js +643 -0
- package/dist/esm/native-ads/native-ad-feed.js.map +1 -0
- package/dist/esm/native-ads/native-ad-geometry.d.ts +8 -0
- package/dist/esm/native-ads/native-ad-geometry.js +92 -0
- package/dist/esm/native-ads/native-ad-geometry.js.map +1 -0
- package/dist/esm/native-ads/native-ad-options.interface.d.ts +40 -0
- package/dist/esm/native-ads/native-ad-options.interface.js +2 -0
- package/dist/esm/native-ads/native-ad-options.interface.js.map +1 -0
- package/dist/esm/native-ads/native-ad-placement.interface.d.ts +28 -0
- package/dist/esm/native-ads/native-ad-placement.interface.js +2 -0
- package/dist/esm/native-ads/native-ad-placement.interface.js.map +1 -0
- package/dist/esm/native-ads/native-ad-plugin-events.enum.d.ts +9 -0
- package/dist/esm/native-ads/native-ad-plugin-events.enum.js +11 -0
- package/dist/esm/native-ads/native-ad-plugin-events.enum.js.map +1 -0
- package/dist/esm/native-ads/native-ad-style.interface.d.ts +30 -0
- package/dist/esm/native-ads/native-ad-style.interface.js +2 -0
- package/dist/esm/native-ads/native-ad-style.interface.js.map +1 -0
- package/dist/esm/native-ads/native-ad-template.enum.d.ts +11 -0
- package/dist/esm/native-ads/native-ad-template.enum.js +13 -0
- package/dist/esm/native-ads/native-ad-template.enum.js.map +1 -0
- package/dist/esm/web.d.ts +9 -1
- package/dist/esm/web.js +15 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +883 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +883 -1
- package/dist/plugin.js.map +1 -1
- package/docs/configuration.md +2 -2
- package/docs/consent.md +6 -6
- package/docs/events.md +3 -2
- package/docs/migration.md +22 -2
- package/docs/native-ads.md +187 -0
- package/docs/rewarded.md +13 -0
- package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +103 -41
- package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift +3 -0
- package/ios/Sources/AdMobPlugin/Banner/BannerAdPluginEvents.swift +3 -0
- package/ios/Sources/AdMobPlugin/Banner/BannerAdSizeEnum.swift +3 -0
- package/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +4 -4
- package/ios/Sources/AdMobPlugin/Helper/AuthorizationStatusEnum.swift +3 -0
- package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +3 -0
- package/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift +3 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdExecutor.swift +354 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdFeedSessions.swift +34 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdPlacementValue.swift +50 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdPluginEvents.swift +11 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdScrollTracker.swift +66 -0
- package/ios/Sources/AdMobPlugin/NativeAds/NativeAdValues.swift +27 -0
- package/ios/Sources/AdMobPlugin/NativeAds/PluginNativeAdView.swift +187 -0
- package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +3 -0
- package/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +3 -0
- package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +3 -0
- package/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift +3 -0
- package/ios/Tests/AdMobPluginTests/AdMobPluginTests.swift +82 -10
- package/ios/Tests/AdMobPluginTests/NativeAdScrollTrackerTests.swift +47 -0
- package/package.json +6 -4
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,859 @@
|
|
|
1
1
|
var capacitorStripe = (function (exports, core) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
function* projectionAncestors(element) {
|
|
5
|
+
let current = element;
|
|
6
|
+
while (current) {
|
|
7
|
+
const root = current.getRootNode();
|
|
8
|
+
current = current.assignedSlot ?? current.parentElement ?? (root instanceof ShadowRoot ? root.host : null);
|
|
9
|
+
if (current)
|
|
10
|
+
yield current;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Current CSS visibility without the Engine's projection hiding rules.
|
|
15
|
+
* Use when an existing renderer decides whether its DOM source is authored hidden.
|
|
16
|
+
* Projection attributes are restored synchronously before returning; this performs
|
|
17
|
+
* a style read and may notify MutationObservers, so it is not a cached measurement.
|
|
18
|
+
*/
|
|
19
|
+
const getUnprojectedVisibility = (element) => {
|
|
20
|
+
const win = element.ownerDocument.defaultView;
|
|
21
|
+
if (!win)
|
|
22
|
+
return 'hidden';
|
|
23
|
+
const markers = [];
|
|
24
|
+
for (const node of [element, ...projectionAncestors(element)]) {
|
|
25
|
+
for (const attribute of Array.from(node.attributes)) {
|
|
26
|
+
if (attribute.name === 'data-native-ui-snapshot-source' ||
|
|
27
|
+
attribute.name === 'data-native-ui-snapshot-prepared' ||
|
|
28
|
+
attribute.name === 'data-native-ui-snapshot-content' ||
|
|
29
|
+
attribute.name.startsWith('data-native-ui-session-'))
|
|
30
|
+
markers.push({ node, name: attribute.name, value: attribute.value });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
for (const { node, name } of markers)
|
|
35
|
+
node.removeAttribute(name);
|
|
36
|
+
return win.getComputedStyle(element).visibility;
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
for (const { node, name, value } of markers)
|
|
40
|
+
node.setAttribute(name, value);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// The injected runtime and a plugin's bundled helper share the binding.
|
|
45
|
+
const placementKey = Symbol.for('webview-native-ui-engine.projection-placement');
|
|
46
|
+
const bindProjectionPlacement = (element, measure, invalidate = () => { }) => {
|
|
47
|
+
const host = element;
|
|
48
|
+
const state = { projected: false, measure, invalidate };
|
|
49
|
+
host[placementKey] = state;
|
|
50
|
+
return {
|
|
51
|
+
get projected() {
|
|
52
|
+
return host[placementKey] === state && state.projected;
|
|
53
|
+
},
|
|
54
|
+
dispose() {
|
|
55
|
+
if (host[placementKey] === state)
|
|
56
|
+
delete host[placementKey];
|
|
57
|
+
state.projected = false;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const NATIVE_AD_ELEMENT_NAME = 'capacitor-admob-native';
|
|
63
|
+
const defineNativeAdElement = (findFeed) => {
|
|
64
|
+
const runtime = globalThis;
|
|
65
|
+
runtime.__capacitorAdMobNativeFeedLookup = findFeed;
|
|
66
|
+
if (typeof customElements === 'undefined' || customElements.get(NATIVE_AD_ELEMENT_NAME)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
customElements.define(NATIVE_AD_ELEMENT_NAME, class extends HTMLElement {
|
|
70
|
+
static get observedAttributes() {
|
|
71
|
+
return ['feed-id', 'slot-key'];
|
|
72
|
+
}
|
|
73
|
+
connectedCallback() {
|
|
74
|
+
this.connectToFeed();
|
|
75
|
+
}
|
|
76
|
+
disconnectedCallback() {
|
|
77
|
+
this.disconnectFromFeed();
|
|
78
|
+
}
|
|
79
|
+
attributeChangedCallback() {
|
|
80
|
+
if (!this.isConnected) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.disconnectFromFeed();
|
|
84
|
+
this.connectToFeed();
|
|
85
|
+
}
|
|
86
|
+
connectToFeed() {
|
|
87
|
+
var _a, _b, _c;
|
|
88
|
+
const feedId = (_a = this.getAttribute('feed-id')) === null || _a === void 0 ? void 0 : _a.trim();
|
|
89
|
+
const slotKey = (_b = this.getAttribute('slot-key')) === null || _b === void 0 ? void 0 : _b.trim();
|
|
90
|
+
const feed = feedId ? (_c = runtime.__capacitorAdMobNativeFeedLookup) === null || _c === void 0 ? void 0 : _c.call(runtime, feedId) : undefined;
|
|
91
|
+
if (!feed || !slotKey) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
feed.attach(slotKey, this);
|
|
96
|
+
this.attachedFeed = feed;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.dispatchEvent(new CustomEvent('nativeAdError', { bubbles: true, detail: error }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
disconnectFromFeed() {
|
|
103
|
+
var _a;
|
|
104
|
+
(_a = this.attachedFeed) === null || _a === void 0 ? void 0 : _a.detach(this);
|
|
105
|
+
this.attachedFeed = undefined;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const connectNativeAdElements = () => {
|
|
110
|
+
document
|
|
111
|
+
.querySelectorAll(NATIVE_AD_ELEMENT_NAME)
|
|
112
|
+
.forEach((element) => { var _a, _b; return (_b = (_a = element).connectToFeed) === null || _b === void 0 ? void 0 : _b.call(_a); });
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const intersectRects = (left, right) => {
|
|
116
|
+
const x = Math.max(left.x, right.x);
|
|
117
|
+
const y = Math.max(left.y, right.y);
|
|
118
|
+
const maxX = Math.min(left.x + left.width, right.x + right.width);
|
|
119
|
+
const maxY = Math.min(left.y + left.height, right.y + right.height);
|
|
120
|
+
return {
|
|
121
|
+
x,
|
|
122
|
+
y,
|
|
123
|
+
width: Math.max(0, maxX - x),
|
|
124
|
+
height: Math.max(0, maxY - y),
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
const toNativeRect = (rect) => ({
|
|
128
|
+
x: rect.left,
|
|
129
|
+
y: rect.top,
|
|
130
|
+
width: rect.width,
|
|
131
|
+
height: rect.height,
|
|
132
|
+
});
|
|
133
|
+
const clipsDescendants = (element) => {
|
|
134
|
+
const style = window.getComputedStyle(element);
|
|
135
|
+
return [style.overflow, style.overflowX, style.overflowY].some((value) => ['auto', 'hidden', 'scroll', 'clip'].includes(value));
|
|
136
|
+
};
|
|
137
|
+
function* nativeAdAncestors(element) {
|
|
138
|
+
var _a, _b;
|
|
139
|
+
let current = element;
|
|
140
|
+
while (current) {
|
|
141
|
+
const root = current.getRootNode();
|
|
142
|
+
current =
|
|
143
|
+
(_b = (_a = current.assignedSlot) !== null && _a !== void 0 ? _a : current.parentElement) !== null && _b !== void 0 ? _b : (root instanceof ShadowRoot ? root.host : null);
|
|
144
|
+
if (current)
|
|
145
|
+
yield current;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const measureNativeAdSlot = (element, scrollElement) => {
|
|
149
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
150
|
+
const style = window.getComputedStyle(element);
|
|
151
|
+
const domRect = element.getBoundingClientRect();
|
|
152
|
+
if (!element.isConnected ||
|
|
153
|
+
style.display === 'none' ||
|
|
154
|
+
(style.visibility === 'hidden' && getUnprojectedVisibility(element) === 'hidden') ||
|
|
155
|
+
Number.parseFloat(style.opacity || '1') === 0 ||
|
|
156
|
+
domRect.width <= 0 ||
|
|
157
|
+
domRect.height <= 0) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const rect = toNativeRect(domRect);
|
|
161
|
+
let clipRect = scrollElement
|
|
162
|
+
? rect
|
|
163
|
+
: {
|
|
164
|
+
x: (_b = (_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.offsetLeft) !== null && _b !== void 0 ? _b : 0,
|
|
165
|
+
y: (_d = (_c = window.visualViewport) === null || _c === void 0 ? void 0 : _c.offsetTop) !== null && _d !== void 0 ? _d : 0,
|
|
166
|
+
width: (_f = (_e = window.visualViewport) === null || _e === void 0 ? void 0 : _e.width) !== null && _f !== void 0 ? _f : window.innerWidth,
|
|
167
|
+
height: (_h = (_g = window.visualViewport) === null || _g === void 0 ? void 0 : _g.height) !== null && _h !== void 0 ? _h : window.innerHeight,
|
|
168
|
+
};
|
|
169
|
+
let foundScrollElement = !scrollElement;
|
|
170
|
+
for (const ancestor of nativeAdAncestors(element)) {
|
|
171
|
+
if (ancestor === scrollElement) {
|
|
172
|
+
foundScrollElement = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
if (clipsDescendants(ancestor)) {
|
|
176
|
+
clipRect = intersectRects(clipRect, toNativeRect(ancestor.getBoundingClientRect()));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
clipRect = intersectRects(rect, clipRect);
|
|
180
|
+
if (!foundScrollElement || clipRect.width <= 0 || clipRect.height <= 0)
|
|
181
|
+
return undefined;
|
|
182
|
+
if (scrollElement) {
|
|
183
|
+
const origin = scrollElement.getBoundingClientRect();
|
|
184
|
+
const translate = (value) => (Object.assign(Object.assign({}, value), { x: value.x - origin.left + scrollElement.scrollLeft, y: value.y - origin.top + scrollElement.scrollTop }));
|
|
185
|
+
return { rect: translate(rect), clipRect: translate(clipRect) };
|
|
186
|
+
}
|
|
187
|
+
return { rect, clipRect };
|
|
188
|
+
};
|
|
189
|
+
const measureNativeAdScrollContainer = (element) => {
|
|
190
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
191
|
+
const rect = toNativeRect(element.getBoundingClientRect());
|
|
192
|
+
let clipRect = intersectRects(rect, {
|
|
193
|
+
x: (_b = (_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.offsetLeft) !== null && _b !== void 0 ? _b : 0,
|
|
194
|
+
y: (_d = (_c = window.visualViewport) === null || _c === void 0 ? void 0 : _c.offsetTop) !== null && _d !== void 0 ? _d : 0,
|
|
195
|
+
width: (_f = (_e = window.visualViewport) === null || _e === void 0 ? void 0 : _e.width) !== null && _f !== void 0 ? _f : window.innerWidth,
|
|
196
|
+
height: (_h = (_g = window.visualViewport) === null || _g === void 0 ? void 0 : _g.height) !== null && _h !== void 0 ? _h : window.innerHeight,
|
|
197
|
+
});
|
|
198
|
+
for (const ancestor of nativeAdAncestors(element)) {
|
|
199
|
+
if (clipsDescendants(ancestor)) {
|
|
200
|
+
clipRect = intersectRects(clipRect, toNativeRect(ancestor.getBoundingClientRect()));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { rect, clipRect, contentWidth: element.scrollWidth, contentHeight: element.scrollHeight };
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Layouts rendered by the native Google Mobile Ads SDK.
|
|
208
|
+
*
|
|
209
|
+
* The dimensions of a native ad slot must remain stable while it is used by a
|
|
210
|
+
* virtual scroller. `small` is intended for compact rows, while `medium`
|
|
211
|
+
* includes a larger media area.
|
|
212
|
+
*/
|
|
213
|
+
exports.NativeAdTemplate = void 0;
|
|
214
|
+
(function (NativeAdTemplate) {
|
|
215
|
+
NativeAdTemplate["Small"] = "small";
|
|
216
|
+
NativeAdTemplate["Medium"] = "medium";
|
|
217
|
+
})(exports.NativeAdTemplate || (exports.NativeAdTemplate = {}));
|
|
218
|
+
|
|
219
|
+
const SCROLL_SETTLE_MS = 120;
|
|
220
|
+
const MAX_NATIVE_ADS = 3;
|
|
221
|
+
const MAX_ACTIVE_FEEDS = 2;
|
|
222
|
+
const MIN_SMALL_SLOT_WIDTH = 120;
|
|
223
|
+
const MIN_MEDIUM_SLOT_WIDTH = 144;
|
|
224
|
+
const MIN_MEDIUM_SLOT_HEIGHT = 300;
|
|
225
|
+
const MIN_SMALL_SLOT_HEIGHT = 120;
|
|
226
|
+
const TEMPLATE_ATTRIBUTE = 'data-capacitor-admob-template';
|
|
227
|
+
const applySlotDefaults = (element, template) => {
|
|
228
|
+
const root = element.getRootNode();
|
|
229
|
+
const container = root instanceof ShadowRoot ? root : element.ownerDocument.head;
|
|
230
|
+
if (!container.querySelector('style[data-capacitor-admob-defaults]')) {
|
|
231
|
+
const style = element.ownerDocument.createElement('style');
|
|
232
|
+
style.setAttribute('data-capacitor-admob-defaults', '');
|
|
233
|
+
// Prefer the first cascade layer; older WebViews use zero-specificity rules.
|
|
234
|
+
const defaults = `
|
|
235
|
+
:where([${TEMPLATE_ATTRIBUTE}]) { display: block; height: 320px; }
|
|
236
|
+
:where([${TEMPLATE_ATTRIBUTE}="small"]) { height: 120px; }
|
|
237
|
+
`;
|
|
238
|
+
style.textContent =
|
|
239
|
+
'CSSLayerBlockRule' in globalThis ? `@layer capacitor-admob-defaults { ${defaults} }` : defaults;
|
|
240
|
+
container.prepend(style);
|
|
241
|
+
}
|
|
242
|
+
element.setAttribute(TEMPLATE_ATTRIBUTE, template);
|
|
243
|
+
};
|
|
244
|
+
let bridge;
|
|
245
|
+
let sessionSequence = 0;
|
|
246
|
+
const feeds = new Map();
|
|
247
|
+
const createSessionId = () => { var _a, _b, _c; return (_c = (_b = (_a = globalThis.crypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : `${Date.now()}-${++sessionSequence}-${Math.random().toString(36).slice(2)}`; };
|
|
248
|
+
/**
|
|
249
|
+
* Manages native ad placement and lifecycle in a scrolling feed.
|
|
250
|
+
*
|
|
251
|
+
* A stable `slotKey`, rather than the element or array index, owns the native
|
|
252
|
+
* ad lifecycle. Virtual-scroller compatibility has not yet been validated.
|
|
253
|
+
*/
|
|
254
|
+
class NativeAdFeed {
|
|
255
|
+
constructor(options) {
|
|
256
|
+
var _a;
|
|
257
|
+
this.sessionId = createSessionId();
|
|
258
|
+
this.slots = new Map();
|
|
259
|
+
this.elementSlots = new Map();
|
|
260
|
+
this.scrollRoots = new Set();
|
|
261
|
+
this.destroyed = false;
|
|
262
|
+
this.nativeStarted = false;
|
|
263
|
+
this.paused = false;
|
|
264
|
+
this.layoutInvalidated = false;
|
|
265
|
+
this.lastPlacementWasDirect = false;
|
|
266
|
+
this.placementAcknowledgementRequired = false;
|
|
267
|
+
this.operationTask = Promise.resolve();
|
|
268
|
+
this.updateDirty = false;
|
|
269
|
+
this.placementSequence = 0;
|
|
270
|
+
this.listenerHandles = new Set();
|
|
271
|
+
this.handleViewportMotion = (event) => {
|
|
272
|
+
if (this.destroyed) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (event instanceof Event &&
|
|
276
|
+
event.type === 'load' &&
|
|
277
|
+
event.target instanceof HTMLImageElement &&
|
|
278
|
+
event.target.dataset['admobSnapshot'] !== undefined)
|
|
279
|
+
return;
|
|
280
|
+
if (!(event instanceof Event) || !['scroll', 'touchmove', 'wheel'].includes(event.type)) {
|
|
281
|
+
for (const state of this.slots.values())
|
|
282
|
+
state.lastPlacement = undefined;
|
|
283
|
+
}
|
|
284
|
+
if (!(this.nativeScrollElement &&
|
|
285
|
+
event instanceof Event &&
|
|
286
|
+
['scroll', 'touchmove', 'wheel'].includes(event.type))) {
|
|
287
|
+
this.schedulePlacementUpdate();
|
|
288
|
+
}
|
|
289
|
+
this.scheduleEvaluation();
|
|
290
|
+
};
|
|
291
|
+
this.handleVisibilityChange = () => {
|
|
292
|
+
if (this.destroyed) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (document.hidden) {
|
|
296
|
+
this.layoutInvalidated = true;
|
|
297
|
+
void this.requestPlacementUpdate();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
this.scheduleEvaluation();
|
|
301
|
+
};
|
|
302
|
+
const id = options.feedId.trim();
|
|
303
|
+
if (!id) {
|
|
304
|
+
throw new Error('Native ad feed id must not be empty');
|
|
305
|
+
}
|
|
306
|
+
if (feeds.has(id)) {
|
|
307
|
+
throw new Error(`Native ad feed id already exists: ${id}`);
|
|
308
|
+
}
|
|
309
|
+
if (feeds.size >= MAX_ACTIVE_FEEDS) {
|
|
310
|
+
throw new Error(`At most ${MAX_ACTIVE_FEEDS} native ad feeds can be active`);
|
|
311
|
+
}
|
|
312
|
+
if (options.androidScrollSnapshot && core.Capacitor.getPlatform() !== 'android') {
|
|
313
|
+
throw new Error('androidScrollSnapshot requires Android');
|
|
314
|
+
}
|
|
315
|
+
this.options = Object.assign(Object.assign({}, options), { feedId: id });
|
|
316
|
+
this.nativeScrollElement = core.Capacitor.getPlatform() === 'ios' ? options.scrollElement : undefined;
|
|
317
|
+
if (typeof IntersectionObserver !== 'undefined') {
|
|
318
|
+
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
319
|
+
for (const entry of entries) {
|
|
320
|
+
const slotKey = this.elementSlots.get(entry.target);
|
|
321
|
+
const state = slotKey ? this.slots.get(slotKey) : undefined;
|
|
322
|
+
if (state) {
|
|
323
|
+
state.intersecting = entry.isIntersecting;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
this.schedulePlacementUpdate();
|
|
327
|
+
this.scheduleEvaluation();
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
331
|
+
this.resizeObserver = new ResizeObserver(this.handleViewportMotion);
|
|
332
|
+
if (this.nativeScrollElement)
|
|
333
|
+
this.resizeObserver.observe(this.nativeScrollElement);
|
|
334
|
+
}
|
|
335
|
+
document.addEventListener('scroll', this.handleViewportMotion, true);
|
|
336
|
+
document.addEventListener('touchmove', this.handleViewportMotion, { capture: true, passive: true });
|
|
337
|
+
document.addEventListener('wheel', this.handleViewportMotion, { capture: true, passive: true });
|
|
338
|
+
window.addEventListener('resize', this.handleViewportMotion, { passive: true });
|
|
339
|
+
(_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.addEventListener('resize', this.handleViewportMotion, { passive: true });
|
|
340
|
+
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
|
341
|
+
document.addEventListener('load', this.handleViewportMotion, true);
|
|
342
|
+
feeds.set(id, this);
|
|
343
|
+
}
|
|
344
|
+
static async create(options) {
|
|
345
|
+
var _a;
|
|
346
|
+
if (!bridge) {
|
|
347
|
+
throw new Error('AdMob native ad bridge is not configured');
|
|
348
|
+
}
|
|
349
|
+
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
350
|
+
throw new Error('NativeAdFeed can only be created in a browser environment');
|
|
351
|
+
}
|
|
352
|
+
if (options.isTesting !== true && !((_a = options.adId) === null || _a === void 0 ? void 0 : _a.trim())) {
|
|
353
|
+
throw new Error('adId is required unless isTesting is true');
|
|
354
|
+
}
|
|
355
|
+
const feed = new NativeAdFeed(options);
|
|
356
|
+
try {
|
|
357
|
+
await bridge.startNativeAdFeed({ feedId: feed.feedId, sessionId: feed.sessionId });
|
|
358
|
+
feed.nativeStarted = true;
|
|
359
|
+
defineNativeAdElement((feedId) => feeds.get(feedId));
|
|
360
|
+
connectNativeAdElements();
|
|
361
|
+
return feed;
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
await feed.destroy();
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
get feedId() {
|
|
369
|
+
return this.options.feedId;
|
|
370
|
+
}
|
|
371
|
+
async addListener(eventName, listener) {
|
|
372
|
+
this.assertActive();
|
|
373
|
+
if (!bridge) {
|
|
374
|
+
throw new Error('AdMob native ad bridge is not configured');
|
|
375
|
+
}
|
|
376
|
+
const nativeHandle = await bridge.addListener(eventName, (event) => {
|
|
377
|
+
if (event.feedId === this.options.feedId && event.sessionId === this.sessionId) {
|
|
378
|
+
const filteredListener = listener;
|
|
379
|
+
filteredListener(event);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
if (this.destroyed) {
|
|
383
|
+
await nativeHandle.remove();
|
|
384
|
+
this.assertActive();
|
|
385
|
+
}
|
|
386
|
+
let removed = false;
|
|
387
|
+
const handle = {
|
|
388
|
+
remove: async () => {
|
|
389
|
+
if (removed) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
removed = true;
|
|
393
|
+
this.listenerHandles.delete(handle);
|
|
394
|
+
await nativeHandle.remove();
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
this.listenerHandles.add(handle);
|
|
398
|
+
return handle;
|
|
399
|
+
}
|
|
400
|
+
attach(slotKey, element) {
|
|
401
|
+
var _a, _b, _c, _d, _e;
|
|
402
|
+
this.assertActive();
|
|
403
|
+
const normalizedKey = slotKey.trim();
|
|
404
|
+
if (!normalizedKey) {
|
|
405
|
+
throw new Error('Native ad slotKey must not be empty');
|
|
406
|
+
}
|
|
407
|
+
const previousKey = this.elementSlots.get(element);
|
|
408
|
+
if (previousKey === normalizedKey) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (previousKey && previousKey !== normalizedKey) {
|
|
412
|
+
this.detach(element);
|
|
413
|
+
}
|
|
414
|
+
const existing = this.slots.get(normalizedKey);
|
|
415
|
+
if ((existing === null || existing === void 0 ? void 0 : existing.element) && existing.element !== element) {
|
|
416
|
+
throw new Error(`Native ad slotKey is already attached: ${normalizedKey}`);
|
|
417
|
+
}
|
|
418
|
+
const state = existing !== null && existing !== void 0 ? existing : {
|
|
419
|
+
slotKey: normalizedKey,
|
|
420
|
+
generation: 0,
|
|
421
|
+
intersecting: !this.intersectionObserver,
|
|
422
|
+
status: 'idle',
|
|
423
|
+
lastUsed: Date.now(),
|
|
424
|
+
loadVersion: 0,
|
|
425
|
+
};
|
|
426
|
+
applySlotDefaults(element, (_a = this.options.template) !== null && _a !== void 0 ? _a : exports.NativeAdTemplate.Medium);
|
|
427
|
+
state.element = element;
|
|
428
|
+
if (this.options.androidScrollSnapshot) {
|
|
429
|
+
const owner = ((_b = state.projectionOwner) !== null && _b !== void 0 ? _b : (state.projectionOwner = `admob-${crypto.randomUUID()}`));
|
|
430
|
+
element.dataset['admobProjection'] = owner;
|
|
431
|
+
state.projectionSelector = `[data-admob-projection="${owner}"]`;
|
|
432
|
+
(_c = state.placementBinding) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
433
|
+
state.placementBinding = bindProjectionPlacement(element, () => {
|
|
434
|
+
const placement = this.measurePlacement(state);
|
|
435
|
+
state.lastPlacement = placement;
|
|
436
|
+
// The reveal request applies this exact placement; keep batch deduplication in sync.
|
|
437
|
+
if (this.lastPlacements) {
|
|
438
|
+
const previous = JSON.parse(this.lastPlacements);
|
|
439
|
+
previous.placements = previous.placements.map((item) => item.slotKey === state.slotKey ? placement : item);
|
|
440
|
+
this.lastPlacements = JSON.stringify(previous);
|
|
441
|
+
}
|
|
442
|
+
return Object.assign(Object.assign({}, placement), { sessionId: this.sessionId, sequence: ++this.placementSequence });
|
|
443
|
+
}, () => {
|
|
444
|
+
if (state.element !== element || this.destroyed)
|
|
445
|
+
return;
|
|
446
|
+
state.lastPlacement = undefined;
|
|
447
|
+
this.lastPlacements = undefined;
|
|
448
|
+
this.schedulePlacementUpdate();
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
state.generation += 1;
|
|
452
|
+
state.lastUsed = Date.now();
|
|
453
|
+
this.slots.set(normalizedKey, state);
|
|
454
|
+
this.elementSlots.set(element, normalizedKey);
|
|
455
|
+
this.updateScrollRoots();
|
|
456
|
+
(_d = this.intersectionObserver) === null || _d === void 0 ? void 0 : _d.observe(element);
|
|
457
|
+
(_e = this.resizeObserver) === null || _e === void 0 ? void 0 : _e.observe(element);
|
|
458
|
+
this.scheduleEvaluation();
|
|
459
|
+
}
|
|
460
|
+
detach(element) {
|
|
461
|
+
var _a, _b, _c;
|
|
462
|
+
const slotKey = this.elementSlots.get(element);
|
|
463
|
+
if (!slotKey) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
const state = this.slots.get(slotKey);
|
|
467
|
+
if ((state === null || state === void 0 ? void 0 : state.element) === element) {
|
|
468
|
+
(_a = state.placementBinding) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
469
|
+
state.placementBinding = undefined;
|
|
470
|
+
state.lastPlacement = undefined;
|
|
471
|
+
if (state.projectionOwner)
|
|
472
|
+
delete element.dataset['admobProjection'];
|
|
473
|
+
state.element = undefined;
|
|
474
|
+
state.intersecting = false;
|
|
475
|
+
state.generation += 1;
|
|
476
|
+
state.lastUsed = Date.now();
|
|
477
|
+
}
|
|
478
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.unobserve(element);
|
|
479
|
+
(_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.unobserve(element);
|
|
480
|
+
this.elementSlots.delete(element);
|
|
481
|
+
this.updateScrollRoots();
|
|
482
|
+
void this.requestPlacementUpdate();
|
|
483
|
+
this.scheduleEvaluation();
|
|
484
|
+
}
|
|
485
|
+
async reload(slotKey) {
|
|
486
|
+
this.assertActive();
|
|
487
|
+
const normalizedKey = slotKey.trim();
|
|
488
|
+
const state = this.slots.get(normalizedKey);
|
|
489
|
+
if (!state) {
|
|
490
|
+
throw new Error(`Native ad slotKey is not registered: ${normalizedKey}`);
|
|
491
|
+
}
|
|
492
|
+
await this.runOperation(async () => {
|
|
493
|
+
await this.removeStateAd(state);
|
|
494
|
+
const protectedStates = new Set(this.getVisibleStates());
|
|
495
|
+
protectedStates.add(state);
|
|
496
|
+
await this.evictUnusedAds(protectedStates);
|
|
497
|
+
if ([...this.slots.values()].filter((slot) => this.occupiesNativeAd(slot)).length >= MAX_NATIVE_ADS) {
|
|
498
|
+
throw new Error('Native ad capacity is currently in use by visible slots');
|
|
499
|
+
}
|
|
500
|
+
await this.loadState(state);
|
|
501
|
+
await this.requestPlacementUpdate();
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
/** Immediately hides this feed's overlays until {@link resume} is called. */
|
|
505
|
+
async pause() {
|
|
506
|
+
this.assertActive();
|
|
507
|
+
this.paused = true;
|
|
508
|
+
this.layoutInvalidated = true;
|
|
509
|
+
if (!(await this.requestPlacementUpdate())) {
|
|
510
|
+
throw new Error('Failed to hide native ad placements');
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
/** Re-evaluates slots and restores eligible overlays after the viewport settles. */
|
|
514
|
+
resume() {
|
|
515
|
+
this.assertActive();
|
|
516
|
+
this.paused = false;
|
|
517
|
+
this.scheduleEvaluation();
|
|
518
|
+
}
|
|
519
|
+
/** Hides stale overlays and remeasures after an application-driven layout change. */
|
|
520
|
+
async invalidateLayout() {
|
|
521
|
+
this.assertActive();
|
|
522
|
+
for (const state of this.slots.values())
|
|
523
|
+
state.lastPlacement = undefined;
|
|
524
|
+
this.layoutInvalidated = true;
|
|
525
|
+
this.scheduleEvaluation();
|
|
526
|
+
if (!(await this.requestPlacementUpdate())) {
|
|
527
|
+
throw new Error('Failed to hide native ad placements');
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
async destroy() {
|
|
531
|
+
var _a, _b, _c;
|
|
532
|
+
if (!this.destroyed) {
|
|
533
|
+
this.destroyed = true;
|
|
534
|
+
feeds.delete(this.options.feedId);
|
|
535
|
+
document.removeEventListener('scroll', this.handleViewportMotion, true);
|
|
536
|
+
for (const root of this.scrollRoots) {
|
|
537
|
+
root.removeEventListener('scroll', this.handleViewportMotion, true);
|
|
538
|
+
}
|
|
539
|
+
this.scrollRoots.clear();
|
|
540
|
+
document.removeEventListener('touchmove', this.handleViewportMotion, true);
|
|
541
|
+
document.removeEventListener('wheel', this.handleViewportMotion, true);
|
|
542
|
+
window.removeEventListener('resize', this.handleViewportMotion);
|
|
543
|
+
(_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.removeEventListener('resize', this.handleViewportMotion);
|
|
544
|
+
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
|
545
|
+
document.removeEventListener('load', this.handleViewportMotion, true);
|
|
546
|
+
if (this.settleTimer) {
|
|
547
|
+
clearTimeout(this.settleTimer);
|
|
548
|
+
}
|
|
549
|
+
if (this.placementFrame !== undefined) {
|
|
550
|
+
cancelAnimationFrame(this.placementFrame);
|
|
551
|
+
this.placementFrame = undefined;
|
|
552
|
+
}
|
|
553
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
554
|
+
(_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
555
|
+
}
|
|
556
|
+
if (this.destroyTask) {
|
|
557
|
+
return this.destroyTask;
|
|
558
|
+
}
|
|
559
|
+
this.destroyTask = this.destroyResources();
|
|
560
|
+
try {
|
|
561
|
+
await this.destroyTask;
|
|
562
|
+
}
|
|
563
|
+
finally {
|
|
564
|
+
this.destroyTask = undefined;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
schedulePlacementUpdate() {
|
|
568
|
+
if (this.destroyed || this.placementFrame !== undefined) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
this.placementFrame = requestAnimationFrame(() => {
|
|
572
|
+
this.placementFrame = undefined;
|
|
573
|
+
void this.requestPlacementUpdate(true);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
updateScrollRoots() {
|
|
577
|
+
const roots = new Set();
|
|
578
|
+
for (const element of this.elementSlots.keys()) {
|
|
579
|
+
for (const ancestor of [element, ...nativeAdAncestors(element)]) {
|
|
580
|
+
const root = ancestor.getRootNode();
|
|
581
|
+
if (root instanceof ShadowRoot)
|
|
582
|
+
roots.add(root);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
for (const root of this.scrollRoots) {
|
|
586
|
+
if (!roots.has(root)) {
|
|
587
|
+
root.removeEventListener('scroll', this.handleViewportMotion, true);
|
|
588
|
+
this.scrollRoots.delete(root);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
for (const root of roots) {
|
|
592
|
+
if (!this.scrollRoots.has(root)) {
|
|
593
|
+
// Element scroll events do not cross a shadow boundary.
|
|
594
|
+
root.addEventListener('scroll', this.handleViewportMotion, true);
|
|
595
|
+
this.scrollRoots.add(root);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
scheduleEvaluation() {
|
|
600
|
+
if (this.destroyed) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (this.settleTimer) {
|
|
604
|
+
clearTimeout(this.settleTimer);
|
|
605
|
+
}
|
|
606
|
+
this.settleTimer = setTimeout(() => {
|
|
607
|
+
this.layoutInvalidated = false;
|
|
608
|
+
void this.runOperation(async () => {
|
|
609
|
+
await this.evaluate();
|
|
610
|
+
});
|
|
611
|
+
}, SCROLL_SETTLE_MS);
|
|
612
|
+
}
|
|
613
|
+
async evaluate() {
|
|
614
|
+
if (this.destroyed || this.paused || document.hidden) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const visibleStates = this.getVisibleStates();
|
|
618
|
+
for (const state of visibleStates) {
|
|
619
|
+
state.lastUsed = Date.now();
|
|
620
|
+
}
|
|
621
|
+
await this.evictUnusedAds(new Set(visibleStates));
|
|
622
|
+
const occupied = [...this.slots.values()].filter((state) => this.occupiesNativeAd(state)).length;
|
|
623
|
+
const loadable = visibleStates
|
|
624
|
+
.filter((state) => state.status === 'idle')
|
|
625
|
+
.slice(0, Math.max(0, MAX_NATIVE_ADS - occupied));
|
|
626
|
+
await Promise.allSettled(loadable.map((state) => this.loadState(state)));
|
|
627
|
+
await this.requestPlacementUpdate();
|
|
628
|
+
}
|
|
629
|
+
async loadState(state) {
|
|
630
|
+
var _a;
|
|
631
|
+
if (state.status !== 'idle' || !bridge) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
state.status = 'loading';
|
|
635
|
+
const loadVersion = ++state.loadVersion;
|
|
636
|
+
try {
|
|
637
|
+
await bridge.loadNativeAd(Object.assign({ feedId: this.options.feedId, sessionId: this.sessionId, slotKey: state.slotKey, template: (_a = this.options.template) !== null && _a !== void 0 ? _a : exports.NativeAdTemplate.Medium, style: this.options.style, adId: this.options.adId, isTesting: this.options.isTesting, npa: this.options.npa }, (state.projectionSelector ? { projectionSelector: state.projectionSelector } : {})));
|
|
638
|
+
if (state.loadVersion === loadVersion) {
|
|
639
|
+
state.status = 'loaded';
|
|
640
|
+
state.lastUsed = Date.now();
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
if (state.loadVersion === loadVersion) {
|
|
645
|
+
state.status = 'failed';
|
|
646
|
+
}
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
async evictUnusedAds(visibleStates) {
|
|
651
|
+
const occupied = [...this.slots.values()].filter((state) => this.occupiesNativeAd(state));
|
|
652
|
+
const requestedLoads = [...visibleStates].filter((state) => state.status === 'idle').length;
|
|
653
|
+
const evictionCount = Math.max(0, occupied.length + Math.min(requestedLoads, MAX_NATIVE_ADS) - MAX_NATIVE_ADS);
|
|
654
|
+
const evicted = occupied
|
|
655
|
+
.filter((state) => !visibleStates.has(state))
|
|
656
|
+
.sort((left, right) => left.lastUsed - right.lastUsed)
|
|
657
|
+
.slice(0, evictionCount);
|
|
658
|
+
await Promise.allSettled(evicted.map((state) => this.removeStateAd(state)));
|
|
659
|
+
const detached = [...this.slots.values()]
|
|
660
|
+
.filter((state) => !state.element && !this.occupiesNativeAd(state))
|
|
661
|
+
.sort((left, right) => right.lastUsed - left.lastUsed);
|
|
662
|
+
for (const state of detached.slice(MAX_NATIVE_ADS)) {
|
|
663
|
+
this.slots.delete(state.slotKey);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
occupiesNativeAd(state) {
|
|
667
|
+
return ['loading', 'loaded', 'removing', 'removeFailed'].includes(state.status);
|
|
668
|
+
}
|
|
669
|
+
getVisibleStates() {
|
|
670
|
+
return [...this.slots.values()].filter((state) => {
|
|
671
|
+
var _a;
|
|
672
|
+
if (this.reuseProjectedPlacement(state))
|
|
673
|
+
return state.intersecting && !!((_a = state.lastPlacement) === null || _a === void 0 ? void 0 : _a.visible);
|
|
674
|
+
const measured = state.element && state.intersecting ? measureNativeAdSlot(state.element) : undefined;
|
|
675
|
+
return Boolean(measured && this.isSupportedSize(measured));
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
isSupportedSize(measured) {
|
|
679
|
+
var _a, _b;
|
|
680
|
+
const minimumHeight = ((_a = this.options.template) !== null && _a !== void 0 ? _a : exports.NativeAdTemplate.Medium) === exports.NativeAdTemplate.Small
|
|
681
|
+
? MIN_SMALL_SLOT_HEIGHT
|
|
682
|
+
: MIN_MEDIUM_SLOT_HEIGHT;
|
|
683
|
+
const minimumWidth = ((_b = this.options.template) !== null && _b !== void 0 ? _b : exports.NativeAdTemplate.Medium) === exports.NativeAdTemplate.Small
|
|
684
|
+
? MIN_SMALL_SLOT_WIDTH
|
|
685
|
+
: MIN_MEDIUM_SLOT_WIDTH;
|
|
686
|
+
return measured.rect.width >= minimumWidth && measured.rect.height >= minimumHeight;
|
|
687
|
+
}
|
|
688
|
+
async removeStateAd(state) {
|
|
689
|
+
if (state.status === 'removing') {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
if (!bridge || state.status === 'idle' || state.status === 'failed') {
|
|
693
|
+
state.status = 'idle';
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
state.status = 'removing';
|
|
697
|
+
const removeVersion = ++state.loadVersion;
|
|
698
|
+
await this.requestPlacementUpdate();
|
|
699
|
+
try {
|
|
700
|
+
await bridge.removeNativeAd({
|
|
701
|
+
feedId: this.options.feedId,
|
|
702
|
+
sessionId: this.sessionId,
|
|
703
|
+
slotKey: state.slotKey,
|
|
704
|
+
});
|
|
705
|
+
if (state.loadVersion === removeVersion) {
|
|
706
|
+
state.status = 'idle';
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
catch (error) {
|
|
710
|
+
if (state.loadVersion === removeVersion) {
|
|
711
|
+
state.status = 'removeFailed';
|
|
712
|
+
}
|
|
713
|
+
throw error;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
runOperation(operation) {
|
|
717
|
+
const result = this.operationTask.then(operation);
|
|
718
|
+
this.operationTask = result.catch(() => undefined);
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
async destroyResources() {
|
|
722
|
+
var _a;
|
|
723
|
+
await Promise.all([
|
|
724
|
+
...[...this.listenerHandles].map((handle) => handle.remove()),
|
|
725
|
+
...(this.nativeStarted && bridge
|
|
726
|
+
? [bridge.destroyNativeAdFeed({ feedId: this.options.feedId, sessionId: this.sessionId })]
|
|
727
|
+
: []),
|
|
728
|
+
]);
|
|
729
|
+
this.nativeStarted = false;
|
|
730
|
+
this.listenerHandles.clear();
|
|
731
|
+
for (const state of this.slots.values())
|
|
732
|
+
(_a = state.placementBinding) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
733
|
+
this.slots.clear();
|
|
734
|
+
this.elementSlots.clear();
|
|
735
|
+
}
|
|
736
|
+
reuseProjectedPlacement(state) {
|
|
737
|
+
var _a, _b, _c;
|
|
738
|
+
return Boolean(((_a = state.placementBinding) === null || _a === void 0 ? void 0 : _a.projected) &&
|
|
739
|
+
((_b = state.lastPlacement) === null || _b === void 0 ? void 0 : _b.visible) &&
|
|
740
|
+
((_c = state.element) === null || _c === void 0 ? void 0 : _c.isConnected) &&
|
|
741
|
+
!this.paused &&
|
|
742
|
+
!this.destroyed &&
|
|
743
|
+
!document.hidden &&
|
|
744
|
+
state.status === 'loaded' &&
|
|
745
|
+
state.lastPlacement.generation === state.generation);
|
|
746
|
+
}
|
|
747
|
+
measurePlacement(state) {
|
|
748
|
+
const measured = state.element ? measureNativeAdSlot(state.element, this.nativeScrollElement) : undefined;
|
|
749
|
+
return {
|
|
750
|
+
feedId: this.options.feedId,
|
|
751
|
+
slotKey: state.slotKey,
|
|
752
|
+
generation: state.generation,
|
|
753
|
+
visible: Boolean(!this.paused &&
|
|
754
|
+
!this.destroyed &&
|
|
755
|
+
state.status === 'loaded' &&
|
|
756
|
+
(!this.layoutInvalidated || this.options.androidScrollSnapshot) &&
|
|
757
|
+
measured &&
|
|
758
|
+
this.isSupportedSize(measured) &&
|
|
759
|
+
!document.hidden),
|
|
760
|
+
rect: measured === null || measured === void 0 ? void 0 : measured.rect,
|
|
761
|
+
clipRect: measured === null || measured === void 0 ? void 0 : measured.clipRect,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
requestPlacementUpdate(allowDirect = false) {
|
|
765
|
+
this.updateDirty = true;
|
|
766
|
+
this.placementAcknowledgementRequired || (this.placementAcknowledgementRequired = !allowDirect);
|
|
767
|
+
if (!this.placementUpdateTask) {
|
|
768
|
+
this.placementUpdateTask = Promise.resolve().then(() => this.flushPlacementUpdates());
|
|
769
|
+
}
|
|
770
|
+
return this.placementUpdateTask;
|
|
771
|
+
}
|
|
772
|
+
async flushPlacementUpdates() {
|
|
773
|
+
if (!bridge || this.destroyed) {
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
try {
|
|
777
|
+
while (this.updateDirty && !this.destroyed) {
|
|
778
|
+
this.updateDirty = false;
|
|
779
|
+
const allowDirect = !this.placementAcknowledgementRequired;
|
|
780
|
+
this.placementAcknowledgementRequired = false;
|
|
781
|
+
const retainedSlots = new Set();
|
|
782
|
+
const placements = [...this.slots.values()]
|
|
783
|
+
.filter((state) => state.status === 'loaded')
|
|
784
|
+
.map((state) => {
|
|
785
|
+
if (this.reuseProjectedPlacement(state)) {
|
|
786
|
+
retainedSlots.add(state.slotKey);
|
|
787
|
+
return state.lastPlacement;
|
|
788
|
+
}
|
|
789
|
+
return (state.lastPlacement = this.measurePlacement(state));
|
|
790
|
+
});
|
|
791
|
+
const scrollContainer = this.nativeScrollElement
|
|
792
|
+
? measureNativeAdScrollContainer(this.nativeScrollElement)
|
|
793
|
+
: undefined;
|
|
794
|
+
const serializedPlacements = JSON.stringify({ placements, scrollContainer });
|
|
795
|
+
if (serializedPlacements === this.lastPlacements && (allowDirect || !this.lastPlacementWasDirect)) {
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
const batch = Object.assign({ feedId: this.options.feedId, sessionId: this.sessionId, sequence: ++this.placementSequence, placements: placements.map((placement) => {
|
|
800
|
+
return retainedSlots.has(placement.slotKey)
|
|
801
|
+
? {
|
|
802
|
+
feedId: placement.feedId,
|
|
803
|
+
slotKey: placement.slotKey,
|
|
804
|
+
generation: placement.generation,
|
|
805
|
+
visible: true,
|
|
806
|
+
retain: true,
|
|
807
|
+
}
|
|
808
|
+
: placement;
|
|
809
|
+
}) }, (scrollContainer ? { scrollContainer } : {}));
|
|
810
|
+
const channel = core.Capacitor.getPlatform() === 'android'
|
|
811
|
+
? window
|
|
812
|
+
.capacitorAdMobPlacements
|
|
813
|
+
: undefined;
|
|
814
|
+
let sentDirectly = false;
|
|
815
|
+
if (allowDirect && channel) {
|
|
816
|
+
try {
|
|
817
|
+
channel.postMessage(JSON.stringify(batch));
|
|
818
|
+
sentDirectly = true;
|
|
819
|
+
}
|
|
820
|
+
catch (_a) {
|
|
821
|
+
// Keep the acknowledged bridge available if the direct channel fails.
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
if (!sentDirectly)
|
|
825
|
+
await bridge.updateNativeAdPlacements(batch);
|
|
826
|
+
this.lastPlacementWasDirect = sentDirectly;
|
|
827
|
+
this.lastPlacements = serializedPlacements;
|
|
828
|
+
}
|
|
829
|
+
catch (_b) {
|
|
830
|
+
this.lastPlacements = undefined;
|
|
831
|
+
// Retry on the next scroll, resize, or lifecycle update without
|
|
832
|
+
// creating an unhandled rejection from this fire-and-forget task.
|
|
833
|
+
this.updateDirty = true;
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
catch (_c) {
|
|
840
|
+
this.updateDirty = true;
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
finally {
|
|
844
|
+
this.placementUpdateTask = undefined;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
assertActive() {
|
|
848
|
+
if (this.destroyed) {
|
|
849
|
+
throw new Error(`Native ad feed has been destroyed: ${this.options.feedId}`);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const configureNativeAdBridge = (adMobBridge) => {
|
|
854
|
+
bridge = adMobBridge;
|
|
855
|
+
};
|
|
856
|
+
|
|
4
857
|
exports.MaxAdContentRating = void 0;
|
|
5
858
|
(function (MaxAdContentRating) {
|
|
6
859
|
/**
|
|
@@ -329,9 +1182,22 @@ var capacitorStripe = (function (exports, core) {
|
|
|
329
1182
|
AppOpenAdPluginEvents["AdImpression"] = "appOpenAdImpression";
|
|
330
1183
|
})(exports.AppOpenAdPluginEvents || (exports.AppOpenAdPluginEvents = {}));
|
|
331
1184
|
|
|
332
|
-
|
|
1185
|
+
exports.NativeAdPluginEvents = void 0;
|
|
1186
|
+
(function (NativeAdPluginEvents) {
|
|
1187
|
+
NativeAdPluginEvents["Loaded"] = "nativeAdLoaded";
|
|
1188
|
+
NativeAdPluginEvents["FailedToLoad"] = "nativeAdFailedToLoad";
|
|
1189
|
+
NativeAdPluginEvents["Clicked"] = "nativeAdClicked";
|
|
1190
|
+
NativeAdPluginEvents["AdImpression"] = "nativeAdImpression";
|
|
1191
|
+
NativeAdPluginEvents["Opened"] = "nativeAdOpened";
|
|
1192
|
+
NativeAdPluginEvents["Closed"] = "nativeAdClosed";
|
|
1193
|
+
NativeAdPluginEvents["AdPaid"] = "nativeAdPaid";
|
|
1194
|
+
})(exports.NativeAdPluginEvents || (exports.NativeAdPluginEvents = {}));
|
|
1195
|
+
|
|
1196
|
+
const nativeAdBridge = core.registerPlugin('AdMob', {
|
|
333
1197
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.AdMobWeb()),
|
|
334
1198
|
});
|
|
1199
|
+
const AdMob = nativeAdBridge;
|
|
1200
|
+
configureNativeAdBridge(nativeAdBridge);
|
|
335
1201
|
|
|
336
1202
|
/**
|
|
337
1203
|
* For more information:
|
|
@@ -407,6 +1273,21 @@ var capacitorStripe = (function (exports, core) {
|
|
|
407
1273
|
async removeBanner() {
|
|
408
1274
|
console.log('removeBanner');
|
|
409
1275
|
}
|
|
1276
|
+
async startNativeAdFeed() {
|
|
1277
|
+
throw new Error('Native ads are only available on iOS and Android');
|
|
1278
|
+
}
|
|
1279
|
+
async destroyNativeAdFeed(options) {
|
|
1280
|
+
console.log('destroyNativeAdFeed', options);
|
|
1281
|
+
}
|
|
1282
|
+
async loadNativeAd() {
|
|
1283
|
+
throw new Error('Native ads are only available on iOS and Android');
|
|
1284
|
+
}
|
|
1285
|
+
async updateNativeAdPlacements(options) {
|
|
1286
|
+
console.log('updateNativeAdPlacements', options);
|
|
1287
|
+
}
|
|
1288
|
+
async removeNativeAd(options) {
|
|
1289
|
+
console.log('removeNativeAd', options);
|
|
1290
|
+
}
|
|
410
1291
|
async prepareInterstitial(options) {
|
|
411
1292
|
console.log('prepareInterstitial', options);
|
|
412
1293
|
return {
|
|
@@ -466,6 +1347,7 @@ var capacitorStripe = (function (exports, core) {
|
|
|
466
1347
|
});
|
|
467
1348
|
|
|
468
1349
|
exports.AdMob = AdMob;
|
|
1350
|
+
exports.NativeAdFeed = NativeAdFeed;
|
|
469
1351
|
|
|
470
1352
|
return exports;
|
|
471
1353
|
|