Unity Android 交互 三 多个Module分别生成 arr 导入Unity自动合并AndroidManifest.xml
系列篇三
其他篇幅
Unity Android 交互
Unity Android 交互 三 多个 Module分别生成 aar 导入Unity自动合并 AndroidManifest.xml
Unity 接入 Android SDK - 讯飞SDK 实战
简单介绍了如何使用 Android Studio 生成 arr 完成 Unity Android 交互
本篇为了实现自己的一些构思,加深对 Android Studio一些特性使用
问题:假如有多个 SDK 接入,或者 使用 Android 一些原生功能支持(获取Wifi 状态、蜂窝数据、系统语言等),需要接入多种不同功能,不想把所有的 SDK 都写在一个工程中(不便于扩展、维护、和删减),而是想每个SDK 或者 功能对应一个 Module。
如何调用
方案一:创建一个主 Module,最终 主 Module 依赖 其他需要的 Module,在 主Module 中写分别调用其他Module的方法,在Unity中只需要通过 主Module 中的方法来调用其他Module中功能方法, 最终将用到的 Module 每个生成自己的 aar 统一放到Unity工程 Plugins/Android 文件夹下,供Unity 使用
方案二:将用到的Module每个生成自己的 aar 统一放到Unity工程 Plugins/Android 文件夹下,供Unity 分别使用
上述实现好处:模块化,维护方便,维护时只需要修改相应的Module,其他模块不会受到任何影响。添加新功能,也不需要担心把现有功能弄坏,需要删除一个功能时只需要把依赖和它对应的几个调用方法关闭,操作简单。
修改、删除等最头疼的就是 AndroidManifest.xml 中一些配置,如果所有功能都在一个Module中完成,每种 SDK 基本都有配置需求,最终 AndroidManifest.xml 中将会有很多各种配置,当添加、删除一个SDK 的时候需要添加、删除该SDK 的配置,坑就在这里。
我想通过上面思路实现每个 SDK 都是一个Module,每个 Module 中都有自己的AndroidManifest.xml,在自己的 AndroidManifest.xml 配置自己SDK 的权限等。最终每个Module 生成一个 .aar, .aar 中包含有自己的 AndroidManifest.xml,我将所有的 .aar 放在Unity中,打包APK 的时候让Unity帮助我去合并所有的 AndroidManifest.xml。
通过测试,上述思路可行。
1.
Plugins/Android 文件夹没有 AndroidManifest.xml, 则打包 APK 的时候 Unity 会将自己带的默认 AndroidManifest.xml 打到 APK 包中,则我们自己的 多个 AndroidManifest.xml就无法合并丢失了
2.
Plugins/Android 有 文件夹AndroidManifest.xml,并且Plugins/Android 文件夹下还有其他的 .aar , Unity 会过滤所有的 .aar 将每个 .aar 中的 AndroidManifest.xml 配置内容合并到 Plugins/Android 文件夹下的AndroidManifest.xml 打包到 APK 中,这样多个 AndroidManifest.xml 就成功合并不影响 APK 运行了。
说了一大通废话,开始实际操作
以方案一,有一个 主 Module 为例来实现
考虑到会有那么些 SDK 会用到 Android 生命周期等,所以我索性创建一个MainActivity 继承于 UnityPlayerActivity 作为 主Module,也作为 主Activity 入口
创建生成好后将无用资源、依赖、配置等都统统删除,不知道操作的请看 Unity Android 交互
只剩下核心
添加 Unity 自带 classes.jar 库等操作不知道的看前两篇,这里不说了
修改 MainActivity.java 继承 UnityPlayerActivity
package com.SDKTest.Demo;
import android.os.Bundle;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
public class MainActivity extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
配置 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.SDKTest.Demo">
<application
android:allowBackup="true"
android:supportsRtl="true"
>
<activity android:name="com.SDKTest.Demo.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
<!--> 词句一定要加 <-->
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
</activity>
</application>
</manifest>
主 Module 就写好了。
创建一个新 Module
新Module 有两个功能,加法计算、减法计算,就按照功能下面就叫 Calculation Module 了
new -> Module
创建一个 Android Library
同样将无用资源、依赖、配置统统删除
然后 选择 包文件夹,new -> JavaClass 创建一个Java 类
如下
CalculationClass.java 代码如下
package com.calculation.demo;
public class CalculationClass {
private static CalculationClass Instance = null;
public static CalculationClass GetInstance()
{
if (Instance == null)
{
Instance = new CalculationClass();
}
return Instance;
}
// 计算两个数相加
public int add(final int number1, final int number2)
{
return number1 + number2;
}
// 计算两个数相减
public int sub(final int number1, final int number2)
{
return number1 - number2;
}
}
上面提到了要合并多个 AndroidManifest.xml, 现在Calculation Module 中的 AndroidManifest.xml 中只是一个最简配置,到时候合并没有也看不出来
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.calculation.demo">
</manifest>
随便向 Calculation Module 的 AndroidManifest.xml 加一些权限申请
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.calculation.demo">
<!--> 下面都是随便加的用来测试的 <-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>
Calculation Module 准备就绪,在主 Module 中 MainActivity.java 中添加对 Calculation Module 的引用
修改 如下
package com.SDKTest.Demo;
import android.os.Bundle;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
import com.calculation.demo.CalculationClass;
//import com.xunfen.demo.*;
public class MainActivity extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public int add(final int number1, final int number2)
{
return number1 + number2;
}
public int calculationAdd(final int number1, final int number2)
{
//调用 Calculation Module 中 CalculationClass 类
CalculationClass calculationClass = CalculationClass.GetInstance();
return calculationClass.add(number1, number2);
}
}
现在可以执行生成 aar 了, Build -> Build APK 或者 Build -> Rebuild Project
在文件夹中找到 app-debug.aar, calculation-debug.aar
删除 app-debug.aar 中的 Unity classes.jar
将 app-debug.aar 中的 AndroidManifest.xml 复制出来
将 app-debug.aar、 AndroidManifest.xml 和 calculation-debug.aar 放到Unity工程 Plugins/Android 下
现在 Plugins/Android 下的 AndroidManifest.xml 为从 app-debug.aar 中复制出来的
创建 C#测试代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestXunFei : MonoBehaviour {
public Text text;
public Button buttonA;
public Button buttonB;
// Use this for initialization
void Start () {
buttonA.onClick.AddListener(StartSpeaking);
buttonB.onClick.AddListener(AddNumber);
}
private void StartSpeaking()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) // Android 的 Java 接口
{
using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))
{
int result = jo.Call<int>("add", 100, 200);
ShowText(result.ToString());
}
}
}
private void AddNumber()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) // Android 的 Java 接口
{
using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))
{
int result = jo.Call<int>("calculationAdd", 1003, 200);
ShowText(result.ToString());
}
}
}
private void ShowText(string _str)
{
text.text = _str;
}
}
Unity 打包 APK,将APK 安装到模拟器上测试
点击 Add 按钮,显示 300 测试成功
点击 AddNumber 按钮,显示 1203 测试成功
下面开始验证 AndroidManifest.xml 是否合并了
直接解压 APK 发现 打开 AndroidManifest.xml 是乱码,没办法只能找一个反编译工具了
反编译成功
目录如下
打开 AndroidManifest.xml
源码附上
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.SDKTest.Demo" platformBuildVersionCode="27" platformBuildVersionName="8.1.0">
<application android:allowBackup="true" android:banner="@drawable/app_banner" android:debuggable="false" android:isGame="true" android:supportsRtl="true">
<activity android:configChanges="locale|fontScale|keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" android:launchMode="singleTask" android:name="com.SDKTest.Demo.MainActivity" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
</activity>
</application>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false"/>
</manifest>
两个 AndroidManifest.xml 中不相同的内容已经合并到 APK 中的 AndroidManifest.xml 了,并且游泳的部分都被保留了,运行测试成功
发现 <activity
中还多了很多配置
<activity android:configChanges="locale|fontScale|keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode" android:launchMode="singleTask" android:name="com.SDKTest.Demo.MainActivity" android:screenOrientation="landscape">
这是Unity自己加入的
坑很多,经过测试 把所有的 aar 都放在 Plugins/Android 下就行了,如果多个 aar 有相对路径的问题,则会有找不到依赖的 aar, 导致执行失败。测试不多,如果谁有更多测试和结果请告知
遇到的一些 BUG
1.APK 打包成功,运行直接闪退,建议查看 AndroidManifest.xml 配置是否有错误, AndroidManifest.xml 不会自己检查错误(坑)
2.测试不将 app-debug.aar 中的 AndroidManifest.xml 放在 Plugins/Android 下,可以正常打出 APK 包,安装到模拟器上蛋疼的出现了两个同名的应用程序
更蛋疼的是测试了一下,两个都能启动,一个调用 Android SDK 失败,要给调用成功
- AndroidStudio 中Module 生成 aar 的时候不会将该 Module 依赖的 aar 或者 依赖的其他 Module一起打包,AndroidStudio 的机制如此不是BUG,所以如果 aar 有依赖其他的等等吧,一定要将依赖的库复制到 Unity中一份,否则就会出现无法找到依赖库各种蛋疼崩溃
4.Unity 的坑,每次添加替换 aar 或者 AndroidManifest.xml 的时候最好 执行以下 Reimport 一下
我替换了 aar 在 Unity 中是显示替换了,但是实际上Unity 并没有执行更新,然后打包 APK 结果其实是将上次更新的 aar 或者 AndroidManifest.xml 来打包的。结果就是,如果有一次是错误、闪退等,后边不管怎么改都会有连续 N 次同样的错误,有时候上次还是错误的 APK 包,但是下次什么都不改直接打 APK ,竟然没有错误了 (Unity 不知道什么时候偷偷的 更新了一下资源)