Unity与Android和IOS的事件回调

发布于 2022-08-13


Unity与Android的事件回调

AndroidJavaProxy

Unity找到Android所设定的接口,然后通过AndroidJavaProxy在C#中写一个回调类继承这个接口,并且重载里面的方法,然后声明一个这个回调类的对象,给Android Java传过去,然后在Java虚拟机里面运行的时候就是自己重定义的函数逻辑了。

例:广告加载

在Android端定义好广告加载回调接口

package cn.weli.supersdk.ad.callback;

public interface IRewardedAdLoadCallback {
    void onRewardVideoLoadFail(int errorCode, String errorMsg, String waterfallInfo);
    void onRewardVideoAdLoad(String waterfallInfo, String requestId);
    void onRewardVideoCached();
}

以GroMore的广告回调为例,实现了GroMore的广告加载接口,然后在对应的回调中加入自定义的回调,以供Unity使用。

package cn.weli.supersdk.ad.callback;

import android.util.Log;

import androidx.annotation.NonNull;

import com.bytedance.msdk.api.AdError;
import com.bytedance.msdk.api.GMAdEcpmInfo;
import com.bytedance.msdk.api.v2.ad.reward.GMRewardAd;

import java.util.List;

import cn.weli.supersdk.AppConstant;

public class GMRewardedAdLoadCallback implements com.bytedance.msdk.api.v2.ad.reward.GMRewardedAdLoadCallback{
    private String TAG = AppConstant.LOGTAG;
    private GMRewardAd _rewardAd;
    private IRewardedAdLoadCallback _rewardedAdListener;

    public GMRewardedAdLoadCallback(GMRewardAd rewardAd, IRewardedAdLoadCallback rewardedAdListener)
    {
        _rewardAd = rewardAd;
        _rewardedAdListener = rewardedAdListener;
    }

    @Override
    public void onRewardVideoLoadFail(@NonNull AdError adError) {
        String adInfo = "";
        if (_rewardAd != null)
        {
            adInfo = _rewardAd.getAdLoadInfoList().toString();
            _rewardAd.destroy();
        }
        int code = 0;
        String msg = "";
        if(adError != null)
        {
            code = adError.code;
            msg = adError.message;
        }
        _rewardedAdListener.onRewardVideoLoadFail(code, msg, adInfo);
    }

    @Override
    public void onRewardVideoAdLoad() {
        // 获取本次waterfall加载中,加载失败的adn错误信息。
        String adInfo = "";
        String requstId = "";
        if (_rewardAd != null)
        {
            adInfo = _rewardAd.getAdLoadInfoList().toString();
            if (_rewardAd.getShowEcpm() != null)
            {
                requstId = _rewardAd.getShowEcpm().getRequestId();
            }
        }
        _rewardedAdListener.onRewardVideoAdLoad(adInfo, requstId);
        printLoadAdInfo();
        printSHowAdInfo();
    }

    @Override
    public void onRewardVideoCached() {
        _rewardedAdListener.onRewardVideoCached();
        printLoadAdInfo();
        printSHowAdInfo();
    }

    //打印已经加载广告的信息
    public void printLoadAdInfo() {
        if (_rewardAd == null) {
            return;
        }
        /**
         * 获取已经加载的clientBidding ,多阶底价广告的相关信息
         */
        List<GMAdEcpmInfo> gmAdEcpmInfos = _rewardAd.getMultiBiddingEcpm();
        if (gmAdEcpmInfos != null) {
            for (GMAdEcpmInfo info : gmAdEcpmInfos) {
                Log.e(TAG, "***多阶+client相关信息*** AdNetworkPlatformId" + info.getAdNetworkPlatformId()
                        + "  AdNetworkRitId:" + info.getAdNetworkRitId()
                        + "  ReqBiddingType:" + info.getReqBiddingType()
                        + "  PreEcpm:" + info.getPreEcpm()
                        + "  LevelTag:" + info.getLevelTag()
                        + "  ErrorMsg:" + info.getErrorMsg()
                        + "  request_id:" + info.getRequestId());
            }
        }

        /**
         * 获取实时填充/缓存池中价格最优的代码位信息即相关价格信息,每次只有一个信息
         */
        GMAdEcpmInfo gmAdEcpmInfo = _rewardAd.getBestEcpm();
        if (gmAdEcpmInfo != null) {
            Log.e(TAG, "***实时填充/缓存池中价格最优的代码位信息*** AdNetworkPlatformId" + gmAdEcpmInfo.getAdNetworkPlatformId()
                    + "  AdNetworkRitId:" + gmAdEcpmInfo.getAdNetworkRitId()
                    + "  ReqBiddingType:" + gmAdEcpmInfo.getReqBiddingType()
                    + "  PreEcpm:" + gmAdEcpmInfo.getPreEcpm()
                    + "  LevelTag:" + gmAdEcpmInfo.getLevelTag()
                    + "  ErrorMsg:" + gmAdEcpmInfo.getErrorMsg()
                    + "  request_id:" + gmAdEcpmInfo.getRequestId());
        }

        /**
         * 获取获取当前缓存池的全部信息
         */
        List<GMAdEcpmInfo> gmCacheInfos = _rewardAd.getCacheList();
        if (gmCacheInfos != null) {
            for (GMAdEcpmInfo info : gmCacheInfos) {
                Log.e(TAG, "***缓存池的全部信息*** AdNetworkPlatformId" + info.getAdNetworkPlatformId()
                        + "  AdNetworkRitId:" + info.getAdNetworkRitId()
                        + "  ReqBiddingType:" + info.getReqBiddingType()
                        + "  PreEcpm:" + info.getPreEcpm()
                        + "  LevelTag:" + info.getLevelTag()
                        + "  ErrorMsg:" + info.getErrorMsg()
                        + "  request_id:" + info.getRequestId());
            }
        }
    }

    public void printSHowAdInfo() {
        if (_rewardAd == null) {
            return;
        }

        GMAdEcpmInfo gmAdEcpmInfo = _rewardAd.getShowEcpm();
        if (gmAdEcpmInfo == null) {
            return;
        }
        Log.e(TAG, "展示的广告信息 : adNetworkPlatformName: " + gmAdEcpmInfo.getAdNetworkPlatformName() + "   adNetworkRitId:" + gmAdEcpmInfo.getAdNetworkRitId() + "   preEcpm: " + gmAdEcpmInfo.getPreEcpm() + "   reqBiddingType: " + gmAdEcpmInfo.getReqBiddingType());
    }
}

随后在Android中AdMgr.java中写好初始化接口的方法

public void LoadRewarded(final String unitId, int orientation, IRewardedAdLoadCallback lis)
    {
        _rewardedAd.LoadRewardedAd(unitId, orientation, lis);
    }

    public void LoadRewardedServerJudge(final String unitId, int orientation, IRewardedAdLoadCallback lis, String extraInfo)
    {
        _rewardedAd.LoadRewardedAdServerJudge(unitId, orientation, lis, extraInfo);
    }

在Unity中,通过AndroidJavaProxy实现Android中的IRewardedAdLoadCallback接口

#region rewarded load listener

        private sealed class GMRewardedAdLoadCallback : AndroidJavaProxy
        {
            private readonly IRewardedAdLoadCallback listener;

            public GMRewardedAdLoadCallback(IRewardedAdLoadCallback listener)
                : base("cn.weli.supersdk.ad.callback.IRewardedAdLoadCallback")
            {
                this.listener = listener;
            }

            public void onRewardVideoLoadFail(int errorCode, string errorMsg, string waterfallInfo)
            {
                AppBoot.Updater.ExecuteUpdateAction(() => this.listener?.OnRewardVideoLoadFail(errorCode, errorMsg, waterfallInfo));
            }

            public void onRewardVideoAdLoad(string waterfallInfo, string requestId)
            {
                AppBoot.Updater.ExecuteUpdateAction(() => this.listener?.OnRewardVideoAdLoad(waterfallInfo, requestId));
            }

            public void onRewardVideoCached()
            {
                AppBoot.Updater.ExecuteUpdateAction(() => this.listener?.OnRewardVideoCached());
            }
        }

        public interface IRewardedAdLoadCallback
        {
            void OnRewardVideoLoadFail(int errorCode, string errorMsg, string waterfallInfo);
            void OnRewardVideoAdLoad(string waterfallInfo, string requestId);
            void OnRewardVideoCached();
        }

#endregion

并在合适的时候,Unity调用AdMgr.java中的LoadRewardedServerJudge函数,实现Unity监听Android中的事件回调

public void LoadRewardAd_Gromore(AdSlotEnum adSlot, Action success = null, Action fail = null)
        {
            //Log.Error($"LoadRewardAd_Gromore");
            IsRewardAdReady = false;
            string unitId = GetSlotId(adSlot);
            var customBannerListener = new RewardedAdLoadCallback(fail, null, () => { IsRewardAdReady = true; success?.Invoke(); });
            var androidListener = new GMRewardedAdLoadCallback(customBannerListener);
            string extraInfo = string.Empty;
            extraInfo += "{";
            extraInfo += "app_key:";
            extraInfo += Weli.WeliNetEarnConfig.Instance.GetAppId();
            extraInfo += ",ver_code:";
            extraInfo += AppConfig.Instance.VersionCode.ToString();
            extraInfo += ",uid:";
            extraInfo += AppBoot.DataRecord.GetString("uid");
            extraInfo += "}";
            extraInfo = Encrypt.DESEnCode(extraInfo, "weli0420");
  					//此处初始化Android中的回调
            AdMgr_Android.Call("LoadRewardedServerJudge", unitId, 1, androidListener, extraInfo);
        }

Unity与IOS的事件回调

MonoPInvokeCallback

这个属性对静态函数有效,它被Mono的超前编译器用来生成必要的代码,以支持本地调用回到托管代码中。

在常规的ECMA CIL程序中,这种情况会自动发生,不需要特别标记什么,但在纯超前编译中,编译器需要知道哪些方法将从非托管代码中调用。

在当前版本的Xamarin.iOS中,只有静态函数可以从非托管代码中被回调。

你必须指定该代码将被调用的委托的类型。下面的例子显示了使用这种情况的场景。

例子:

Sample.mm

extern "C" {
    // C#函数的函数指针
    typedef void (*cs_callback)(int);

    void sampleMethod4(cs_callback callback) {
        callback(9);
    }
}

Sample.cs

using System.Runtime.InteropServices;
using AOT;

public class Sample {
    delegate void callback_delegate(int val);

    [DllImport("__Internal")]
    private static extern void sampleMethod4(callback_delegate callback);

    //回调函数,必须MonoPInvokeCallback并且是static
    [MonoPInvokeCallback(typeof(callback_delegate))]
    private static void cs_callback(int val) {
        UnityEngine.Debug.Log ("cs_callback : " + val);
    }

    private static void sampleMethod4Invoker() {
        //直接把函数传过去
        sampleMethod4 (cs_callback);
    }
}

C#的静态方法,作为一个函数指针发给Objective-C。Objective-C方面收到这个函数指针过后也可以不直接调用,放到全局变量里面,随时可以调用。