cordova-plugin-admob-nextgen 1.1.9 → 1.3.9

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/README.md CHANGED
@@ -75,6 +75,12 @@ We prioritize the safety of your AdMob account and the stability of your app.
75
75
  > Fastest test (APK Debug): **[⚡ With github action ](https://github.com/swaplab-engine/cordova-plugin-admob-nextgen/discussions/4)** (Optional)
76
76
  ---
77
77
 
78
+ ### 🎉 View all plugin release notes
79
+ - 👉 [**Releases**](https://github.com/swaplab-engine/cordova-plugin-admob-nextgen/releases)
80
+
81
+ ---
82
+
83
+
78
84
  ## 1. Cordova or Framework7
79
85
 
80
86
  ### Option A: Via CLI
@@ -228,6 +234,17 @@ Supports **Adaptive**, **Standard**, and **Collapsible** banners.
228
234
  isAutoShow: true
229
235
  });
230
236
 
237
+ ### New large banner adaptive size
238
+
239
+ > new banner size min plugin version: 1.2+
240
+
241
+ - LARGE_LANDSCAPE_ANCHORED_ADAPTIVE
242
+ - LARGE_PORTRAIT_ANCHORED_ADAPTIVE
243
+ - CURRENT_ORIENTATION_INLINE_ADAPTIVE
244
+ - LARGE_ANCHORED_ADAPTIVE
245
+ - PORTRAIT_INLINE_ADAPTIVE
246
+
247
+
231
248
  ### Banner Methods
232
249
 
233
250
  admobNextGen.showBanner();
@@ -104,7 +104,7 @@ function updateIosInfoPlist(appIdIos) {
104
104
  setStringKey('NSUserTrackingUsageDescription', 'This identifier will be used to deliver personalized ads to you.');
105
105
 
106
106
  setBoolKey('GADDelayAppMeasurementInit', true);
107
-
107
+ // https://developers.google.com/admob/ios/quick-start
108
108
  if (!content.includes('<key>SKAdNetworkItems</key>')) {
109
109
  const skAdNetworks = [
110
110
  'cstr6suwn9.skadnetwork', '4fzdc2evr5.skadnetwork', '2fnua5tdw4.skadnetwork', 'ydx93a7ass.skadnetwork',
@@ -158,7 +158,7 @@ function run() {
158
158
  admob = {
159
159
  APP_ID_ANDROID: appIdAndroid ? appIdAndroid[1] : "ca-app-pub-3940256099942544~3347511713",
160
160
  APP_ID_IOS: appIdIos ? appIdIos[1] : "ca-app-pub-3940256099942544~1458002511",
161
- NEXT_GEN_SDK_VERSION: sdk ? sdk[1] : "1.0.0",
161
+ NEXT_GEN_SDK_VERSION: sdk ? sdk[1] : "1.0.1",
162
162
  UMP_VERSION: ump ? ump[1] : "4.0.0"
163
163
  };
164
164
  }
@@ -167,7 +167,7 @@ function run() {
167
167
  injectExclusionRules();
168
168
  if (admob?.NEXT_GEN_SDK_VERSION || admob?.UMP_VERSION) {
169
169
  updateGradleDependencies(
170
- admob.NEXT_GEN_SDK_VERSION || "1.0.0",
170
+ admob.NEXT_GEN_SDK_VERSION || "1.0.1",
171
171
  admob.UMP_VERSION || "4.0.0"
172
172
  );
173
173
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cordova-plugin-admob-nextgen",
3
- "version": "1.1.9",
3
+ "version": "1.3.9",
4
4
  "description": "Google Mobile Ads Next Gen SDK for Cordova. High performance and modular architecture. ",
5
5
  "cordova": {
6
6
  "id": "cordova-plugin-admob-nextgen",
package/plugin.xml CHANGED
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0' encoding='utf-8'?>
2
2
  <plugin id="cordova-plugin-admob-nextgen"
3
- version="1.1.9"
3
+ version="1.3.9"
4
4
  xmlns="http://apache.org/cordova/ns/plugins/1.0"
5
5
  xmlns:android="http://schemas.android.com/apk/res/android">
6
6
 
@@ -47,7 +47,7 @@
47
47
 
48
48
  </platform>
49
49
 
50
- <preference name="NEXT_GEN_SDK_VERSION" default="1.0.0" />
50
+ <preference name="NEXT_GEN_SDK_VERSION" default="1.0.1" />
51
51
  <preference name="UMP_VERSION" default="4.0.0" />
52
52
  <preference name="APP_ID_ANDROID" default="ca-app-pub-3940256099942544~3347511713" />
53
53
 
@@ -283,7 +283,12 @@ public class AdMobNextGen extends CordovaPlugin {
283
283
 
284
284
  @Override
285
285
  public void onDestroy() {
286
- if (bannerExecutor != null) bannerExecutor.destroy();
286
+ if (bannerExecutor != null){
287
+ bannerExecutor.destroy();
288
+ }
289
+ if (nativeExecutor != null) {
290
+ nativeExecutor.destroy();
291
+ }
287
292
  super.onDestroy();
288
293
  }
289
294
 
@@ -58,7 +58,7 @@ public class BannerExecutor {
58
58
  private boolean isAutoShow = true;
59
59
  private boolean isCollapsible = false;
60
60
  private boolean isCapacitor = false;
61
- private boolean isCordova15 = false;
61
+ private boolean isCordova15 = false;
62
62
 
63
63
  private int lastAdHeight = 0;
64
64
 
@@ -96,7 +96,7 @@ public class BannerExecutor {
96
96
  if (options.has("isCapacitor")) this.isCapacitor = options.getBoolean("isCapacitor");
97
97
  else this.isCapacitor = false;
98
98
 
99
- if (options.has("isCordova15")) this.isCordova15 = options.getBoolean("isCordova15");
99
+ if (options.has("isCordova15")) this.isCordova15 = options.getBoolean("isCordova15");
100
100
 
101
101
  final String finalSizeStr = requestedSize;
102
102
  final String finalNewPosition = newPosition;
@@ -157,19 +157,11 @@ public class BannerExecutor {
157
157
  private void loadBanner(String adUnitId, String sizeStr, CallbackContext callbackContext) {
158
158
  Context context = cordova.getActivity();
159
159
 
160
- destroyBannerInternal();
161
-
162
160
  isLoading = true;
163
161
  lastLoadTime = new Date().getTime();
164
- lastAdUnitId = adUnitId;
165
- lastSizeStr = sizeStr;
166
-
167
- adView = new AdView(context);
168
162
 
163
+ AdView pendingAdView = new AdView(context);
169
164
  AdSize adSize = getAdSize(context, sizeStr);
170
- lastAdSize = adSize;
171
-
172
- lastAdHeight = adSize.getHeightInPixels(context);
173
165
 
174
166
  BannerAdRequest.Builder builder = new BannerAdRequest.Builder(adUnitId, adSize);
175
167
 
@@ -182,19 +174,51 @@ public class BannerExecutor {
182
174
 
183
175
  BannerAdRequest request = builder.build();
184
176
 
185
- adView.loadAd(request, new AdLoadCallback<BannerAd>() {
177
+ attachPendingViewHidden(pendingAdView);
178
+
179
+ pendingAdView.loadAd(request, new AdLoadCallback<BannerAd>() {
186
180
  @Override
187
181
  public void onAdLoaded(@NonNull BannerAd bannerAd) {
188
182
  cordova.getActivity().runOnUiThread(() -> {
189
183
  isLoading = false;
190
184
 
185
+ if (adView != null) {
186
+
187
+ if (adView.getParent() != null) {
188
+ ((ViewGroup) adView.getParent()).removeView(adView);
189
+ }
190
+ adView.destroy();
191
+ }
192
+
193
+ adView = pendingAdView;
194
+ lastAdUnitId = adUnitId;
195
+ lastSizeStr = sizeStr;
196
+ lastAdSize = adSize;
197
+ lastAdHeight = adSize.getHeightInPixels(context);
198
+
191
199
  boolean isActualCollapsible = bannerAd.isCollapsible();
192
200
 
193
201
  bannerAd.setAdEventCallback(new BannerAdEventCallback() {
194
- @Override public void onAdImpression() { fireEvent("on.banner.impression", null); }
195
- @Override public void onAdClicked() { fireEvent("on.banner.clicked", null); }
196
- @Override public void onAdShowedFullScreenContent() { fireEvent("on.banner.opened", null); }
197
- @Override public void onAdDismissedFullScreenContent() { fireEvent("on.banner.closed", null); }
202
+ @Override
203
+ public void onAdImpression() {
204
+ fireEvent("on.banner.impression", null);
205
+ }
206
+
207
+ @Override
208
+ public void onAdClicked() {
209
+ fireEvent("on.banner.clicked", null);
210
+ }
211
+
212
+ @Override
213
+ public void onAdShowedFullScreenContent() {
214
+ fireEvent("on.banner.opened", null);
215
+ }
216
+
217
+ @Override
218
+ public void onAdDismissedFullScreenContent() {
219
+ fireEvent("on.banner.closed", null);
220
+ }
221
+
198
222
  @Override
199
223
  public void onAdPaid(@NonNull AdValue adValue) {
200
224
  try {
@@ -203,20 +227,27 @@ public class BannerExecutor {
203
227
  data.put("currency", adValue.getCurrencyCode());
204
228
  data.put("precision", adValue.getPrecisionType());
205
229
  fireEvent("on.banner.revenue", data);
206
- } catch (JSONException ignored) {}
230
+ } catch (JSONException ignored) {
231
+ }
207
232
  }
233
+
208
234
  @Override
209
235
  public void onAdFailedToShowFullScreenContent(@NonNull FullScreenContentError error) {
210
236
  try {
211
237
  JSONObject errData = new JSONObject();
212
238
  errData.put("message", error.getMessage());
213
239
  fireEvent("on.banner.failed.show", errData);
214
- } catch (JSONException ignored) {}
240
+ } catch (JSONException ignored) {
241
+ }
215
242
  }
216
243
  });
217
244
 
218
245
  bannerAd.setBannerAdRefreshCallback(new BannerAdRefreshCallback() {
219
- @Override public void onAdRefreshed() { fireEvent("on.banner.refreshed", null); }
246
+ @Override
247
+ public void onAdRefreshed() {
248
+ fireEvent("on.banner.refreshed", null);
249
+ }
250
+
220
251
  @Override
221
252
  public void onAdFailedToRefresh(@NonNull LoadAdError loadAdError) {
222
253
  try {
@@ -224,7 +255,8 @@ public class BannerExecutor {
224
255
  err.put("code", loadAdError.getCode());
225
256
  err.put("message", loadAdError.getMessage());
226
257
  fireEvent("on.banner.refresh.failed", err);
227
- } catch (JSONException ignored) {}
258
+ } catch (JSONException ignored) {
259
+ }
228
260
  }
229
261
  });
230
262
 
@@ -234,6 +266,7 @@ public class BannerExecutor {
234
266
  showBannerView();
235
267
  callbackContext.success("Banner Created & Shown");
236
268
  } else {
269
+ hideBannerView();
237
270
  callbackContext.success("Banner Loaded (Hidden)");
238
271
  }
239
272
  });
@@ -243,18 +276,66 @@ public class BannerExecutor {
243
276
  public void onAdFailedToLoad(@NonNull LoadAdError adError) {
244
277
  cordova.getActivity().runOnUiThread(() -> {
245
278
  isLoading = false;
279
+
280
+ if (pendingAdView.getParent() != null) {
281
+ ((ViewGroup) pendingAdView.getParent()).removeView(pendingAdView);
282
+ }
283
+ pendingAdView.destroy();
284
+
246
285
  try {
247
286
  JSONObject errData = new JSONObject();
248
287
  errData.put("code", adError.getCode());
249
288
  errData.put("message", adError.getMessage());
250
289
  fireEvent("on.banner.failed", errData);
251
- } catch (JSONException ignored) {}
290
+ } catch (JSONException ignored) {
291
+ }
292
+
252
293
  callbackContext.error("Failed: " + adError.getMessage());
253
294
  });
254
295
  }
255
296
  });
256
297
  }
257
298
 
299
+ private void attachPendingViewHidden(AdView pendingView) {
300
+ if (isCapacitor) {
301
+ if (capacitorAdLayout == null) {
302
+
303
+ capacitorAdLayout = new FrameLayout(cordova.getActivity());
304
+ capacitorAdLayout.setTag("emi_banner_layout");
305
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
306
+ FrameLayout.LayoutParams.MATCH_PARENT,
307
+ FrameLayout.LayoutParams.MATCH_PARENT
308
+ );
309
+ ViewGroup decorView = (ViewGroup) cordova.getActivity().getWindow().getDecorView();
310
+ decorView.addView(capacitorAdLayout, layoutParams);
311
+ }
312
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(1, 1);
313
+ capacitorAdLayout.addView(pendingView, params);
314
+ pendingView.setVisibility(View.INVISIBLE);
315
+ } else {
316
+ if (adLayout == null) {
317
+
318
+ adLayout = new RelativeLayout(cordova.getActivity());
319
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
320
+ RelativeLayout.LayoutParams.MATCH_PARENT,
321
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
322
+
323
+ if ("top".equalsIgnoreCase(currentPosition)) {
324
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
325
+ } else {
326
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
327
+ }
328
+
329
+ adLayout.setClickable(false);
330
+ adLayout.setFocusable(false);
331
+ cordova.getActivity().addContentView(adLayout, layoutParams);
332
+ }
333
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(1, 1);
334
+ adLayout.addView(pendingView, params);
335
+ pendingView.setVisibility(View.INVISIBLE);
336
+ }
337
+ }
338
+
258
339
  private void sendLoadedEvent(AdSize adSize, boolean isCollapsible) {
259
340
  try {
260
341
  Context context = cordova.getActivity();
@@ -274,12 +355,32 @@ public class BannerExecutor {
274
355
  else if ("MEDIUM_RECTANGLE".equalsIgnoreCase(sizeStr)) return AdSize.MEDIUM_RECTANGLE;
275
356
  else if ("FULL_BANNER".equalsIgnoreCase(sizeStr)) return AdSize.FULL_BANNER;
276
357
  else if ("LEADERBOARD".equalsIgnoreCase(sizeStr)) return AdSize.LEADERBOARD;
358
+ else if ("LARGE_LANDSCAPE_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
359
+ return AdSize.getLargeLandscapeAnchoredAdaptiveBannerAdSize(context, getAdWidth());
360
+ else if ("LARGE_PORTRAIT_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
361
+ return AdSize.getLargePortraitAnchoredAdaptiveBannerAdSize(context, getAdWidth());
362
+ else if ("CURRENT_ORIENTATION_INLINE_ADAPTIVE".equalsIgnoreCase(sizeStr))
363
+ return AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(context, getAdWidth());
364
+ else if ("LARGE_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
365
+ return AdSize.getLargeAnchoredAdaptiveBannerAdSize(context, getAdWidth());
366
+ else if ("PORTRAIT_INLINE_ADAPTIVE".equalsIgnoreCase(sizeStr))
367
+ return AdSize.getPortraitInlineAdaptiveBannerAdSize(context, getAdWidth());
277
368
  else return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(context, getAdWidth());
278
369
  }
279
370
 
280
371
  private int getAdWidth() {
281
372
  DisplayMetrics displayMetrics = cordova.getActivity().getResources().getDisplayMetrics();
282
- return (int) (displayMetrics.widthPixels / displayMetrics.density);
373
+
374
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
375
+ android.view.WindowMetrics windowMetrics = cordova.getActivity().getWindowManager().getCurrentWindowMetrics();
376
+ android.graphics.Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
377
+ android.view.WindowInsets.Type.systemBars() | android.view.WindowInsets.Type.displayCutout()
378
+ );
379
+ int widthPixels = windowMetrics.getBounds().width() - insets.left - insets.right;
380
+ return (int) (widthPixels / displayMetrics.density);
381
+ } else {
382
+ return (int) (displayMetrics.widthPixels / displayMetrics.density);
383
+ }
283
384
  }
284
385
 
285
386
  private int getScreenHeightInPx() {
@@ -443,15 +544,12 @@ public class BannerExecutor {
443
544
  systemSafeBottom = insets.getSystemWindowInsetBottom();
444
545
  }
445
546
 
446
- if (isCordova15) {
447
-
448
547
  if ("top".equalsIgnoreCase(currentPosition)) {
449
548
  adLayout.setPadding(0, systemSafeTop, 0, 0);
450
549
  } else {
451
550
  adLayout.setPadding(0, 0, 0, systemSafeBottom);
452
551
  }
453
552
 
454
- }
455
553
  updateWebViewMargins();
456
554
 
457
555
  return insets;
@@ -491,7 +589,7 @@ public class BannerExecutor {
491
589
  });
492
590
  adLayout.requestApplyInsets();
493
591
  }
494
- }
592
+ }
495
593
  }
496
594
  }
497
595
 
@@ -514,7 +612,6 @@ public class BannerExecutor {
514
612
  params.bottomMargin = 0;
515
613
  } else {
516
614
  if ("top".equalsIgnoreCase(currentPosition)) {
517
-
518
615
  params.topMargin = lastAdHeight;
519
616
  params.bottomMargin = 0;
520
617
  params.height = screenHeightInPx - lastAdHeight;
@@ -526,8 +623,23 @@ public class BannerExecutor {
526
623
  }
527
624
 
528
625
  webViewView.setTranslationY(0);
529
- webViewView.setLayoutParams(params);
530
- webViewView.requestLayout();
626
+
627
+ } else if (isCordova15) {
628
+
629
+ webViewView.setTranslationY(0);
630
+
631
+ if (!isBannerVisible || isOverlapping) {
632
+
633
+ params.setMargins(0, systemSafeTop, 0, systemSafeBottom);
634
+ } else {
635
+ if ("top".equalsIgnoreCase(currentPosition)) {
636
+
637
+ params.setMargins(0, systemSafeTop + lastAdHeight, 0, systemSafeBottom);
638
+ } else {
639
+
640
+ params.setMargins(0, systemSafeTop, 0, systemSafeBottom + lastAdHeight);
641
+ }
642
+ }
531
643
 
532
644
  } else {
533
645
 
@@ -550,10 +662,10 @@ public class BannerExecutor {
550
662
  params.setMargins(0, 0, 0, finalBottom);
551
663
  }
552
664
  }
553
-
554
- webViewView.setLayoutParams(params);
555
- webViewView.requestLayout();
556
665
  }
666
+
667
+ webViewView.setLayoutParams(params);
668
+ webViewView.requestLayout();
557
669
  }
558
670
  }
559
671
 
@@ -55,6 +55,7 @@ public class BannerPreloadExecutor {
55
55
  private boolean isOverlapping = true;
56
56
  private boolean isBannerVisible = false;
57
57
  private boolean isCapacitor = false;
58
+ private boolean isCordova15 = false;
58
59
 
59
60
  private int lastAdHeight = 0;
60
61
 
@@ -62,7 +63,7 @@ public class BannerPreloadExecutor {
62
63
  private int systemSafeBottom = 0;
63
64
 
64
65
  private long lastShowTime = 0;
65
- private long minShowInterval = 5000;
66
+ private long minShowInterval = 5000;
66
67
 
67
68
  public BannerPreloadExecutor(CordovaInterface cordova, CordovaWebView webView) {
68
69
  this.cordova = cordova;
@@ -86,6 +87,8 @@ public class BannerPreloadExecutor {
86
87
  if (options.has("isOverlapping")) this.isOverlapping = options.getBoolean("isOverlapping");
87
88
  if (options.has("isCapacitor")) this.isCapacitor = options.getBoolean("isCapacitor");
88
89
 
90
+ if (options.has("isCordova15")) this.isCordova15 = options.getBoolean("isCordova15");
91
+
89
92
  if (options.has("retryInterval")) this.minShowInterval = options.getLong("retryInterval");
90
93
 
91
94
  String requestedSize = "ADAPTIVE";
@@ -163,21 +166,33 @@ public class BannerPreloadExecutor {
163
166
  } catch (JSONException ignored) {}
164
167
  }
165
168
 
166
- if (currentBannerAd != null && isBannerVisible) {
169
+ if (currentBannerAd != null) {
167
170
  boolean isSamePos = newPosition.equalsIgnoreCase(this.currentPosition);
168
171
  boolean isSameOverlap = (newIsOverlapping == this.isOverlapping);
169
172
 
170
- if (isSamePos && isSameOverlap) {
171
- callbackContext.success("Banner Already Visible (Flicker Prevented)");
172
- return;
173
+ if (isBannerVisible) {
174
+ if (isSamePos && isSameOverlap) {
175
+ callbackContext.success("Banner Already Visible (Flicker Prevented)");
176
+ return;
177
+ } else {
178
+ this.currentPosition = newPosition;
179
+ this.isOverlapping = newIsOverlapping;
180
+
181
+ cordova.getActivity().runOnUiThread(() -> {
182
+ updateBannerLayout();
183
+ updateWebViewMargins();
184
+ callbackContext.success("Banner Repositioned");
185
+ });
186
+ return;
187
+ }
173
188
  } else {
189
+
174
190
  this.currentPosition = newPosition;
175
191
  this.isOverlapping = newIsOverlapping;
176
192
 
177
193
  cordova.getActivity().runOnUiThread(() -> {
178
- updateBannerLayout();
179
- updateWebViewMargins();
180
- callbackContext.success("Banner Repositioned (No Pool Exhaustion)");
194
+ showBannerView();
195
+ callbackContext.success("Banner Unhidden (Restored from hidden state)");
181
196
  });
182
197
  return;
183
198
  }
@@ -201,13 +216,22 @@ public class BannerPreloadExecutor {
201
216
  return;
202
217
  }
203
218
 
204
- destroyCurrentBanner();
205
- this.currentBannerAd = ad;
219
+ BannerAd oldBannerAd = this.currentBannerAd;
206
220
 
221
+ this.currentBannerAd = ad;
207
222
  this.lastAdHeight = ad.getAdSize().getHeightInPixels(cordova.getActivity());
208
223
 
209
224
  setupAdEvents(ad);
210
225
  showBannerView();
226
+
227
+ if (oldBannerAd != null && oldBannerAd != ad) {
228
+ View oldView = oldBannerAd.getView(cordova.getActivity());
229
+ if (oldView != null && oldView.getParent() != null) {
230
+ ((ViewGroup) oldView.getParent()).removeView(oldView);
231
+ }
232
+ oldBannerAd.destroy();
233
+ }
234
+
211
235
  sendLoadedEvent(ad.getAdSize(), ad.isCollapsible());
212
236
 
213
237
  callbackContext.success("Ad Shown from Pool");
@@ -359,36 +383,66 @@ public class BannerPreloadExecutor {
359
383
  } else {
360
384
  adView.setLayoutParams(bannerParams);
361
385
  }
386
+ if (isCordova15) {
362
387
 
363
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
364
- adLayout.setOnApplyWindowInsetsListener((v, insets) -> {
388
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
389
+ adLayout.setOnApplyWindowInsetsListener((v, insets) -> {
365
390
 
366
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
367
- android.graphics.Insets sysInsets = insets.getInsets(android.view.WindowInsets.Type.systemBars());
368
- systemSafeTop = sysInsets.top;
369
- systemSafeBottom = sysInsets.bottom;
370
- } else {
371
- systemSafeTop = insets.getSystemWindowInsetTop();
372
- systemSafeBottom = insets.getSystemWindowInsetBottom();
373
- }
391
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
392
+ android.graphics.Insets sysInsets = insets.getInsets(android.view.WindowInsets.Type.systemBars());
393
+ systemSafeTop = sysInsets.top;
394
+ systemSafeBottom = sysInsets.bottom;
395
+ } else {
396
+ systemSafeTop = insets.getSystemWindowInsetTop();
397
+ systemSafeBottom = insets.getSystemWindowInsetBottom();
398
+ }
374
399
 
375
- if (adView.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
376
- RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) adView.getLayoutParams();
377
400
  if ("top".equalsIgnoreCase(currentPosition)) {
378
- params.topMargin = systemSafeTop;
379
- params.bottomMargin = 0;
401
+ adLayout.setPadding(0, systemSafeTop, 0, 0);
380
402
  } else {
381
- params.bottomMargin = systemSafeBottom;
382
- params.topMargin = 0;
403
+ adLayout.setPadding(0, 0, 0, systemSafeBottom);
383
404
  }
384
- adView.setLayoutParams(params);
385
- }
386
405
 
387
- updateWebViewMargins();
388
- return insets;
389
- });
390
- adLayout.requestApplyInsets();
391
- }
406
+ updateWebViewMargins();
407
+
408
+ return insets;
409
+ });
410
+ adLayout.requestApplyInsets();
411
+ }
412
+
413
+ } else {
414
+
415
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
416
+ adLayout.setOnApplyWindowInsetsListener((v, insets) -> {
417
+
418
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
419
+ android.graphics.Insets sysInsets = insets.getInsets(android.view.WindowInsets.Type.systemBars());
420
+ systemSafeTop = sysInsets.top;
421
+ systemSafeBottom = sysInsets.bottom;
422
+ } else {
423
+ systemSafeTop = insets.getSystemWindowInsetTop();
424
+ systemSafeBottom = insets.getSystemWindowInsetBottom();
425
+ }
426
+
427
+ if (adView != null && adView.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
428
+ RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) adView.getLayoutParams();
429
+ if ("top".equalsIgnoreCase(currentPosition)) {
430
+ params.topMargin = systemSafeTop;
431
+ params.bottomMargin = 0;
432
+ } else {
433
+ params.bottomMargin = systemSafeBottom;
434
+ params.topMargin = 0;
435
+ }
436
+ adView.setLayoutParams(params);
437
+ }
438
+
439
+ updateWebViewMargins();
440
+
441
+ return insets;
442
+ });
443
+ adLayout.requestApplyInsets();
444
+ }
445
+ }
392
446
  }
393
447
  }
394
448
 
@@ -398,36 +452,36 @@ public class BannerPreloadExecutor {
398
452
  View webViewView = webView.getView();
399
453
  ViewGroup.LayoutParams lp = webViewView.getLayoutParams();
400
454
 
401
- if (isCapacitor) {
455
+ if (lp instanceof ViewGroup.MarginLayoutParams) {
456
+ ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lp;
457
+
458
+ if (isCapacitor) {
402
459
 
403
- if (lp instanceof ViewGroup.MarginLayoutParams) {
404
- ViewGroup.MarginLayoutParams capLp = (ViewGroup.MarginLayoutParams) lp;
405
460
  int screenHeightInPx = getScreenHeightInPx();
406
- boolean isFull = isFullScreenMode();
407
461
 
408
462
  if (!isBannerVisible || isOverlapping) {
409
- capLp.height = ViewGroup.LayoutParams.MATCH_PARENT;
410
- capLp.topMargin = 0;
463
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
464
+ params.topMargin = 0;
465
+ params.bottomMargin = 0;
411
466
  } else {
412
467
  if ("top".equalsIgnoreCase(currentPosition)) {
413
468
 
414
- capLp.topMargin = lastAdHeight;
415
- capLp.bottomMargin = 0;
416
- capLp.height = screenHeightInPx - lastAdHeight;
469
+ params.topMargin = lastAdHeight;
470
+ params.bottomMargin = 0;
471
+ params.height = screenHeightInPx - lastAdHeight;
417
472
  } else {
418
473
  int webViewHeight = screenHeightInPx - lastAdHeight;
419
- capLp.height = webViewHeight;
420
- capLp.topMargin = 0;
474
+ params.height = webViewHeight;
475
+ params.topMargin = 0;
421
476
  }
422
477
  }
423
478
 
424
- webViewView.setLayoutParams(capLp);
479
+ webViewView.setTranslationY(0);
480
+ webViewView.setLayoutParams(params);
425
481
  webViewView.requestLayout();
426
- }
427
- } else {
428
482
 
429
- if (lp instanceof ViewGroup.MarginLayoutParams) {
430
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lp;
483
+ } else {
484
+
431
485
  if ("top".equalsIgnoreCase(currentPosition)) {
432
486
  params.setMargins(0, 0, 0, 0);
433
487
 
@@ -447,6 +501,7 @@ public class BannerPreloadExecutor {
447
501
  params.setMargins(0, 0, 0, finalBottom);
448
502
  }
449
503
  }
504
+
450
505
  webViewView.setLayoutParams(params);
451
506
  webViewView.requestLayout();
452
507
  }
@@ -596,12 +651,32 @@ public class BannerPreloadExecutor {
596
651
  else if ("MEDIUM_RECTANGLE".equalsIgnoreCase(sizeStr)) return AdSize.MEDIUM_RECTANGLE;
597
652
  else if ("FULL_BANNER".equalsIgnoreCase(sizeStr)) return AdSize.FULL_BANNER;
598
653
  else if ("LEADERBOARD".equalsIgnoreCase(sizeStr)) return AdSize.LEADERBOARD;
654
+ else if ("LARGE_LANDSCAPE_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
655
+ return AdSize.getLargeLandscapeAnchoredAdaptiveBannerAdSize(context, getAdWidth());
656
+ else if ("LARGE_PORTRAIT_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
657
+ return AdSize.getLargePortraitAnchoredAdaptiveBannerAdSize(context, getAdWidth());
658
+ else if ("CURRENT_ORIENTATION_INLINE_ADAPTIVE".equalsIgnoreCase(sizeStr))
659
+ return AdSize.getCurrentOrientationInlineAdaptiveBannerAdSize(context, getAdWidth());
660
+ else if ("LARGE_ANCHORED_ADAPTIVE".equalsIgnoreCase(sizeStr))
661
+ return AdSize.getLargeAnchoredAdaptiveBannerAdSize(context, getAdWidth());
662
+ else if ("PORTRAIT_INLINE_ADAPTIVE".equalsIgnoreCase(sizeStr))
663
+ return AdSize.getPortraitInlineAdaptiveBannerAdSize(context, getAdWidth());
599
664
  else return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(context, getAdWidth());
600
665
  }
601
666
 
602
667
  private int getAdWidth() {
603
668
  DisplayMetrics displayMetrics = cordova.getActivity().getResources().getDisplayMetrics();
604
- return (int) (displayMetrics.widthPixels / displayMetrics.density);
669
+
670
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
671
+ android.view.WindowMetrics windowMetrics = cordova.getActivity().getWindowManager().getCurrentWindowMetrics();
672
+ android.graphics.Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
673
+ android.view.WindowInsets.Type.systemBars() | android.view.WindowInsets.Type.displayCutout()
674
+ );
675
+ int widthPixels = windowMetrics.getBounds().width() - insets.left - insets.right;
676
+ return (int) (widthPixels / displayMetrics.density);
677
+ } else {
678
+ return (int) (displayMetrics.widthPixels / displayMetrics.density);
679
+ }
605
680
  }
606
681
 
607
682
  private void fireEvent(String eventName, JSONObject data) {
@@ -51,12 +51,18 @@ public class NativeExecutor {
51
51
  private NativeAd mNativeAd;
52
52
 
53
53
  private boolean isOverlapping = true;
54
+ private boolean isCapacitor = false;
55
+ private boolean isCordova15 = false;
54
56
  private String currentPreset = "";
55
57
  private int currentAdHeightPixels = 0;
56
58
 
57
59
  private boolean isLoading = false;
58
60
  private long lastLoadTime = 0;
59
61
  private long minLoadInterval = 5000;
62
+ private boolean isNativeVisible = false;
63
+
64
+ private int systemSafeTop = 0;
65
+ private int systemSafeBottom = 0;
60
66
 
61
67
  public NativeExecutor(CordovaInterface cordova, CordovaWebView webView) {
62
68
  this.cordova = cordova;
@@ -89,6 +95,10 @@ public class NativeExecutor {
89
95
  String viewMode = options.optString("view", "custom");
90
96
  this.currentPreset = viewMode;
91
97
  this.isOverlapping = options.optBoolean("isOverlapping", true);
98
+ this.isCapacitor = options.optBoolean("isCapacitor", false);
99
+ if (options.has("isCordova15")) {
100
+ this.isCordova15 = options.getBoolean("isCordova15");
101
+ }
92
102
 
93
103
  DisplayMetrics metrics = cordova.getActivity().getResources().getDisplayMetrics();
94
104
  float density = metrics.density;
@@ -158,14 +168,78 @@ public class NativeExecutor {
158
168
  public void onNativeAdLoaded(@NonNull NativeAd nativeAd) {
159
169
 
160
170
  cordova.getActivity().runOnUiThread(() -> {
161
-
162
171
  isLoading = false;
163
172
 
164
- removeNativeAd();
173
+ NativeAdView pendingView = buildNativeAdView(nativeAd, x, y, w, h);
174
+
175
+ if (adContainer == null) {
176
+ adContainer = new RelativeLayout(cordova.getActivity());
177
+ ViewGroup.LayoutParams containerParams = new ViewGroup.LayoutParams(
178
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
179
+ cordova.getActivity().addContentView(adContainer, containerParams);
180
+
181
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
182
+ adContainer.setOnApplyWindowInsetsListener((v, insets) -> {
183
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
184
+ android.graphics.Insets sysInsets = insets.getInsets(android.view.WindowInsets.Type.systemBars());
185
+ systemSafeTop = sysInsets.top;
186
+ systemSafeBottom = sysInsets.bottom;
187
+ } else {
188
+ systemSafeTop = insets.getSystemWindowInsetTop();
189
+ systemSafeBottom = insets.getSystemWindowInsetBottom();
190
+ }
191
+
192
+ if (isCordova15) {
193
+
194
+ if ("banner_top".equalsIgnoreCase(currentPreset)) {
195
+ adContainer.setPadding(0, systemSafeTop, 0, 0);
196
+ } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
197
+ adContainer.setPadding(0, 0, 0, systemSafeBottom);
198
+ } else {
199
+ adContainer.setPadding(0, 0, 0, 0);
200
+ }
201
+ } else {
202
+
203
+ if (nativeAdView != null && nativeAdView.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
204
+ RelativeLayout.LayoutParams viewParams = (RelativeLayout.LayoutParams) nativeAdView.getLayoutParams();
205
+ if ("banner_top".equalsIgnoreCase(currentPreset)) {
206
+ viewParams.topMargin = systemSafeTop;
207
+ viewParams.bottomMargin = 0;
208
+ } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
209
+ viewParams.bottomMargin = systemSafeBottom;
210
+ viewParams.topMargin = 0;
211
+ }
212
+ nativeAdView.setLayoutParams(viewParams);
213
+ }
214
+ }
215
+
216
+ updateWebViewMargins();
217
+ return insets;
218
+ });
219
+ adContainer.requestApplyInsets();
220
+ }
221
+ }
222
+
223
+ RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) pendingView.getLayoutParams();
224
+
225
+ adContainer.addView(pendingView, layoutParams);
226
+ adContainer.bringToFront();
227
+
228
+ if (nativeAdView != null) {
229
+ adContainer.removeView(nativeAdView);
230
+ nativeAdView.destroy();
231
+ }
232
+ if (mNativeAd != null && mNativeAd != nativeAd) {
233
+ mNativeAd.destroy();
234
+ }
235
+
236
+ nativeAdView = pendingView;
165
237
  mNativeAd = nativeAd;
166
238
 
239
+ isNativeVisible = true;
240
+
167
241
  setupEventCallback(nativeAd);
168
- showNativeAdView(nativeAd, x, y, w, h);
242
+ updateWebViewMargins();
169
243
 
170
244
  fireEvent("on.native.loaded", null);
171
245
  callbackContext.success("Native Ad Shown");
@@ -183,7 +257,7 @@ public class NativeExecutor {
183
257
  err.put("code", loadAdError.getCode());
184
258
  err.put("message", loadAdError.getMessage());
185
259
  fireEvent("on.native.failed", err);
186
- } catch (JSONException e) {}
260
+ } catch (JSONException ignored) {}
187
261
  callbackContext.error(loadAdError.getMessage());
188
262
  });
189
263
  }
@@ -192,48 +266,7 @@ public class NativeExecutor {
192
266
  NativeAdLoader.load(request, loaderCallback);
193
267
  }
194
268
 
195
- private void setupEventCallback(NativeAd nativeAd) {
196
- nativeAd.setAdEventCallback(new NativeAdEventCallback() {
197
- @Override
198
- public void onAdShowedFullScreenContent() {
199
- fireEvent("on.native.shown", null);
200
- }
201
- @Override
202
- public void onAdDismissedFullScreenContent() {
203
- fireEvent("on.native.dismissed", null);
204
- }
205
- @Override
206
- public void onAdFailedToShowFullScreenContent(@NonNull com.google.android.libraries.ads.mobile.sdk.common.FullScreenContentError error) {
207
-
208
- try {
209
- JSONObject errData = new JSONObject();
210
- errData.put("message", error.getMessage());
211
- fireEvent("on.native.show.failed", errData);
212
- } catch (JSONException e) {}
213
- }
214
- @Override
215
- public void onAdImpression() {
216
- fireEvent("on.native.impression", null);
217
- }
218
- @Override
219
- public void onAdClicked() {
220
- fireEvent("on.native.clicked", null);
221
- }
222
- @Override
223
- public void onAdPaid(@NonNull AdValue adValue) {
224
- try {
225
- JSONObject data = new JSONObject();
226
- data.put("value", adValue.getValueMicros());
227
- data.put("currency", adValue.getCurrencyCode());
228
- data.put("precision", adValue.getPrecisionType());
229
-
230
- fireEvent("on.native.revenue", data);
231
- } catch (JSONException e) {}
232
- }
233
- });
234
- }
235
-
236
- private void showNativeAdView(NativeAd nativeAd, int x, int y, int width, int height) {
269
+ private NativeAdView buildNativeAdView(NativeAd nativeAd, int x, int y, int width, int height) {
237
270
  float density = cordova.getActivity().getResources().getDisplayMetrics().density;
238
271
 
239
272
  int finalX = (int) (x * density);
@@ -245,11 +278,25 @@ public class NativeExecutor {
245
278
 
246
279
  boolean isSmallMode = (height < 150);
247
280
 
248
- nativeAdView = new NativeAdView(cordova.getActivity());
281
+ NativeAdView newNativeAdView = new NativeAdView(cordova.getActivity());
249
282
 
250
283
  RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(finalW, finalH);
251
- params.leftMargin = finalX;
252
- params.topMargin = finalY;
284
+
285
+ if ("banner_top".equalsIgnoreCase(currentPreset)) {
286
+ params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
287
+ params.addRule(RelativeLayout.CENTER_HORIZONTAL);
288
+ } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
289
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
290
+ params.addRule(RelativeLayout.CENTER_HORIZONTAL);
291
+ } else if ("modal_center".equalsIgnoreCase(currentPreset)) {
292
+ params.addRule(RelativeLayout.CENTER_IN_PARENT);
293
+ } else {
294
+
295
+ params.leftMargin = finalX;
296
+ params.topMargin = finalY;
297
+ }
298
+
299
+ newNativeAdView.setLayoutParams(params);
253
300
 
254
301
  LinearLayout mainLayout = new LinearLayout(cordova.getActivity());
255
302
  mainLayout.setOrientation(LinearLayout.VERTICAL);
@@ -325,44 +372,77 @@ public class NativeExecutor {
325
372
  }
326
373
  mainLayout.addView(ctaView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
327
374
 
328
- nativeAdView.addView(mainLayout);
375
+ newNativeAdView.addView(mainLayout);
329
376
 
330
- nativeAdView.setIconView(iconView);
331
- nativeAdView.setHeadlineView(headlineView);
332
- nativeAdView.setBodyView(bodyView);
333
- nativeAdView.setCallToActionView(ctaView);
334
- nativeAdView.registerNativeAd(nativeAd, mediaView);
377
+ newNativeAdView.setIconView(iconView);
378
+ newNativeAdView.setHeadlineView(headlineView);
379
+ newNativeAdView.setBodyView(bodyView);
380
+ newNativeAdView.setCallToActionView(ctaView);
381
+ newNativeAdView.registerNativeAd(nativeAd, mediaView);
335
382
 
336
- MediaContent mediaContent = nativeAd.getMediaContent();
337
- if (mediaContent != null && mediaContent.getHasVideoContent()) {
338
- VideoController vc = mediaContent.getVideoController();
339
- }
383
+ return newNativeAdView;
384
+ }
340
385
 
341
- if (adContainer == null) {
342
- adContainer = new RelativeLayout(cordova.getActivity());
343
- ViewGroup.LayoutParams containerParams = new ViewGroup.LayoutParams(
344
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
345
- cordova.getActivity().addContentView(adContainer, containerParams);
346
- }
386
+ private void setupEventCallback(NativeAd nativeAd) {
387
+ nativeAd.setAdEventCallback(new NativeAdEventCallback() {
388
+ @Override
389
+ public void onAdShowedFullScreenContent() {
390
+ fireEvent("on.native.shown", null);
391
+ }
392
+ @Override
393
+ public void onAdDismissedFullScreenContent() {
394
+ fireEvent("on.native.dismissed", null);
395
+ }
396
+ @Override
397
+ public void onAdFailedToShowFullScreenContent(@NonNull com.google.android.libraries.ads.mobile.sdk.common.FullScreenContentError error) {
347
398
 
348
- adContainer.addView(nativeAdView, params);
349
- adContainer.bringToFront();
399
+ try {
400
+ JSONObject errData = new JSONObject();
401
+ errData.put("message", error.getMessage());
402
+ fireEvent("on.native.show.failed", errData);
403
+ } catch (JSONException e) {}
404
+ }
405
+ @Override
406
+ public void onAdImpression() {
407
+ fireEvent("on.native.impression", null);
408
+ }
409
+ @Override
410
+ public void onAdClicked() {
411
+ fireEvent("on.native.clicked", null);
412
+ }
413
+ @Override
414
+ public void onAdPaid(@NonNull AdValue adValue) {
415
+ try {
416
+ JSONObject data = new JSONObject();
417
+ data.put("value", adValue.getValueMicros());
418
+ data.put("currency", adValue.getCurrencyCode());
419
+ data.put("precision", adValue.getPrecisionType());
350
420
 
351
- updateWebViewMargins();
421
+ fireEvent("on.native.revenue", data);
422
+ } catch (JSONException e) {}
423
+ }
424
+ });
352
425
  }
353
426
 
354
427
  public void removeNativeAd() {
355
428
  cordova.getActivity().runOnUiThread(() -> {
429
+
430
+ isNativeVisible = false;
431
+
356
432
  if (nativeAdView != null) {
357
433
  nativeAdView.destroy();
358
434
  if (adContainer != null) {
359
435
  adContainer.removeView(nativeAdView);
360
436
  }
361
437
  nativeAdView = null;
362
- mNativeAd = null;
438
+ }
363
439
 
364
- resetWebViewMargins();
440
+ if (mNativeAd != null) {
441
+ mNativeAd.destroy();
442
+ mNativeAd = null;
365
443
  }
444
+
445
+ updateWebViewMargins();
366
446
  });
367
447
  }
368
448
 
@@ -375,14 +455,74 @@ public class NativeExecutor {
375
455
  if (lp instanceof ViewGroup.MarginLayoutParams) {
376
456
  ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lp;
377
457
 
378
- if (isOverlapping) {
379
- params.setMargins(0, 0, 0, 0);
458
+ if (isCapacitor) {
459
+
460
+ int screenHeightInPx = getScreenHeightInPx();
461
+
462
+ if (!isNativeVisible || isOverlapping) {
463
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
464
+ params.topMargin = 0;
465
+ params.bottomMargin = 0;
466
+ } else {
467
+ if ("banner_top".equalsIgnoreCase(currentPreset)) {
468
+ params.topMargin = currentAdHeightPixels;
469
+ params.bottomMargin = 0;
470
+ params.height = screenHeightInPx - currentAdHeightPixels;
471
+ } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
472
+ int webViewHeight = screenHeightInPx - currentAdHeightPixels;
473
+ params.height = webViewHeight;
474
+ params.topMargin = 0;
475
+ } else {
476
+
477
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
478
+ params.topMargin = 0;
479
+ params.bottomMargin = 0;
480
+ }
481
+ }
482
+
483
+ webViewView.setTranslationY(0);
484
+
485
+ } else if (isCordova15) {
486
+
487
+ webViewView.setTranslationY(0);
488
+
489
+ if (!isNativeVisible || isOverlapping) {
490
+
491
+ params.setMargins(0, systemSafeTop, 0, systemSafeBottom);
492
+ } else {
493
+ if ("banner_top".equalsIgnoreCase(currentPreset)) {
494
+
495
+ params.setMargins(0, systemSafeTop + currentAdHeightPixels, 0, systemSafeBottom);
496
+ } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
497
+
498
+ params.setMargins(0, systemSafeTop, 0, systemSafeBottom + currentAdHeightPixels);
499
+ } else {
500
+ params.setMargins(0, systemSafeTop, 0, systemSafeBottom);
501
+ }
502
+ }
503
+
380
504
  } else {
505
+
381
506
  if ("banner_top".equalsIgnoreCase(currentPreset)) {
382
- params.setMargins(0, currentAdHeightPixels, 0, 0);
507
+ params.setMargins(0, 0, 0, 0);
508
+
509
+ if (isNativeVisible && !isOverlapping) {
510
+ float shift = (float) (currentAdHeightPixels + systemSafeTop);
511
+ webViewView.setTranslationY(shift);
512
+ } else {
513
+ webViewView.setTranslationY(0);
514
+ }
383
515
  } else if ("banner_bottom".equalsIgnoreCase(currentPreset)) {
384
- params.setMargins(0, 0, 0, currentAdHeightPixels);
516
+ webViewView.setTranslationY(0);
517
+
518
+ if (!isNativeVisible || isOverlapping) {
519
+ params.setMargins(0, 0, 0, 0);
520
+ } else {
521
+ int finalBottom = currentAdHeightPixels + systemSafeBottom;
522
+ params.setMargins(0, 0, 0, finalBottom);
523
+ }
385
524
  } else {
525
+ webViewView.setTranslationY(0);
386
526
  params.setMargins(0, 0, 0, 0);
387
527
  }
388
528
  }
@@ -392,19 +532,31 @@ public class NativeExecutor {
392
532
  }
393
533
  }
394
534
 
395
- private void resetWebViewMargins() {
396
- if (webView == null || webView.getView() == null) return;
397
- View webViewView = webView.getView();
398
- ViewGroup.LayoutParams lp = webViewView.getLayoutParams();
399
-
400
- if (lp instanceof ViewGroup.MarginLayoutParams) {
401
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lp;
402
- params.setMargins(0, 0, 0, 0);
403
- webViewView.setLayoutParams(params);
404
- webViewView.requestLayout();
535
+ private int getScreenHeightInPx() {
536
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
537
+ android.view.WindowMetrics windowMetrics = cordova.getActivity().getWindowManager().getCurrentWindowMetrics();
538
+ android.graphics.Insets insets = windowMetrics.getWindowInsets().getInsets(android.view.WindowInsets.Type.systemBars());
539
+ return windowMetrics.getBounds().height() - insets.top - insets.bottom;
540
+ } else {
541
+ DisplayMetrics displayMetrics = new DisplayMetrics();
542
+ cordova.getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
543
+ return displayMetrics.heightPixels;
405
544
  }
406
545
  }
407
546
 
547
+ public void destroy() {
548
+ cordova.getActivity().runOnUiThread(() -> {
549
+ removeNativeAd();
550
+ if (adContainer != null) {
551
+ if (adContainer.getParent() != null) {
552
+ ((ViewGroup) adContainer.getParent()).removeView(adContainer);
553
+ }
554
+ adContainer.removeAllViews();
555
+ adContainer = null;
556
+ }
557
+ });
558
+ }
559
+
408
560
  private void fireEvent(String eventName, JSONObject data) {
409
561
  cordova.getActivity().runOnUiThread(() -> {
410
562
  StringBuilder js = new StringBuilder();
@@ -115,6 +115,17 @@ var AdMobNextGen = {
115
115
  },
116
116
 
117
117
  createNativeAd: function (options, successEvent, error) {
118
+ var isCapacitorEnvironment = typeof window.Capacitor !== 'undefined';
119
+ var isCordova15Environment = false;
120
+ if (!isCapacitorEnvironment && typeof cordova !== 'undefined' && cordova.platformVersion) {
121
+ var majorVersion = parseInt(cordova.platformVersion.split('.')[0], 10);
122
+ if (majorVersion >= 15) {
123
+ isCordova15Environment = true;
124
+ }
125
+ }
126
+ options = options || {};
127
+ options.isCapacitor = isCapacitorEnvironment;
128
+ options.isCordova15 = isCordova15Environment;
118
129
  exec(successEvent, error, 'AdMobNextGen', 'createNativeAd', [options]);
119
130
  },
120
131
 
@@ -123,10 +134,17 @@ var AdMobNextGen = {
123
134
  },
124
135
 
125
136
  startBannerPreload: function (options, success, error) {
126
- var isCapacitorEnvironment = typeof window.Capacitor !== 'undefined';
127
-
137
+ var isCapacitorEnvironment = typeof window.Capacitor !== 'undefined';
138
+ var isCordova15Environment = false;
139
+ if (!isCapacitorEnvironment && typeof cordova !== 'undefined' && cordova.platformVersion) {
140
+ var majorVersion = parseInt(cordova.platformVersion.split('.')[0], 10);
141
+ if (majorVersion >= 15) {
142
+ isCordova15Environment = true;
143
+ }
144
+ }
128
145
  options = options || {};
129
146
  options.isCapacitor = isCapacitorEnvironment;
147
+ options.isCordova15 = isCordova15Environment;
130
148
 
131
149
  exec(success, error, 'AdMobNextGen', 'startBannerPreload', [options]);
132
150
  },