Skip to content

Commit 4c9ad50

Browse files
Fix Java-generic name-clash in AdLoadCallback subclasses (issue #1491) (#1492)
Fixes #1491. ## Problem `AdLoadCallback<AdT>` declares `public void onAdLoaded(AdT ad)`, which erases to `onAdLoaded(Object)` in bytecode. The binding therefore only exposes `virtual OnAdLoaded(Java.Lang.Object p0)` on every concrete subclass: - `AdManagerInterstitialAdLoadCallback` - `InterstitialAdLoadCallback` - `RewardedAdLoadCallback` - `RewardedInterstitialAdLoadCallback` - `AppOpenAd.AppOpenAdLoadCallback` When a user overrides that in C#, the generated ACW Java stub emits `public void onAdLoaded(java.lang.Object p0)`, and javac rejects it: ``` error: name clash: onAdLoaded(Object) in MyCallback and onAdLoaded(AdManagerInterstitialAd) in AdLoadCallback have the same erasure, yet neither overrides the other ``` After generic substitution the parent's real method is the specialized one, so the erased override doesn't satisfy javac. ## Fix For each concrete `*AdLoadCallback` subclass, add a specialized `onAdLoaded(SpecificAd)` method via `<add-node>` in the binding's `Transforms/Metadata.xml`. The binding now surfaces a properly-typed `virtual OnAdLoaded(SpecificAd)` with a specialized JNI registration, e.g.: ```csharp [Register("onAdLoaded", "(Lcom/google/android/gms/ads/admanager/AdManagerInterstitialAd;)V", "GetOnAdLoaded_Lcom_google_android_gms_ads_admanager_AdManagerInterstitialAd_Handler")] public virtual unsafe void OnAdLoaded(AdManagerInterstitialAd p0) { ... } ``` Users override the specialized overload, and the resulting ACW stub emits the specialized Java signature that correctly overrides the parent — matching how Google's docs show the callback being subclassed in Java. The same fix is applied in **both** bindings that ship these types: - `play-services-ads-lite` — `Android.Gms.Ads.*` namespace (used by `Xamarin.GooglePlayServices.Ads.Lite` direct consumers). - `play-services-ads-api` — `Google.Android.Gms.Ads.*` namespace (pulled in transitively by `Xamarin.GooglePlayServices.Ads`, which is what the issue reporter uses). Both `.aar`s independently contain the `*AdLoadCallback.class` files and each produces its own set of .NET types, so the metadata must be added in both places. ## Version bumps - `Xamarin.GooglePlayServices.Ads.Lite`: `124.0.0.6` → `124.0.0.7` - `Xamarin.GooglePlayServices.Ads.Api`: `125.4.0.1` → `125.4.0.2` - `Xamarin.GooglePlayServices.Ads`: `125.4.0.1` → `125.4.0.2` ## User-facing migration Users hitting `javac.exe error JAVAC0000` from #1491 should change: ```csharp public override void OnAdLoaded(Java.Lang.Object p0) { ... } ``` to the specialized overload, e.g.: ```csharp public override void OnAdLoaded(AdManagerInterstitialAd p0) { ... } ``` ## Verification - `dotnet cake --target=metadata-verify` passes. - Built both `com.google.android.gms.play-services-ads-lite` and `com.google.android.gms.play-services-ads-api` locally (against a project-referenced `Ads.Base` since the published `Ads.Base 124.0.0.1` NuGet does not yet target `net10.0-android36`) — build succeeded, 0 warnings, 0 errors. - Verified generated `*AdLoadCallback.cs` in each project's `obj/` contains the specialized `virtual void OnAdLoaded(SpecificAd p0)` with the expected `[Register("onAdLoaded", "(Lcom/.../SpecificAd;)V", ...)]`. - All 5 specialized overloads picked up in `PublicAPI.Unshipped.txt` for both packages by the analyzer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent fe9978d commit 4c9ad50

5 files changed

Lines changed: 139 additions & 3 deletions

File tree

config.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2730,7 +2730,7 @@
27302730
"groupId": "com.google.android.gms",
27312731
"artifactId": "play-services-ads",
27322732
"version": "25.4.0",
2733-
"nugetVersion": "125.4.0.1",
2733+
"nugetVersion": "125.4.0.2",
27342734
"nugetId": "Xamarin.GooglePlayServices.Ads",
27352735
"allowPrereleaseDependencies": true,
27362736
"extraDependencies": "androidx.lifecycle.lifecycle-livedata-core,androidx.lifecycle.lifecycle-runtime",
@@ -2740,7 +2740,7 @@
27402740
"groupId": "com.google.android.gms",
27412741
"artifactId": "play-services-ads-api",
27422742
"version": "25.4.0",
2743-
"nugetVersion": "125.4.0.1",
2743+
"nugetVersion": "125.4.0.2",
27442744
"nugetId": "Xamarin.GooglePlayServices.Ads.Api",
27452745
"type": "xbd"
27462746
},
@@ -2764,7 +2764,7 @@
27642764
"groupId": "com.google.android.gms",
27652765
"artifactId": "play-services-ads-lite",
27662766
"version": "24.0.0",
2767-
"nugetVersion": "124.0.0.6",
2767+
"nugetVersion": "124.0.0.7",
27682768
"nugetId": "Xamarin.GooglePlayServices.Ads.Lite",
27692769
"frozen": true,
27702770
"extraDependencies": "androidx.lifecycle.lifecycle-livedata-core,androidx.lifecycle.lifecycle-runtime",

source/com.google.android.gms/play-services-ads-api/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,17 @@ Google.Android.Gms.Ads.Initialization.IOnInitializationCompleteListener.OnInitia
227227
Google.Android.Gms.Ads.Initialization.InitializationCompleteEventArgs
228228
Google.Android.Gms.Ads.Initialization.InitializationCompleteEventArgs.InitializationCompleteEventArgs(Google.Android.Gms.Ads.Initialization.IInitializationStatus! p0) -> void
229229
Google.Android.Gms.Ads.Initialization.InitializationCompleteEventArgs.P0.get -> Google.Android.Gms.Ads.Initialization.IInitializationStatus!
230+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpDeepLinkServiceWrapper
231+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpDeepLinkServiceWrapper.EndSession(Android.Gms.Dynamic.IObjectWrapper! p0, string! p1) -> void
232+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpDeepLinkServiceWrapper.Open(Android.Gms.Dynamic.IObjectWrapper! p0, string! p1, string! p2, Android.OS.Bundle! p3, bool p4, Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpServiceCallback! p5) -> void
233+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpDeepLinkServiceWrapper.Prewarm(Android.Gms.Dynamic.IObjectWrapper! p0, System.Collections.Generic.IList<Android.OS.Bundle!>! p1, Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpPrewarmServiceCallback! p2) -> void
234+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpPrewarmServiceCallback
235+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpPrewarmServiceCallback.OnError(Android.OS.Bundle! p0) -> void
236+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpPrewarmServiceCallback.OnPrewarmCompleted(Android.OS.Bundle! p0) -> void
237+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpServiceCallback
238+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpServiceCallback.OnDismissed(Android.OS.Bundle! p0) -> void
239+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpServiceCallback.OnError(Android.OS.Bundle! p0) -> void
240+
Google.Android.Gms.Ads.Internal.Client.Hsdp.IHsdpServiceCallback.OnShown(Android.OS.Bundle! p0) -> void
230241
Google.Android.Gms.Ads.Internal.Offline.Buffering.OfflineNotificationPoster
231242
Google.Android.Gms.Ads.Internal.Offline.Buffering.OfflineNotificationPoster.OfflineNotificationPoster(Android.Content.Context! context, AndroidX.Work.WorkerParameters! params) -> void
232243
Google.Android.Gms.Ads.Internal.Offline.Buffering.OfflineNotificationPoster.OfflineNotificationPoster(nint javaReference, Android.Runtime.JniHandleOwnership transfer) -> void
@@ -1375,6 +1386,7 @@ virtual Google.Android.Gms.Ads.AdLoader.IsLoading.get -> bool
13751386
virtual Google.Android.Gms.Ads.AdLoader.LoadAd(Google.Android.Gms.Ads.AdManager.AdManagerAdRequest! adManagerAdRequest) -> void
13761387
virtual Google.Android.Gms.Ads.AdLoader.LoadAd(Google.Android.Gms.Ads.AdRequest! adRequest) -> void
13771388
virtual Google.Android.Gms.Ads.AdLoader.LoadAds(Google.Android.Gms.Ads.AdRequest! adRequest, int maxNumberOfAds) -> void
1389+
virtual Google.Android.Gms.Ads.AdManager.AdManagerInterstitialAdLoadCallback.OnAdLoaded(Google.Android.Gms.Ads.AdManager.AdManagerInterstitialAd! p0) -> void
13781390
virtual Google.Android.Gms.Ads.AdRequest.AdString.get -> string?
13791391
virtual Google.Android.Gms.Ads.AdRequest.Builder.Build() -> Google.Android.Gms.Ads.AdRequest!
13801392
virtual Google.Android.Gms.Ads.AdRequest.Builder.Self() -> Google.Android.Gms.Ads.AdRequest.Builder!
@@ -1387,6 +1399,7 @@ virtual Google.Android.Gms.Ads.AdRequest.Keywords.get -> System.Collections.Gene
13871399
virtual Google.Android.Gms.Ads.AdRequest.NeighboringContentUrls.get -> System.Collections.Generic.IList<string!>!
13881400
virtual Google.Android.Gms.Ads.AdRequest.PlacementId.get -> long
13891401
virtual Google.Android.Gms.Ads.AdRequest.RequestAgent.get -> string!
1402+
virtual Google.Android.Gms.Ads.AppOpen.AppOpenAd.AppOpenAdLoadCallback.OnAdLoaded(Google.Android.Gms.Ads.AppOpen.AppOpenAd! p0) -> void
13901403
virtual Google.Android.Gms.Ads.BaseAdView.AdListener.get -> Google.Android.Gms.Ads.AdListener!
13911404
virtual Google.Android.Gms.Ads.BaseAdView.AdListener.set -> void
13921405
virtual Google.Android.Gms.Ads.BaseAdView.AdSize.get -> Google.Android.Gms.Ads.AdSize?
@@ -1412,6 +1425,7 @@ virtual Google.Android.Gms.Ads.FullScreenContentCallback.OnAdDismissedFullScreen
14121425
virtual Google.Android.Gms.Ads.FullScreenContentCallback.OnAdFailedToShowFullScreenContent(Google.Android.Gms.Ads.AdError! p0) -> void
14131426
virtual Google.Android.Gms.Ads.FullScreenContentCallback.OnAdImpression() -> void
14141427
virtual Google.Android.Gms.Ads.FullScreenContentCallback.OnAdShowedFullScreenContent() -> void
1428+
virtual Google.Android.Gms.Ads.Interstitial.InterstitialAdLoadCallback.OnAdLoaded(Google.Android.Gms.Ads.Interstitial.InterstitialAd! p0) -> void
14151429
virtual Google.Android.Gms.Ads.Mediation.Adapter.LoadAppOpenAd(Google.Android.Gms.Ads.Mediation.MediationAppOpenAdConfiguration! p0, Google.Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
14161430
virtual Google.Android.Gms.Ads.Mediation.Adapter.LoadBannerAd(Google.Android.Gms.Ads.Mediation.MediationBannerAdConfiguration! p0, Google.Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
14171431
virtual Google.Android.Gms.Ads.Mediation.Adapter.LoadInterstitialAd(Google.Android.Gms.Ads.Mediation.MediationInterstitialAdConfiguration! p0, Google.Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
@@ -1503,8 +1517,10 @@ virtual Google.Android.Gms.Ads.RequestConfiguration.TagForChildDirectedTreatment
15031517
virtual Google.Android.Gms.Ads.RequestConfiguration.TagForUnderAgeOfConsent.get -> int
15041518
virtual Google.Android.Gms.Ads.RequestConfiguration.TestDeviceIds.get -> System.Collections.Generic.IList<string!>!
15051519
virtual Google.Android.Gms.Ads.RequestConfiguration.ToBuilder() -> Google.Android.Gms.Ads.RequestConfiguration.Builder!
1520+
virtual Google.Android.Gms.Ads.Rewarded.RewardedAdLoadCallback.OnAdLoaded(Google.Android.Gms.Ads.Rewarded.RewardedAd! p0) -> void
15061521
virtual Google.Android.Gms.Ads.Rewarded.ServerSideVerificationOptions.CustomData.get -> string!
15071522
virtual Google.Android.Gms.Ads.Rewarded.ServerSideVerificationOptions.UserId.get -> string!
1523+
virtual Google.Android.Gms.Ads.RewardedInterstitial.RewardedInterstitialAdLoadCallback.OnAdLoaded(Google.Android.Gms.Ads.RewardedInterstitial.RewardedInterstitialAd! p0) -> void
15081524
virtual Google.Android.Gms.Ads.VersionInfo.MajorVersion.get -> int
15091525
virtual Google.Android.Gms.Ads.VersionInfo.MicroVersion.get -> int
15101526
virtual Google.Android.Gms.Ads.VersionInfo.MinorVersion.get -> int

source/com.google.android.gms/play-services-ads-api/Transforms/Metadata.xml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,63 @@
125125
OnAdFailedToLoadWithErrorCode
126126
</attr>
127127

128+
<!--
129+
Java-generics erasure fix for AdLoadCallback<AdT> subclasses (issue #1491).
130+
131+
The base class:
132+
public abstract class AdLoadCallback<AdT> {
133+
public void onAdLoaded(AdT ad) { }
134+
}
135+
only declares the erased onAdLoaded(Object) in bytecode, so the binding
136+
generator exposes it as `virtual OnAdLoaded(Java.Lang.Object p0)` on every
137+
concrete subclass (AdManagerInterstitialAdLoadCallback,
138+
InterstitialAdLoadCallback, etc.).
139+
140+
When a user overrides that in C#, the generated Java ACW stub emits
141+
`public void onAdLoaded(java.lang.Object p0)`. From javac's point of view
142+
the parent (after generic substitution) declares
143+
`onAdLoaded(AdManagerInterstitialAd)`, and the two methods have the same
144+
erasure but neither overrides the other; javac reports a name-clash and
145+
the app fails to build.
146+
147+
Fix: for each concrete subclass, add a specialized onAdLoaded(SpecificAd)
148+
method via add-node. That surfaces a properly-typed
149+
`virtual OnAdLoaded(SpecificAd p0)` in C# with a specialized JNI
150+
registration, so users' ACW stubs emit the specialized signature that
151+
correctly overrides the parent.
152+
153+
Note: play-services-ads-lite also ships bindings for the same types
154+
(under the Android.Gms.Ads.* namespace); the equivalent fix lives in
155+
that project's Metadata.xml.
156+
-->
157+
<add-node path="/api/package[@name='com.google.android.gms.ads.admanager']/class[@name='AdManagerInterstitialAdLoadCallback']">
158+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/admanager/AdManagerInterstitialAd;)V" jni-return="V">
159+
<parameter name="p0" type="com.google.android.gms.ads.admanager.AdManagerInterstitialAd" not-null="true"></parameter>
160+
</method>
161+
</add-node>
162+
163+
<add-node path="/api/package[@name='com.google.android.gms.ads.interstitial']/class[@name='InterstitialAdLoadCallback']">
164+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/interstitial/InterstitialAd;)V" jni-return="V">
165+
<parameter name="p0" type="com.google.android.gms.ads.interstitial.InterstitialAd" not-null="true"></parameter>
166+
</method>
167+
</add-node>
168+
169+
<add-node path="/api/package[@name='com.google.android.gms.ads.rewarded']/class[@name='RewardedAdLoadCallback']">
170+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/rewarded/RewardedAd;)V" jni-return="V">
171+
<parameter name="p0" type="com.google.android.gms.ads.rewarded.RewardedAd" not-null="true"></parameter>
172+
</method>
173+
</add-node>
174+
175+
<add-node path="/api/package[@name='com.google.android.gms.ads.rewardedinterstitial']/class[@name='RewardedInterstitialAdLoadCallback']">
176+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/rewardedinterstitial/RewardedInterstitialAd;)V" jni-return="V">
177+
<parameter name="p0" type="com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd" not-null="true"></parameter>
178+
</method>
179+
</add-node>
180+
181+
<add-node path="/api/package[@name='com.google.android.gms.ads.appopen']/class[@name='AppOpenAd.AppOpenAdLoadCallback']">
182+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/appopen/AppOpenAd;)V" jni-return="V">
183+
<parameter name="p0" type="com.google.android.gms.ads.appopen.AppOpenAd" not-null="true"></parameter>
184+
</method>
185+
</add-node>
186+
128187
</metadata>

source/com.google.android.gms/play-services-ads-lite/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,7 @@ virtual Android.Gms.Ads.AdLoader.IsLoading.get -> bool
13361336
virtual Android.Gms.Ads.AdLoader.LoadAd(Android.Gms.Ads.AdManager.AdManagerAdRequest! adManagerAdRequest) -> void
13371337
virtual Android.Gms.Ads.AdLoader.LoadAd(Android.Gms.Ads.AdRequest! adRequest) -> void
13381338
virtual Android.Gms.Ads.AdLoader.LoadAds(Android.Gms.Ads.AdRequest! adRequest, int maxNumberOfAds) -> void
1339+
virtual Android.Gms.Ads.AdManager.AdManagerInterstitialAdLoadCallback.OnAdLoaded(Android.Gms.Ads.AdManager.AdManagerInterstitialAd! p0) -> void
13391340
virtual Android.Gms.Ads.AdRequest.AdString.get -> string?
13401341
virtual Android.Gms.Ads.AdRequest.Builder.Build() -> Android.Gms.Ads.AdRequest!
13411342
virtual Android.Gms.Ads.AdRequest.ContentUrl.get -> string!
@@ -1346,6 +1347,7 @@ virtual Android.Gms.Ads.AdRequest.IsTestDevice(Android.Content.Context! context)
13461347
virtual Android.Gms.Ads.AdRequest.Keywords.get -> System.Collections.Generic.ICollection<string!>!
13471348
virtual Android.Gms.Ads.AdRequest.NeighboringContentUrls.get -> System.Collections.Generic.IList<string!>!
13481349
virtual Android.Gms.Ads.AdRequest.RequestAgent.get -> string!
1350+
virtual Android.Gms.Ads.AppOpen.AppOpenAd.AppOpenAdLoadCallback.OnAdLoaded(Android.Gms.Ads.AppOpen.AppOpenAd! p0) -> void
13491351
virtual Android.Gms.Ads.BaseAdView.AdListener.get -> Android.Gms.Ads.AdListener!
13501352
virtual Android.Gms.Ads.BaseAdView.AdListener.set -> void
13511353
virtual Android.Gms.Ads.BaseAdView.AdSize.get -> Android.Gms.Ads.AdSize?
@@ -1369,6 +1371,7 @@ virtual Android.Gms.Ads.FullScreenContentCallback.OnAdDismissedFullScreenContent
13691371
virtual Android.Gms.Ads.FullScreenContentCallback.OnAdFailedToShowFullScreenContent(Android.Gms.Ads.AdError! p0) -> void
13701372
virtual Android.Gms.Ads.FullScreenContentCallback.OnAdImpression() -> void
13711373
virtual Android.Gms.Ads.FullScreenContentCallback.OnAdShowedFullScreenContent() -> void
1374+
virtual Android.Gms.Ads.Interstitial.InterstitialAdLoadCallback.OnAdLoaded(Android.Gms.Ads.Interstitial.InterstitialAd! p0) -> void
13721375
virtual Android.Gms.Ads.Mediation.Adapter.LoadAppOpenAd(Android.Gms.Ads.Mediation.MediationAppOpenAdConfiguration! p0, Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
13731376
virtual Android.Gms.Ads.Mediation.Adapter.LoadBannerAd(Android.Gms.Ads.Mediation.MediationBannerAdConfiguration! p0, Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
13741377
virtual Android.Gms.Ads.Mediation.Adapter.LoadInterstitialAd(Android.Gms.Ads.Mediation.MediationInterstitialAdConfiguration! p0, Android.Gms.Ads.Mediation.IMediationAdLoadCallback! callback) -> void
@@ -1454,8 +1457,10 @@ virtual Android.Gms.Ads.RequestConfiguration.TagForChildDirectedTreatment.get ->
14541457
virtual Android.Gms.Ads.RequestConfiguration.TagForUnderAgeOfConsent.get -> int
14551458
virtual Android.Gms.Ads.RequestConfiguration.TestDeviceIds.get -> System.Collections.Generic.IList<string!>!
14561459
virtual Android.Gms.Ads.RequestConfiguration.ToBuilder() -> Android.Gms.Ads.RequestConfiguration.Builder!
1460+
virtual Android.Gms.Ads.Rewarded.RewardedAdLoadCallback.OnAdLoaded(Android.Gms.Ads.Rewarded.RewardedAd! p0) -> void
14571461
virtual Android.Gms.Ads.Rewarded.ServerSideVerificationOptions.CustomData.get -> string!
14581462
virtual Android.Gms.Ads.Rewarded.ServerSideVerificationOptions.UserId.get -> string!
1463+
virtual Android.Gms.Ads.RewardedInterstitial.RewardedInterstitialAdLoadCallback.OnAdLoaded(Android.Gms.Ads.RewardedInterstitial.RewardedInterstitialAd! p0) -> void
14591464
virtual Android.Gms.Ads.VersionInfo.MajorVersion.get -> int
14601465
virtual Android.Gms.Ads.VersionInfo.MicroVersion.get -> int
14611466
virtual Android.Gms.Ads.VersionInfo.MinorVersion.get -> int

source/com.google.android.gms/play-services-ads-lite/Transforms/Metadata.xml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,62 @@
127127
<parameter name="bundle" type="android.os.Bundle"></parameter>
128128
</method>
129129
</add-node>
130+
131+
<!--
132+
Java-generics erasure fix for AdLoadCallback<AdT> subclasses (issue #1491).
133+
134+
The base class:
135+
public abstract class AdLoadCallback<AdT> {
136+
public void onAdLoaded(AdT ad) { }
137+
}
138+
only declares the erased `onAdLoaded(Object)` in bytecode, so the binding
139+
generator exposes it as `virtual OnAdLoaded(Java.Lang.Object p0)` on every
140+
concrete subclass (AdManagerInterstitialAdLoadCallback, InterstitialAdLoadCallback,
141+
etc.).
142+
143+
When a user overrides that in C#, the generated Java ACW stub emits
144+
`public void onAdLoaded(java.lang.Object p0)`. From javac's point of view
145+
the parent (after generic substitution) declares
146+
`onAdLoaded(AdManagerInterstitialAd)`, and the two methods have the same
147+
erasure but neither overrides the other — javac reports a name-clash and
148+
the app fails to build.
149+
150+
Fix: for each concrete subclass, add a specialized `onAdLoaded(SpecificAd)`
151+
method via <add-node>. That surfaces a properly-typed
152+
`virtual OnAdLoaded(SpecificAd p0)` in C# with a specialized JNI
153+
registration, so users' ACW stubs emit the specialized signature that
154+
correctly overrides the parent. This matches how Google's own docs show
155+
the callback being overridden in Java.
156+
-->
157+
<add-node path="/api/package[@name='com.google.android.gms.ads.admanager']/class[@name='AdManagerInterstitialAdLoadCallback']">
158+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/admanager/AdManagerInterstitialAd;)V" jni-return="V">
159+
<parameter name="p0" type="com.google.android.gms.ads.admanager.AdManagerInterstitialAd" not-null="true"></parameter>
160+
</method>
161+
</add-node>
162+
163+
<add-node path="/api/package[@name='com.google.android.gms.ads.interstitial']/class[@name='InterstitialAdLoadCallback']">
164+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/interstitial/InterstitialAd;)V" jni-return="V">
165+
<parameter name="p0" type="com.google.android.gms.ads.interstitial.InterstitialAd" not-null="true"></parameter>
166+
</method>
167+
</add-node>
168+
169+
<add-node path="/api/package[@name='com.google.android.gms.ads.rewarded']/class[@name='RewardedAdLoadCallback']">
170+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/rewarded/RewardedAd;)V" jni-return="V">
171+
<parameter name="p0" type="com.google.android.gms.ads.rewarded.RewardedAd" not-null="true"></parameter>
172+
</method>
173+
</add-node>
174+
175+
<add-node path="/api/package[@name='com.google.android.gms.ads.rewardedinterstitial']/class[@name='RewardedInterstitialAdLoadCallback']">
176+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/rewardedinterstitial/RewardedInterstitialAd;)V" jni-return="V">
177+
<parameter name="p0" type="com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd" not-null="true"></parameter>
178+
</method>
179+
</add-node>
180+
181+
<add-node path="/api/package[@name='com.google.android.gms.ads.appopen']/class[@name='AppOpenAd.AppOpenAdLoadCallback']">
182+
<method abstract="false" deprecated="not deprecated" final="false" name="onAdLoaded" native="false" return="void" static="false" synchronized="false" visibility="public" bridge="false" synthetic="false" jni-signature="(Lcom/google/android/gms/ads/appopen/AppOpenAd;)V" jni-return="V">
183+
<parameter name="p0" type="com.google.android.gms.ads.appopen.AppOpenAd" not-null="true"></parameter>
184+
</method>
185+
</add-node>
130186

131187

132188
<attr

0 commit comments

Comments
 (0)