Unity接入多个SDK的通用接口开发与资源管理(二)
接着上篇,本篇对SDK接口进行封装。在开始之前,需要先了解下面知识。
(1)unity与android之间的交互
unity通过下面方式调用android中的函数:
方法一:
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer"); AndroidJavaObject _mActivity = jc.GetStatic<AndroidJavaObject>("currentActivity"); _mActivity.Call("函数名");
方法二:
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");//括号里可以是任意jar包的包名+类名 jc.CallStatic("函数名");
上面代码第一种先获得UnityPlayer类,UnityPlayer类是unity导出Android工程后生成的unity-classes.jar里的类。然后再获取静态变量_mActivity,_mActivity 是Activity类型,由此获得了Android当前的Activity,然后再调用此Activity中的方法。我们可以看一下unity自动生成的classes.jar中的源码:
第二种是通过包名+类名获取该类,直接调用类中的静态方法来实现的。可以是任意自定义的包名和类名。但这种就与Android的生命周期无关了。
我们可以这么理解Android应用中一个界面是一个Activity,两个界面的跳转就是两个Activity之间的跳转(类似的iOS是UIController之间的跳转)。其实我们unity游戏在Android上也是一个Android应用,所以它也是运行在一个Activity上的,这个Activity叫UnityPlayerActivity,它继承自Activity,看源码如下,每个Activity初始化的时候会首先执行onCreate()方法,所以通常把SDK的初始化函数也放在这个函数中。它就会随着Android的生命周期进行初始化,这是第一种做法,也是最常用的SDK初始化方法。还有一种SDK初始化的方法,就是自己新建一个jar包,在jar包中新建类,在类中写一些SDK初始化的静态方法,然后通过方法二在unity中调用这些方法进行初始化。我们这里采用大多数人使用的方法一,即在onCreate()中初始化。
有了上面的了解,我们开始进行unity的通用接口的开发。我们需要一个SDKManager类来管理所有调用SDK接口的方法,代码如下,把脚本挂在一个空物体上。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class SDKManager : MonoBehaviour { private static SDKManager _instance = null; public static SDKManager Instance { get { return _instance; } } private void Awake() { if (_instance != null) { GameObject.Destroy(this.gameObject); } _instance = this; InitSDKManager(); DontDestroyOnLoad(this); } private void OnDestroy() { if (_instance == this) { _instance = null; } } #if UNITY_ANDROID && !UNITY_EDITOR private static string UNITY_CLASS = "com.unity3d.player.UnityPlayer"; private AndroidJavaObject _mActivity; #endif public void InitSDKManager() { #if UNITY_ANDROID && !UNITY_EDITOR AndroidJavaClass jc = new AndroidJavaClass (UNITY_CLASS); _mActivity = jc.GetStatic<AndroidJavaObject>("currentActivity"); #endif } //信鸽SDK接口 public void GetPushToken() { #if UNITY_ANDROID && !UNITY_EDITOR _pushToken = _mActivity.Call<string>("GetXGPushTokenNew"); #endif } public void SetXGPushTag(string tag) { #if UNITY_ANDROID && !UNITY_EDITOR _mActivity.Call("SetXGPushTag",tag); #endif } public void AddLocalPushNotificationAndroid(string content, DateTime date, bool isRepeatEveryday = false) { #if UNITY_ANDROID && !UNITY_EDITOR int isRepeat = 0; if (isRepeatEveryday == true) { isRepeat = 1; } _mActivity.Call("AddLocalNotification","SDK集合",content, date.ToString("yyyyMMdd"), date.ToString("HH"), date.ToString("mm"),isRepeat); #endif } public void ClearAllLocalNotificationAndroid() { #if UNITY_ANDROID && !UNITY_EDITOR _mActivity.Call("ClearAllLocalNotification"); #endif } //buglySDK接口 //启动c#异常捕获上报功能 public void buglyCatch() { Debug.Log("start Bugly report"); BuglyAgent.EnableExceptionHandler(); } }
然后新建一个Test脚本挂在摄像机上,调用这些接口:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class Test : MonoBehaviour { void OnGUI() { if (GUILayout.Button("信鸽推送", GUILayout.Width(100.0f), GUILayout.Height(50.0f))) { DateTime noticeTime = new DateTime(2017, 11, 24, 21, 30, 30); SDKManager.Instance.AddLocalPushNotificationAndroid("信鸽给你的推送", noticeTime); } if (GUILayout.Button("清除本地推送", GUILayout.Width(100.0f), GUILayout.Height(50.0f))) { SDKManager.Instance.ClearAllLocalNotificationAndroid(); } if (GUILayout.Button("开启Bugly异常上报", GUILayout.Width(100.0f), GUILayout.Height(50.0f))) { SDKManager.Instance.buglyCatch(); } } }
上面代码,我们新建一个SDKManaget单例类,把每个SDK的接口封装成一个函数。像信鸽这种原生的jar包中的方法,我们就用_mActivity.Call()去调用,像bugly这种提供了接口的,我们直接调用提供的接口。通用接口类就介绍到这里,下面我们来实现_mActivity.Call()中调用的Android工程里的方法。使用Android Studio(2.3.3)新建一个工程。我们的目的是做一个jar包,这个jar包作用有两点:(1)用来对接unity调用jar包里的方法。(2)对接unity导出的Android工程的生命周期。这是我们为什么选择上面第一种接入方法的原因。上面说过unity运行的Activity是UnityPlayerActivity,我们新建一个类MainActivity,继承com.unity3d.player.UnityPlayerNativeActivity,而UnityPlayerNativeActivity继承UnityPlayerActivity。然后在AndroidManifest.xml里设置MainActivity为启动的Activity,所以MainActivity就是当前unity运行的Activity。我们通过_mActivity = jc.GetStatic<AndroidJavaObject>("currentActivity")获取到的就是MainActivity,然后我们在MainActivity中实现被unity调用的函数。代码:
public class MainActivity extends com.unity3d.player.UnityPlayerNativeActivity { private static boolean _isXGRegisterSuccess = false; private static String _pushToken = ""; @Override protected void onCreate(Bundle savedInstanceState) { if (savedInstanceState == null) { savedInstanceState = new Bundle(); } super.onCreate(savedInstanceState); Log.d("myGame", "MainActivity onCreate Called"); InitBugly(); InitXG(); } void InitBugly() { CrashReport.initCrashReport(getApplicationContext(),"aaaaaaaa",false); } void InitXG(){ XGPushConfig.enableDebug(this,false); MsgReceiver testReceiver = new MsgReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.abc.def.receiveintent"); registerReceiver(testReceiver,intentFilter); XGPushManager.registerPush(this, new XGIOperateCallback() { @Override public void onSuccess(Object o, int i) { Log.w("XGPush","XGsuccess:"+o); _isXGRegisterSuccess = true; _pushToken = o.toString(); } @Override public void onFail(Object o, int i, String s) { _isXGRegisterSuccess = false; Log.w("XGPush","failed:"+i+", msg:"+s); } }); } public void AddLocalNotification(String title, String content, String date, String hour, String min, int isRepeatEveryday) { if (_isXGRegisterSuccess) { XGLocalMessage msg = new XGLocalMessage(); msg.setTitle(title); msg.setContent(content); msg.setDate(date); msg.setHour(hour); msg.setMin(min); int notifyIconId = getResources().getIdentifier("notify_icon", "drawable", getPackageName()); Log.e("notify icon id",notifyIconId+""); msg.setSmall_icon(Integer.toString(notifyIconId)); int _hour = Integer.parseInt(hour); int _min = Integer.parseInt(min); msg.setRing(1); XGPushManager.addLocalNotification(MainActivity.this,msg); } } public void ClearAllLocalNotification() { Log.w("ClearAllLocalNotice","success"); if (_isXGRegisterSuccess) { XGPushManager.clearLocalNotifications(MainActivity.this); } } }
如果需要在启动unity的Activity(即MainActivity)前做一些处理,你可以新建一个类SplashActivity继承Activity,设置SplashActivity为启动Activity,然后跳转到MainActivity。就可以在SplashActivity中做一些启动游戏前的处理。我们把上述工作做完后,就可以将这些类打包成一个jar包(AS如何打jar包,再说),导入unity导出的Android工程中就可以了。到这里通用接口的开发就完了。还剩下一项工作就是我们之前从unity中提取出来的SDK资源,我们需要添加到Android工程中,下面就介绍如何进行资源管理,把资源添加到unity导出的Android工程中。
注:
AS打jar包,在build.gradle最后加这些代码:
task makeJar(type: Jar, dependsOn:['build']){ archiveName = 'QuicksdkDemo.jar' //包名 from('build/intermediates/classes/debug/') destinationDir = file('build/libs') //导出路径 exclude('com/taiyouxi/a3k/BuildConfig.class') //不打进包的文件 exclude('com/taiyouxi/a3k/BuildConfig\$*.class') //不打进包的文件 exclude('**/R.class') //不打进包的文件 exclude('**/R\$*.class') //不打进包的文件 include('com/taiyouxi/a3k/*.class') //需要打进包的文件 include('com/quicksdk/unity/*.class') //需要打进包的文件 include('com/weibo/*.class') //需要打进包的文件 include('com/wxapi/*.class') //需要打进包的文件 } makeJar.dependsOn(build)
然后打开Terminal窗口,输入gradlew makeJar然后回车:
gradlew makeJar
打出的包在build>libs文件夹下如图:
原文地址:https://www.cnblogs.com/gangtie/p/12731891.html
- “奇幻熊”(APT28)组织最新攻击
- GDB调试CVE-2018-5711 PHP-GD拒绝服务漏洞
- 高效与争议并存:大规模自动化渗透工具AutoSploit
- Android应用测试速查表
- ADB配置提权漏洞(CVE-2017-13212)原理与利用分析
- Fuzz自动化Bypass软WAF姿势
- Web黑盒渗透思路之猜想
- ZZCMS v8.2 最新版SQL注入漏洞
- 一款轻量级Web漏洞教学演示系统(DSVW)
- 使用Burpsuite代理和pypcap抓包进行抢红包的尝试
- 基于WAVSEP的靶场搭建指南
- 【干货】大数据量下,58同城mysql实践!
- 如何预先处理电影评论数据以进行情感分析
- 如何在Python中从零开始实现随机森林
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Solidity 0.6.11 更新
- 潘石屹用Python解决100个问题 | 最小公倍数
- 通过CREATE2获得合约地址:解决交易所充值账号问题
- 小知识:如何判定crontab任务的执行频度
- 以太坊合约静态分析工具Slither简介与使用
- Cesium第一次搭建环境出不来地球的问题
- 小知识:解决EXP-00003的报错
- Mysql5中Packet for query is too large (3396053 > 1048576),数据量太大解决方案
- 关于 servlet 的这个问题,你能答对吗?
- MYSQL数据优化常用配置参数
- Hadoop分块存储解析及还原分块存储的文件
- ValueError: too many values to unpack (expected 2)
- VMware15更新后克隆Centos7发现网卡起不来了
- 基于SSH的医院在线挂号
- Linux-远程拷贝(scp命令)