Android sdk工程搭建(aar)
Unity 和 Android 交互流程
AndroidJavaClass:
public AndroidJavaClass(string className); // className:指定类名
java.lang.Class
的通用实例的统一表示,是java
里的类。
AndroidJavaObject:
- 生成一个对象,通过对象去调用里面的方法和属性
// 加载 com.unity3d.player.UnityPlayer 类
AndroidJavaClass ajc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
// 调用 com.unity3d.player.UnityPlayer 类中的 静态方法
ajc.CallStatic("Test");
ajc.CallStatic("Test","Hello"); // 带参数的静态方法
int sum = ajc.CallStatic<int>("Sum", 1, 2); // 带参数和返回值的静态方法
// 实例化 com.unity3d.player.UnityPlayer 对象
AndroidJavaObject ajo = new AndroidJavaObject("com.unity3d.player.UnityPlayer");
// 调用 com.unity3d.player.UnityPlayer 类中的 实例方法
ajo.Call("Test");
ajo.Call("Test","Hello");
int sum = ajo.Call<int>("Sum", 1, 2);
classes.jar
Unity
发布Android
的APK
时,会使用Android
的SDK
构建,发布出来的APK
只包含一个Activity
,俗称MainActivity
。在发布过程中,Unity
会引入内置的Jar
库(classes.jar
),里面包含了Unity
需要的库类,关键类UnityPlayerActivity
就是Android
程序的主要入口类,也就是MainActivity
。
aar 和 jar的区别
jar
:只包含了class
文件与清单文件
,不包含资源文件,如图片等所有res
中的文件aar
:包含所有资源,class
以及res
资源文件。
AndroidManifest
Unity
发布Android
的APK时,如果在Plugins/Android
目录下不存在AndroidManifest
文件,会使用Unity默认的AndroidManifest
文件。
默认的AndroidManifest
文件目录:Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk
如果存在AndroidManifest
文件,Unity
会使用它代替默认的AndroidManifest
文件,这个AndroidManifest
文件必须带有活动
以及标签
。
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
发布APK的两种方式
Internal
:不需要签名,仅需Android SDK
支持,不能导出工程。Gradle
:需要签名,需要Android SDK
与Gradle
支持,可以导出Android Studio
工程,使用与需要与Android
功能交互的项目。
Unity接入SDK两种方法
- 将
Unity
在安卓平台选中Gradle
打包出来,然后在Android Studio
导入需要的SDK
进行操作。 - 将
Unity
的classes.jar
包和需要的SDK
导入Android Studio
新建的Library
中,然后导出jar
或者aar
放到Unity
中调用。
具体操作流程
-
创建一个
Android Studio
项目,视图切换到Project
。 -
首先修改
app - build.gradle
文件。 -
将第一行,
application
改为library
,这样就可以发布aar
包 -
删掉
applicationId
那一行
// apply plugin: 'com.android.application'
apply plugin: 'com.android.library' // 不生成apk,生成aar包。
android {
compileSdkVersion 28 // sdk版本
buildToolsVersion "30.0.3"
defaultConfig {
// applicationId "com.td.sdktest" 注释这一行
minSdkVersion 15 // 最低sdk版本
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation files('libs/classes.jar') //添加unity classes.jar 添加依赖自动生成
}
-
点击
工具栏 - Build - MakeProject
测试是否可以发布aar
包。 -
完成之后,可以看到在
app - build - outputs - aar
文件夹下已经生成app-debug.aar
-
复制
Unity
的classes.jar
到AndroidStudio
Unity
和Android
没法直接通信,需要classes.jar
搭桥牵线。classes.jar
由Unity
提供。将
Unity
安装目录下的 classes.jar 复制到Android
项目的libs
文件夹下,右键点击Add As Library
添加依赖。implementation files('libs/classes.jar')
目录:
Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
-
修改
MainActivity.java
以便unity
调用
package com.example.unityaar;
import android.os.Bundle;
import android.widget.Toast;
import java.text.SimpleDateFormat;
// 复制过来的 unity_classes.jar
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
// 修改类 继承 UnityPlayerActivity
public class MainActivity extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main) // 注释掉,不需要界面
}
// 写交互函数
// 供unity调用的普通函数,弹toast
public void ShowAndroidToast(String str){
Toast.makeText(this,str,Toast.LENGTH_SHORT).show();
}
// unity调用的静态方法,然后再调用unity函数
// UnityPlayer.UnitySendMessage(String,String,params)
// 参数1:unity中一个GameObject名字。参数2:改GameObject脚本中的一个方法。参数3:改方法参数
public static void GetSystemTime(){
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String timeStr = sDateFormat.format(new java.util.Date());
UnityPlayer.UnitySendMessage("Canvas","GetDate", timeStr);
}
// 供unity调用的普通方法,带返回值
public String GetDate(){
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String timeStr = sDateFormat.format(new java.util.Date());
return timeStr;
}
}
-
不需要
Android
界面,删除app - src - main - res - layout
文件夹 -
不需要
Android
界面,删除app - src - main - res - values - styles.xml
文件 -
修改
AndroidManife
文件android:theme
修改成安卓自带的主题@android:style/Theme.NoTitleBar
android:name="com.example.unityaar.MainActivity"
- 再添加
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
,否则发布的apk是无法运行的
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.unityaar"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@android:style/Theme.NoTitleBar"> <activity android:name="com.example.unityaar.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="unityplayer.UnityActivity" android:value="true"/> </application> </manifest>
-
Build - Make Project
,生成新的aar
包 -
将
Android
导出的aar
和AndroidManifest
复制到unity
项目Plugins/Android
目录下。- 删除
aar
压缩包lib文件下的unity_classes.jar
,否则会有冲突,打包不成功
- 删除
-
编写
Unity
脚本,调用Android
接口。using UnityEngine; using UnityEngine.UI; public class UnityAndroidAar : MonoBehaviour { public Text timeTxt; public InputField inputField; public Text timeBtnStr; private AndroidJavaClass javaClass; private AndroidJavaObject javaObject; private void Start() { // 获取 Unity 导出的 Activity 对象,固定写法,UnityPlayerActivity 里面对其进行了处理 javaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); // Unity 要导出的 MainActivity 类 javaObject = javaClass.GetStatic<AndroidJavaObject>("currentActivity"); // 获取 MainActivity 的实例对象 } private void Update() { // 调用 Java 类中的普通方法 javaObject.CallStatic("GetSystemTime"); } // Android 调用 unity 方法 public void GetDate(string timeStr) { timeTxt.text = timeStr; } public void OnClickGetTimeBtn() { // 调用 Java 类中的普通方法 ,带返回值 timeBtnStr.text = javaObject.Call<string>("GetDate"); } public void OnClickThostBtn() { // 调用 Java 类中的普通方法,带参数,不带返回值 string inputValue = inputField.text; javaObject.Call("ShowAndroidToast",inputValue); } }
-
打包发布
APK
,unity
切换到Android
平台。Build
。安装APK
,运行游戏检测。
遇到的坑:
- 直接运行
Unity
,报错。
解决:需要运行在安卓真机设备上。如果需要调试:
#if UNITY_ANDROID && !UNITY_EDITOR
// 报错的调用代码写这里
#endif
- 打包报错:
解决:与unity
中的classes.jar
冲突,打开aar
包,删除lib文件夹下的classe.jar
文件,重新导入unity
-
当导出apk时,可能遇到下面的问题:
Unable to find unity activity in manifest. You need to make sure orientation attribute is set to fullSensor manually.
需在AndroidManifest中, 主 Activity的之前增加一行:<meta-data android:name="unityplayer.UnityActivity" android:value="true" />