AndroidStudio3.4+Unity2018.3,导出JAR包给UNITY使用
环境 Android studio 3.4 + unity2018.3
1,android studio 新建空工程,一切默认,完成。
这个空工程只是个壳,它的所有参数都没什么用,它存在的意义是为了后面能创建 module。
因为JAVA不像C++,可以直接创建类库。
2,新建模块
file->new module->android library
application name 和 module name 都不重要,没有实际用处(这里取名mylibrary),重要的是包名: package name。
这里取名为 com.x.y
包名用到哪些地方?
(1,AndroidManifest.xml里的 package
(2,每个java文件的开始处,形如 package com.x.y,表示此java文件被放入了工程的com/x/y目录下
(3,unity 的build Settings里的 package name
这三处必须使用同一个包名,如果不一致则启动时闪退。如果想修改包名,就要修改这三处就行了。
3,在mylibrary模块下的src/java/com.x.y/添加java文件,随便取名,就叫MainActivity吧
修改其源码如下:
package com.x.y; import android.content.Intent; import com.unity3d.player.UnityPlayerActivity; import android.app.Activity; import android.os.Bundle; public class MainActivity extends UnityPlayerActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); activity = this; } //public static MainActivity activity; public static MainActivity activity; public int Calc(int x, int y){ return x + y; } public static float Calcf(float x, float y){ return x + y; } public void restartApplication() { new Thread(){ public void run(){ Intent launch=getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); launch.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(launch); android.os.Process.killProcess(android.os.Process.myPid()); } }.start(); finish(); } }
这个类的目的:
(1,测试普通成员函数和静态函数的调用
(2,测试重启功能
4,修改mylibary模块的AndroidManifest.xml,这一步放在最后也行,此文件是拿给UNITY用的,内容如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x.y"> <application android:allowBackup="true" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
注意一定要有下面两行
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
学过安卓开发的都知道这是标记此活动是主活动,没有主活动的应用是不会被运行的。
默认情况下UNITY会创建自己AndroidManifest.xml,一旦我们在Assets/Plugins/Android/下放置了我们自定的AndroidManifest.xml,
UNITY就以我们的配置为主,并将buildsettings里的相关配置合并进来,如安装位置,持久化路径等。
因此,如果我们生成了自己的AndroidManifest.xml,却又不配置为主活动,安装后桌面没有图标,因为它不是一个可执行程序。
5,修改mylibrary模块的 build.gradle(注意不是修改工程的),为编译做准备,在末尾添加:
task exportJar(type: Copy) { //必须先删除旧的包,否则新包不会生成,这个目录对应mylibrary/build/libs/AndroidUtils.jar delete 'build/libs/AndroidUtils.jar' //生成的目录在这里 from('build/intermediates/packaged-classes/release/') //生成build/libs目录,并将build/intermediates/packaged-classes/release/下的classes.jar复制到此目录 into('build/libs/') //指定我们只在build/intermediates/packaged-classes/release/下寻找classes.jar(放入到build/libs/目录 include('classes.jar') //重命名下,起个个性的名字,不要与别人混淆 rename('classes.jar', 'AndroidUtils.jar') } //这里会触发真正对mylibaray的编译 exportJar.dependsOn(build)
然后点击工具栏上的 run anything: ,或双击ctrl,在弹出的输入窗口中输入 gradlew exprotJar,回车,等待编译完成。
如果没问题,会提示 BUILD SUCCESSFUL
如果出了错,仔细看前面的输出LOG。
这里的注意点:
(1,from('build/intermediates/packaged-classes/release/') 这里的路径在不同版本的 Android Studio中不同。
在低版本的AS中路径为 build/intermediates/bundles/release
如果编译中报错 exportJar: NO-SOURCE,就说明是此路径错误了,这时就去磁盘上的build/intermediates/目录搜索classes.jar文件,
找到它的路径,写入到from里就对了。
6,生成完成后,得到我们的AndroidUtils.jar包,新建UNITY工程,package name取名:com.x.y
在Assets下新建如下目录 Plugins/Android,然后将AndroidManifest.xml放入到此目录下,然后在创建 Plugins/Android/libs目录,
将AndroidUtils.jar放入此目录。
注意这里的目录结构要求:AndroidManifest.xml必须与libs同目录,AndroidUtils.jar必须在libs目录中,名字不能错。
但libs和XML不一定直接在Android下,可以是多层目录下,如:Android/abc/libs也可以
7,添加脚本,随便挂在什么上,如相机上,测试代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class calljava : MonoBehaviour { AndroidJavaObject jo; Text info; void Start() { //方式一,使用基类,这种比较通用 var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); info = GameObject.Find("TextInfo").GetComponent<Text>(); info.text += "start \n"; //方式二,使用具体类,不通用,当类名改了就要改这里的字符串 //var jc = new AndroidJavaClass("com.example.mylibraryx.MainActivity"); //jo = jc.GetStatic<AndroidJavaObject>("activity"); info.text += "get java object " + (jo == null ? "null\n" : "ok\n"); //var btn = GetComponent<Button>(); //btn.onClick.AddListener(() => //{ if (jo != null) { //注意1,参数类型必须传对,否则运行到这里就出错了 var ret = jo.Call<int>("Calc", 10, 20); info.text += "call ret : " + ret + " \n"; //调用静态函数 var retf = jo.CallStatic<float>("Calcf", (float)10.2, (float)20.2); info.text += "call retf : " + retf + " \n"; //注意2,由于Calcf是个静态函数,非静态调用会造成参数错位,结果为retfx = 10.2 var retfx = jo.Call<float>("Calcf", (float)10.2, (float)20.2); info.text += "call retfx : " + retfx + " \n"; } //}); } // Update is called once per frame void Update() { } }
8,打包APK,到安卓上运行。在UNITY上运行会出错,提示jo为空.