您的位置:首页 > 移动开发 > Unity3D

Unity Android平台下插件/SDK开发通用流程

2017-09-19 15:14 609 查看
本文主要面向对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等一堆东西,删掉其余不相关的内容后如下所示,可以看到内容非常精简,只保留了最基础的东西:

[html] view
plain copy

<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一下:

[java] view
plain copy

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);  // 这一句很重要,保存对该Fragment的引用,防止在旋转屏幕等操作时时丢失引用(Fragment隶属于Activity)  

    }  

    //示例方法一:简单的向Unity回调    

    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中编写如下示例代码调用插件的两个方法:

[csharp] view
plain copy

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,之后项目的结构中包名会变成三层结构,修改对应的结构即可:


 
       



参考资料

1.关于插件中继承Fragment而不是UnityPlayerActivity的原因:Unity
Android plugin tutorial 。
2.关于Android Fragment的资料:Fragment
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: