如何在 Xamarin.Android 中实现 RewardedAdLoadCallback?

Posted

技术标签:

【中文标题】如何在 Xamarin.Android 中实现 RewardedAdLoadCallback?【英文标题】:How can I implement RewardedAdLoadCallback in Xamarin.Android? 【发布时间】:2021-05-19 19:01:02 【问题描述】:

我正在尝试用 C# 在 Xamarin.android 中实现奖励广告。

Android 文档中的代码 sn-ps 是用 Java 编写的,通常我在 C# 中采用该代码并没有太大问题,但现在看来确实是个问题。

要在 Java 中加载 RewardedAd,您必须执行以下操作 (according to the official documentation):

AdRequest adRequest = new AdRequest.Builder().build();

RewardedAd.load(this, "ca-app-pub-3940256099942544/5224354917",
      adRequest, new RewardedAdLoadCallback()
        @Override
        public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) 
          // Handle the error.
          Log.d(TAG, loadAdError.getMessage());
          mRewardedAd = null
        

        @Override
        public void onAdLoaded(@NonNull RewardedAd rewardedAd) 
          mRewardedAd = rewardedAd;
          Log.d(TAG, "onAdFailedToLoad");
        
    );

现在这里的问题是,在这段代码中传递的对象RewardedAdLoadCallback,还定义了方法实现(onAdFailedToLoadonAdLoaded),而在 C# 中这是无法做到的。

所以我的解决方案是创建自己的类MyRewardedAdLoadCallback,并覆盖方法。

public class MyRewardedAdLoadCallback : RewardedAdLoadCallback

    public override void OnAdLoaded(Java.Lang.Object p0)
    
        base.OnAdLoaded(p0);
    

    public override void OnAdFailedToLoad(LoadAdError p0)
    
        base.OnAdFailedToLoad(p0);
    

然后我只需使用以下代码加载奖励广告:

AdRequest adRequest = new AdRequest.Builder().Build();

RewardedAd.Load(this, "ca-app-pub-3940256099942544/5224354917", adRequest, new MyRewardedAdLoadCallback());

现在由于一些奇怪的原因,我在构建项目时遇到了这个错误:

error: name ***: onAdLoaded(Object) in MyRewardedAdLoadCallback and onAdLoaded(AdT) in AdLoadCallback have the same erasure, yet neither overrides the other
    public void onAdLoaded (java.lang.Object p0)
  where AdT is a type-variable:
    AdT extends Object declared in class AdLoadCallback

我尝试在互联网上搜索此错误并得出结论,这是一个 Java 错误并且与泛型类型有关(请参阅this SO 问题)。但是,我在我的代码和关于奖励广告的 Android 文档中都没有看到任何通用类型。关于我正在尝试实施的奖励广告的 Xamarin 文档也为零。

如果有人能帮我解决这个问题,我会非常高兴。提前致谢。

【问题讨论】:

您是否尝试覆盖 OnRewardedAdLoadedOnRewardedAdFailedToLoadmethod ? @LeoZhu-MSFT 覆盖这两种方法完全可以正常工作,但自 SDK 版本 19.7.0 起已弃用,因此我不想使用它们。 乍一看没有意义。 onAdLoaded( Object )onAdLoaded( AdT ) 不应该有相同的擦除。话虽如此,onAdLoaded( Object ) 不应该能够覆盖onAdLoaded( Object )因为 擦除不一样。这可能是您的错误的根源。 @Koenigsberg 这确实是重点。另一个奇怪的事情是,在 Xamarin 中,我必须重写 OnAdLoaded(Java.Lang.Object),但在 Android 文档 (here) 中,只有一个名称为 onAdLoaded 的方法,它有一个类型为 @987654341 的参数@ (没有任何文档)。那么为什么我无法使用这个方法呢? @Maximus 听起来很糟糕。在我在之前的评论中发送的 Github 链接中,有一条带有非官方解决方案的评论 (link)。不过自己没试过。 【参考方案1】:

这是让插页式广告和奖励广告在 Xamarin.GooglePlayServices.Ads 版本 120.0.0 中运行的技巧。

将以下文件添加到您的项目(需要使用 unsafe 标志构建)并使用 Android.Gms.Ads.Hack 命名空间来加载您的广告和子类化回调。

例如,InterstitialAd.Load 变为 global::Android.Gms.Ads.Hack.InterstitialAd.LoadInterstitialAdLoadCallback 变为 global::Android.Gms.Ads.Hack.InterstitialAdLoadCallback

回调类分别将OnInterstitialAdLoaded()OnRewardedAdLoaded() 虚拟方法添加到插页式广告加载回调和奖励广告加载回调中。

using System;
using System.ComponentModel;
using System.Diagnostics;
using Android.Content;
using Android.Runtime;
using Java.Interop;

namespace Android.Gms.Ads.Hack

    public abstract class InterstitialAd : Java.Lang.Object
    
        private static readonly JniPeerMembers _members = new XAPeerMembers("com/google/android/gms/ads/interstitial/InterstitialAd", typeof(InterstitialAd));

        public unsafe static void Load(Context context, string adUnit, AdRequest request, AdLoadCallback callback)
        
            IntPtr intPtr = JNIEnv.NewString(adUnit);
            try
            
                JniArgumentValue* ptr = stackalloc JniArgumentValue[4];
                *ptr = new JniArgumentValue(context?.Handle ?? IntPtr.Zero);
                ptr[1] = new JniArgumentValue(intPtr);
                ptr[2] = new JniArgumentValue(request?.Handle ?? IntPtr.Zero);
                ptr[3] = new JniArgumentValue(callback?.Handle ?? IntPtr.Zero);
                _members.StaticMethods.InvokeVoidMethod("load.(Landroid/content/Context;Ljava/lang/String;Lcom/google/android/gms/ads/AdRequest;Lcom/google/android/gms/ads/interstitial/InterstitialAdLoadCallback;)V", ptr);
            
            finally
            
                JNIEnv.DeleteLocalRef(intPtr);
                GC.KeepAlive(context);
                GC.KeepAlive(request);
                GC.KeepAlive(callback);
            
        
    

    [Register("com/google/android/gms/ads/interstitial/InterstitialAdLoadCallback", DoNotGenerateAcw = true)]
    public abstract class InterstitialAdLoadCallback : AdLoadCallback
    
        private static readonly JniPeerMembers _members = new XAPeerMembers("com/google/android/gms/ads/interstitial/InterstitialAdLoadCallback", typeof(InterstitialAdLoadCallback));

        static IntPtr class_ref => _members.JniPeerType.PeerReference.Handle;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override JniPeerMembers JniPeerMembers => _members;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override IntPtr ThresholdClass => _members.JniPeerType.PeerReference.Handle;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override Type ThresholdType => _members.ManagedPeerType;

        protected InterstitialAdLoadCallback(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        
        

        [Register(".ctor", "()V", "")]
        public unsafe InterstitialAdLoadCallback()
            : base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
        
            if (!(base.Handle != IntPtr.Zero))
            
                SetHandle(_members.InstanceMethods.StartCreateInstance("()V", GetType(), null).Handle, JniHandleOwnership.TransferLocalRef);
                _members.InstanceMethods.FinishCreateInstance("()V", this, null);
            
        

        private static Delegate cb_onAdLoaded;

        private static Delegate GetOnAdLoadedHandler()
        
            if (cb_onAdLoaded is null)
            
                cb_onAdLoaded = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr>)n_onAdLoaded);
            

            return cb_onAdLoaded;
        

        private static void n_onAdLoaded(IntPtr jnienv, IntPtr native__this, IntPtr native_p0)
        
            InterstitialAdLoadCallback? @object = Java.Lang.Object.GetObject<InterstitialAdLoadCallback>(jnienv, native__this, JniHandleOwnership.DoNotTransfer);
            global::Android.Gms.Ads.Interstitial.InterstitialAd object2 = Java.Lang.Object.GetObject<global::Android.Gms.Ads.Interstitial.InterstitialAd>(native_p0, JniHandleOwnership.DoNotTransfer);
            @object!.OnInterstitialAdLoaded(object2);
        

        [Register("onAdLoaded", "(Lcom/google/android/gms/ads/interstitial/InterstitialAd;)V", "GetOnAdLoadedHandler")]
        public virtual void OnInterstitialAdLoaded(global::Android.Gms.Ads.Interstitial.InterstitialAd interstitialAd)
        
        
    

    public abstract class RewardedAd : Java.Lang.Object
    
        private static readonly JniPeerMembers _members = new XAPeerMembers("com/google/android/gms/ads/rewarded/RewardedAd", typeof(RewardedAd));

        public unsafe static void Load(Context context, string adUnit, AdRequest request, RewardedAdLoadCallback callback)
        
            IntPtr intPtr = JNIEnv.NewString(adUnit);
            try
            
                JniArgumentValue* ptr = stackalloc JniArgumentValue[4];
                *ptr = new JniArgumentValue(context?.Handle ?? IntPtr.Zero);
                ptr[1] = new JniArgumentValue(intPtr);
                ptr[2] = new JniArgumentValue(request?.Handle ?? IntPtr.Zero);
                ptr[3] = new JniArgumentValue(callback?.Handle ?? IntPtr.Zero);
                _members.StaticMethods.InvokeVoidMethod("load.(Landroid/content/Context;Ljava/lang/String;Lcom/google/android/gms/ads/AdRequest;Lcom/google/android/gms/ads/rewarded/RewardedAdLoadCallback;)V", ptr);
            
            finally
            
                JNIEnv.DeleteLocalRef(intPtr);
                GC.KeepAlive(context);
                GC.KeepAlive(request);
                GC.KeepAlive(callback);
            
        
    

    [Register("com/google/android/gms/ads/rewarded/RewardedAdLoadCallback", DoNotGenerateAcw = true)]
    public abstract class RewardedAdLoadCallback : AdLoadCallback
    
        private static readonly JniPeerMembers _members = new XAPeerMembers("com/google/android/gms/ads/rewarded/RewardedAdLoadCallback", typeof(RewardedAdLoadCallback));

        static IntPtr class_ref => _members.JniPeerType.PeerReference.Handle;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override JniPeerMembers JniPeerMembers => _members;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override IntPtr ThresholdClass => _members.JniPeerType.PeerReference.Handle;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected override Type ThresholdType => _members.ManagedPeerType;

        protected RewardedAdLoadCallback(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        
        

        [Register(".ctor", "()V", "")]
        public unsafe RewardedAdLoadCallback()
            : base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
        
            if (!(base.Handle != IntPtr.Zero))
            
                SetHandle(_members.InstanceMethods.StartCreateInstance("()V", GetType(), null).Handle, JniHandleOwnership.TransferLocalRef);
                _members.InstanceMethods.FinishCreateInstance("()V", this, null);
            
        

        private static Delegate cb_onAdLoaded;

        private static Delegate GetOnAdLoadedHandler()
        
            if (cb_onAdLoaded is null)
            
                cb_onAdLoaded = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr>)n_onAdLoaded);
            

            return cb_onAdLoaded;
        

        private static void n_onAdLoaded(IntPtr jnienv, IntPtr native__this, IntPtr native_p0)
        
            RewardedAdLoadCallback? @object = Java.Lang.Object.GetObject<RewardedAdLoadCallback>(jnienv, native__this, JniHandleOwnership.DoNotTransfer);
            global::Android.Gms.Ads.Rewarded.RewardedAd object2 = Java.Lang.Object.GetObject<global::Android.Gms.Ads.Rewarded.RewardedAd>(native_p0, JniHandleOwnership.DoNotTransfer);
            @object!.OnRewardedAdLoaded(object2);
        

        [Register("onAdLoaded", "(Lcom/google/android/gms/ads/rewarded/RewardedAd;)V", "GetOnAdLoadedHandler")]
        public virtual void OnRewardedAdLoaded(global::Android.Gms.Ads.Rewarded.RewardedAd rewardedAd)
        
        
    

【讨论】:

【参考方案2】:
public abstract class InterstitialCallback : Android.Gms.Ads.Interstitial.InterstitialAdLoadCallback

    [Register("onAdLoaded", "(Lcom/google/android/gms/ads/interstitial/InterstitialAd;)V", "GetOnAdLoadedHandler")]
    public virtual void OnAdLoaded(Android.Gms.Ads.Interstitial.InterstitialAd interstitialAd)
    
    

    private static Delegate cb_onAdLoaded;
    private static Delegate GetOnAdLoadedHandler()
    
        if (cb_onAdLoaded is null)
            cb_onAdLoaded = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr>)n_onAdLoaded);
        return cb_onAdLoaded;
    
    private static void n_onAdLoaded(IntPtr jnienv, IntPtr native__this, IntPtr native_p0)
    
        InterstitialCallback thisobject = GetObject<InterstitialCallback>(jnienv, native__this, JniHandleOwnership.DoNotTransfer);
        Android.Gms.Ads.Interstitial.InterstitialAd resultobject = GetObject<Android.Gms.Ads.Interstitial.InterstitialAd>(native_p0, JniHandleOwnership.DoNotTransfer);
        thisobject.OnAdLoaded(resultobject);
    

public abstract class RewardedAdLoadCallback : Android.Gms.Ads.Rewarded.RewardedAdLoadCallback

    [Register("onAdLoaded", "(Lcom/google/android/gms/ads/rewarded/RewardedAd;)V", "GetOnAdLoadedHandler")]
    public virtual void OnAdLoaded(Android.Gms.Ads.Rewarded.RewardedAd rewardedAd)
    
    

    private static Delegate cb_onAdLoaded;
    private static Delegate GetOnAdLoadedHandler()
    
        if (cb_onAdLoaded is null)
        
            cb_onAdLoaded = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr>)n_onAdLoaded);
        

        return cb_onAdLoaded;
    
    private static void n_onAdLoaded(IntPtr jnienv, IntPtr native__this, IntPtr native_p0)
    
        RewardedAdLoadCallback thisobject = GetObject<RewardedAdLoadCallback>(jnienv, native__this, JniHandleOwnership.DoNotTransfer);
        Android.Gms.Ads.Rewarded.RewardedAd resultobject = GetObject<Android.Gms.Ads.Rewarded.RewardedAd>(native_p0, JniHandleOwnership.DoNotTransfer);
        thisobject.OnAdLoaded(resultobject);
    

【讨论】:

【参考方案3】:

也许只是子类化回调

class RewardedVideoAds : RewardedAdLoadCallback
    
        private RewardedAd rewardedAd;

        
        public RewardedVideoAds()
        
            
            AdRequest adRequest = new AdRequest.Builder().Build();
           
            RewardedAd.Load(MainActivity.Current, "ca-app-pub-3940256099942544/5224354917", adRequest, this);
        
        public override void OnAdFailedToLoad(LoadAdError p0)
        
            base.OnAdFailedToLoad(p0);
        
        public override void OnAdLoaded(Java.Lang.Object p0)
        
            base.OnAdLoaded(p0);
        
    

【讨论】:

以上是关于如何在 Xamarin.Android 中实现 RewardedAdLoadCallback?的主要内容,如果未能解决你的问题,请参考以下文章

GCM 推送通知不适用于 xamarin android

如何使用 Xamarin Android 在 Edit Text 上实现 TextWatcher 接口?

OnTokenRefresh 从未在 Xamarin Android 中调用

如何在 R 中实现保留验证

Google Play 服务 - 位置 Xamarin Android

如何将变量传递给已经在 R 的参数中实现非标准评估的函数?