Unity开发之使用aar接入SDK

参考链接:https://blog.csdn.net/ZhangDi2017/article/details/65629589
最近负责项目的SDK接入,之前没使用过Android Studio,基本算是从零学起,大部分内容参考自逝水追风的博客,并结合我的实际情况进行了修改、优化,谨以此篇记录所学

开发环境

  1. 系统环境:Mac
  2. 开发软件:Unity 2017.2.0f3 、Android Studio 3.4.1。
  3. 所需类库:UnityPlayer等需要的classes.jar包。Mac中位置:在应用程序中找到unity app 同级目录下的PlaybackEngines文件夹,AndroidPlayer/Variations/mono/Development/Classes/classes.jar

项目构建

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的Gradle模式打包,重名会导致打包失败;而Mininum Required SDK最好选择4.0以上,要不然还需要引入android-support-v7兼容包,而且随后会用到Android 3.0之后才支持的Fragment特性(请先确定Unity支持的最低版本,我的Unity支持的Android版本最低为4.1(API level 16)),最后点击Finish完成创建。
Unity开发之使用aar接入SDK_第1张图片

3

在新的Library创建完成后,需要删除app相关的内容。点击菜单栏File -> Project Structure,在Modules中选中app然后点击上方的-号,选择YES,最后点击OK,稍等一会儿,等待系统编译。
Unity开发之使用aar接入SDK_第2张图片

4

如果不小心点到最上边Modules右边的-,按下图所示重新打开即可
Unity开发之使用aar接入SDK_第3张图片

5

回到Project视图,右键点击app,选择删除。
Unity开发之使用aar接入SDK_第4张图片

6

展开刚创建的Library目录如下图中所示,以后所有的开发操作都会在创建的这个Library下面进行。下面对项目的结构进行一些说明。build/outputs/aar文件下面是构建生产的供Unity使用的aar文件(aar文件和jar文件类似,Unity可以识别,如果没有aar文件,通过Build->Rebuild Project重新编译一下);libs文件夹下面是项目以来的类库,可以说各种SDK的jar等等;最后是src文件夹,这里面存放了AndroidManifest以及源码。这些内容有一些是不需要的,例如一些单元测试的内容,我们删掉测试工程以及res下面的Android自带的资源及配置(白框部分),只保留了AndroidManifest.xml。
Unity开发之使用aar接入SDK_第5张图片

7

接下来是配置AndroidManifest的内容。双击打开AndroidManifest.xml,如果里面有一些红色的内容,那些是因为刚才各种删除导致的,删掉其余不相关的内容,只保留最基础的东西(原文内容,我测试过程中没有出现上述情况)

8

最后就是编写自己的插件或者对接第三方SDK了。首先引入Unity的jar包(Mac中位置:在应用程序中找到unity app 同级目录下的PlaybackEngines文件夹AndroidPlayer/Variations/mono/Development/Classes/classes.jar
Unity开发之使用aar接入SDK_第6张图片
classes.jar拷贝到文件夹里libs文件夹下面,还是点击File -> Project Structure,在左侧选择Dependencies,选择自己创建的插件,先删除的现存的所有依赖库,然后点击+号 ->Jar Dependency添加Unity的jar包,点击OK完成设置。对于第三方SDK的jar包,以同样的方式进行引入。 如果第三方依赖库中有so文件,先不需要导入,稍后将会说明如何添加so文件。如果库文件为 *.jar(Unity的jar包) *.aar(例如支付宝),千万不要这样导入,具体参考补充第2条,这样只需要导入一次而已,不用每开发一个插件,都要导入一次jar包, 并且打出的aar包中不会包括引用库,也就不会引起打包冲突 。到这一步,项目、依赖库都设置完毕。
Unity开发之使用aar接入SDK_第7张图片
Unity开发之使用aar接入SDK_第8张图片

编写代码

创建MyPluginClass类
Unity开发之使用aar接入SDK_第9张图片
不要再继承UnityPlayerActivity了1!具体原因后面的参考资料里给出。首先贴一段Android Studio里的示例代码,这里用一个单例作为这个类访问的入口,在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 = "TestLibrary";
    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;
    }
    //示例方法三:返回拼接字符串
    public String GetPluginString(String str){
        return "Get Plugin Back "+str;
    }
}

在Unity中编写如下示例代码调用插件的三个方法:

using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    public string className = "com.xxx.xxx.MyPluginClass";// 同上面被屏蔽的包名,后面拼接Java类名
    public Text callbackText = null;
    public Text resultText = null;
    public Text resultText1 = null;
    private AndroidJavaObject pluginObject = null;
    // Use this for initialization
    void Start()
    {
#if UNITY_ANDROID 
        pluginObject = new AndroidJavaClass(className).CallStatic<AndroidJavaObject>("GetInstance", gameObject.name);
        pluginObject.Call("SayHello");                                                                               
        resultText.text = pluginObject.Call<int>("CalculateAdd", 22, 33).ToString(); 
        resultText1.text = pluginObject.Call<string>("GetPluginString", "你好"); 
#endif
    }
    public void PluginCallBack(string text)
    {
        callbackText.text = text;
    }
}

两边都编写完成,开始将插件编译导出:选中Android Studio最右侧(默认布局)的Gradle,选中如图所示的选项编译输出,稍等一会儿,在左侧的Project面板可以看到相关的aar文件了
Unity开发之使用aar接入SDK_第10张图片 Unity开发之使用aar接入SDK_第11张图片
这个aar文件就是最终输出给Unity使用的aar包,(如果使用补充第2条的方法打出的aar包则不需要进行下面的解压再压缩操作) 拿到aar包之后,需要进行一项关键的操作,将其后缀改为压缩格式(zip或rar)打开压缩包删除掉libs/下面的classes.jar(原因是Unity在打包的时候会再次拷贝安装目录下的classes.jar到项目中造成冲突,另,ios解压之后不要直接对文件夹压缩,要把文件夹里面的内容打成一个压缩包,再改名,蛋疼)!如果插件使用到了so文件,将对应平台的so文件拷贝至libs下面
错误做法:
Unity开发之使用aar接入SDK_第12张图片
正确做法:
Unity开发之使用aar接入SDK_第13张图片
最后将aar文件后缀改回为aar拷贝至Unity工程中Plugins/Android文件夹下,不再需要AndroidManifest.xml!设置好Platform和Bundle Identifier以及Mininum API Level(和插件保持一致),到真机上测试即可。

我的unity工程打包最后报错,大概错误是版本问题,我把插件中的build.gradle中的compileSdkVersion改为了22,将图示的两行版本注释掉,重新生成aar包,删除libs/classes.jar,再导入unity,打包通过。。。
Unity开发之使用aar接入SDK_第14张图片

真机测试

使用adb命令在手机上安装之后,运行,可以看到测试的三个方法都已经执行成功
Unity开发之使用aar接入SDK_第15张图片

注意事项

  1. UnityPlayer.UnitySendMessage()方法接受三个参数,每一个都不能为null!如果不想填就用string.Empty。
  2. AndroidJavaObject.Call()传参的时候必须严格按照类型传递,如果参数是float却填了一个int类型的也会造成调用失败!
  3. 真机在打开开发者模式后可以用adb logcat -s Unity来获取手机中Unity输出的日志,进而进行定位
  4. 以这种方式开发出的插件可以多个并存,例如将一些常用功能封装成静态类获取电量,wifi状态等,然后和支付宝,暴风魔镜的SDK并存等等。
  5. 快速更改插件的包名,点击齿轮并取消勾选Compact Empty Middle Packages,之后项目的结构中包名会变成三层结构,修改对应的结构(右键->Refactor->Rename…,或者快捷键shift+F6)即可:
    Unity开发之使用aar接入SDK_第16张图片

结语

通过自我摸索、反复测试,终于成功,又学到了新知识,填补了知识盲区。上述内容可能有巧合成分,也可能有错误,欢迎留言斧正

参考资料

  1. 插件中继承Fragment而不是UnityPlayerActivity的原因

补充:

经过几天的学习与踩坑,总结一下:

  1. 在Unity中打包时,如果选择Gradle打包,那么模块的包名不能与Unity包名及其他模块的包名相同,在Java脚本开头package字段和AndroidManifest中修改包名(或者修改Unity)
    Unity开发之使用aar接入SDK_第17张图片
  2. 在将其他aar包作为依赖时(在接入支付宝时遇到这个问题,如果将aar导入libs文件夹下,编译没问题,打出包运行就崩溃,说找不到相关的包),千万不要将.aar包导入libs文件夹当库文件,正确的做法是:
    1,先像添加Module一样导入aar包,只不过module类型选择.jar/.aar
    Unity开发之使用aar接入SDK_第18张图片
    2,还是打开File -> Project Structure,选择工作模块,将新添加的库模块作为依赖项
    Unity开发之使用aar接入SDK_第19张图片Unity开发之使用aar接入SDK_第20张图片
    然后就是开发项目工程需要的Java代码了,最后按前面的方法打包出来,可以发现,并没有依赖的库文件,干干净净,将这个aar导入Unity工程,同时,将依赖的.aar文件和.jar文件 (导入Android studio前的文件,除了Unity的classes.jar) 也放在一起。
    !Unity开发之使用aar接入SDK_第21张图片Unity开发之使用aar接入SDK_第22张图片
    使用Gradle打包,在手机上跑,支付宝正常运行,取消支付后也有反馈(反馈是项目的服务器返回的消息,非支付宝反馈)
    Unity开发之使用aar接入SDK_第23张图片Unity开发之使用aar接入SDK_第24张图片

  1. 不要再继承UnityPlayerActivity的原因 ↩︎

你可能感兴趣的:(Unity)