本文主要面向对Android开发不甚了解的Unity开发者,介绍了基于最新的Android Studio的标准Android开发环境与项目结构的配置流程,在此基础上,开发者可以快速的进行SDK的接入与插件的开发。
目前国内各大博客上搜到的文章内容基本上都是相互抄来抄去,比如说先是清一色的继承UnityPlayerActivity,然后再配置AndroidManifest文件等等,这些确实有效果,但是具有很大的局限性。例如,如果项目中如果存在两个Android插件或SDK会怎么样?都继承UnityPlayerActivity显然是不行的,启动入口Activity只能有一个,AndroidManifest文件没法这样配置。笔者最近在做毕设,帮同学接了若干个Android下的SDK,包括支付宝,科大讯飞以及二维码扫描的SDK,参考一些国外的优秀博客以及自己的实践,总结出一套SDK接入与插件开发的通用流程,在这里分享给大家。
开发环境
1.开发软件:笔者使用的开发软件是Unity 5.4.3f 和Android Studio 2.3。
2.所需类库:UnityPlayer等需要的classes.jar包。在 Unity支持Android下IL2CPP后,UnityPlayer相关的这个jar包位置由原来的`Editor\Data\PlaybackEngines\AndroidPlayer\bin`变成了`Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono(or il2cpp)\Release\Classes`,选择jar包时需要注意选择对应Backend的版本。
项目构建
1.启动Android Studio新建一个Project,会弹出创建工程向导,这里可以
随意填写
Package Name和
Mininum SDK,最后让选择的
Activity类型也可以随意。因为我们并不会用到现在创建的这个项目,我们只是在其结构上再创建一个Library作为我们的Plugin。这里值得注意的是,根据你填写的
Company domain和
Application name生成的
Package name总是小写的,点击右侧的Edit按钮可以对其进行修改。
2.创建项目点击Finish后进入编辑器界面,空无一物,点击左侧的
Project,然后切换至
Project视图,如图下图左所示。随后在项目名称上点击右键选择
New -> Module来创建一个新的模块,这时新的创建向导会启动,选择
Android Library类型,随后输入包名的配置与
Mininum SDK,注意这里的
Package Name需要和Unity项目中的
Bundle Identifier保持一致(包括大小写),保持一致的原因是Unity在最后打包时会将所有插件里的
AndroidManifest.XML进行合并,如果包名不一致就会出错;而
Mininum SDK这里需要在
Android 3.0(API 11)以上,因为随后会用到Android 3.0之后才支持的
Fragment特性,最后点击Finish完成创建,项目结构应该如下图右所示,红框部分是新创建的Library。
3.在新的Library创建完成后,需要删除
app相关的内容。点击菜单栏
File -> Project Structure,选中左侧的
app然后点击上方的`
-`号,最后点击OK,稍等一会儿,Gradle Build会完成构建(可以注意到每次进行一次大的操作如增删,Android Studio都会编译一下项目,所以构建的时候请坐和放宽)。回到Project视图,右键点击app,选择删除。展开Library目录如下图中所示,以后所有的开发操作都会在创建的这个Library下面进行。下面对项目的结构进行一些说明。
build/outputs/aar/文件下面是构建生产的供Unity使用的aar文件(aar文件和jar文件类似,Unity可以识别);
libs文件夹下面是项目以来的类库,可以说各种SDK的jar等等;最后是
src文件夹,这里面存放了AndroidManifest以及源码。这些内容有一些是不需要的,例如一些单元测试的内容,我们删掉测试工程以及res下面的Android自带的资源及配置,最后的项目结构如下图右所示,只保留了AndroidManifest.xml。
4.接下来是配置AndroidManifest的内容。双击打开AndroidManifest.xml,里面有一些红色的内容,那些是因为刚才各种删除导致的,这里不再需要常规的插入UnityPlayer等一堆东西,删掉其余不相关的内容后如下所示,可以看到内容非常精简,只保留了最基础的东西:
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.soulgame.myplugin">
- <application android:allowBackup="true" android:supportsRtl="true"></application>
- </manifest>
5.最后就是编写我们的插件或者对接第三方SDK了。首先引入Unity的jar包,将
classes.jar拷贝到文件夹里
libs文件夹下面,通用点击
File -> Project Structure,在左侧选择我们的插件,然后在上方选择
Dependencies,先删除的现存的所有依赖库,然后点击`
+`号 ->
Jar Dependency添加Unity的jar包,点击OK完成设置,稍等一会儿就完成了构建。对于第三方SDK的jar包,以同样的方式进行引入。
如果第三方依赖库中有so文件,先不需要导入,稍后将会说明如何添加so文件。到这一步,项目、依赖库都设置完毕。
编写代码
不要再继承
UnityPlayerActivity了!具体原因会在后面的参考资料里给出。首先贴一段Android Studio里的示例代码,创建一个MyPluginClass类,这里简单的用到了一个static的Instance作为这个类访问的入口(类似单例),在Unity中只需要拿到Instance进行操作即可,里面涉及到一些Android原生的Fragment的操作,具体含义可以Google一下:
- package com.soulgame.myplugin;
-
- import android.app.Fragment;
- import android.os.Bundle;
-
- import com.unity3d.player.UnityPlayer;
-
- public class MyPluginClass extends Fragment
- {
- private static final String TAG = "MyPlugin";
- private static MyPluginClass Instance = null;
- private String gameObjectName;
-
- public static MyPluginClass GetInstance(String gameObject)
- {
- if(Instance == null)
- {
- Instance = new MyPluginClass();
- Instance.gameObjectName = gameObject;
- UnityPlayer.currentActivity.getFragmentManager().beginTransaction().add(Instance, TAG).commit();
- }
- return Instance;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setRetainInstance(true);
- }
-
- public void SayHello()
- {
- UnityPlayer.UnitySendMessage(gameObjectName,"PluginCallBack","Hello Unity!");
- }
-
- public int CalculateAdd(int one, int another)
- {
- return one + another;
- }
- }
编写完成,将插件编译导出,选中Android Studio右侧的Gradle,选中如图所示的选项编译输出,稍等一会儿,在左侧的Project面板可以看到相关的aar文件了,这个aar文件就是最终输出给Unity使用的aar包,拿到aar包之后,需要进行一项关键的操作,将其后缀改为压缩格式(zip或rar)打开
压缩包删除掉libs/下面的classes.jar(原因是Unity在打包的时候会再次拷贝安装目录下的classes.jar到项目中造成冲突)!如果插件使用到了so文件,
将对应平台的so文件拷贝至libs下面,如下图右所示:
最后将aar文件后缀改回为aar拷贝至Unity工程中Plugins/Android文件夹下,
不再需要AndroidManifest.xml!
在Unity中编写如下示例代码调用插件的两个方法:
- using UnityEngine;
- using UnityEngine.UI;
- using System.Collections;
-
- public class PluginManager : MonoBehaviour
- {
- public string className = "com.soulgame.myplugin.MyPluginClass";
- public Text callbackText = null;
- public Text resultText = null;
- private AndroidJavaObject pluginObject = null;
-
- void Start()
- {
- #if UNITY_ANDROID && !UNITY_EDITOR
- pluginObject = new AndroidJavaClass(className).CallStatic<AndroidJavaObject>("GetInstance", gameObject.name);
- pluginObject.Call("SayHello");
- resultText.text = pluginObject.Call<int>("CalculateAdd", 22, 33).ToString();
- #endif
- }
-
- public void PluginCallBack(string text)
- {
- callbackText.text = text;
- }
- }
编写完成后,设置好Platform和Bundle Identifier以及Mininum API Level(和插件保持一致),到真机上测试即可。
注意事项
1.UnityPlayer.UnitySendMessage()方法接受三个参数,每一个都不能为null!如果不想填就用string.Empty。
2.AndroidJavaObject.Call()传参的时候必须严格按照类型传递,如果参数是float却填了一个int类型的也会造成调用失败!
3.真机在打开开发者模式后可以用adb logcat -s Unity来获取手机中Unity输出的日志,进而进行定位(adb需要在环境变量里配置好),如下图所示的日志就说明找不到插件类里对应的参数(笔者在操作的时候忘记填参数了):
4.以这种方式开发出的插件可以多个并存,例如将一些常用功能封装成静态类获取电量,wifi状态等,然后和支付宝,暴风魔镜的SDK并存等等。
5.快速更改插件的包名,点击齿轮并取消勾选Compact Empty Middle Packages,之后项目的结构中包名会变成三层结构,修改对应的结构即可:
参考资料