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方面收到这个函数指针过后也可以不直接调用,放到全局变量里面,随时可以调用。