Unity实现自主apk安装

First Post:

Last Update:

Word Count:
1.6k

Read Time:
6 min

Unity3d实现apk安装

前言

最近在做游戏项目,采用Unity3d的JEngine框架来做热更,里面采用的是ILRuntime来进行即时解释运行c#机器码的,IL2CPP虚拟机的运行程序,运行效率也比较快,但存在一个问题是,很多资源都可以实现热更,也包括脚本,但有时候增加特效的时候,很多特效资源包也包含了自己的脚本,我们也不能将该特效资源中的脚本移植为热更脚本,这样运行效率会下降,且有时候ILRuntime的虚拟机没有进行Adapter绑定,没法去调用移植的脚本。Adapter绑定是在编译apk的时候就绑定的,后面热更时,都不能去绑定。这也就意味着,不得不去重新编译新的安装包来进行安装了,所以冷更新功能就有必要增加,腾讯的手游基本也是这个模式,冷 + 热更新。

在Unity中想要安装apk文件,但unity官方没有给出相关的api,需要自己采用android studio写一个模块,采用unity中的c#来进行调用。这里就记录一下Unity C#调用Java代码。

Android Studio生成模块

可能在Android Studio工程创建以及编译过程中会报一些错误,可以看我另一篇博客,避免一些坑。

首先自己新建一个android工程。

选择一个空的项目

image

这里我命名为UnityCallTest,名字随便取。

image

点击Android切换至Project。

image

创建一个Android Library模块

image

名字我就取为install

image

image

接下来创建一个空的文件夹叫tempLibs,然后把Unity引擎中的classes.jar拷贝进去,classes.jar文件在引擎的这个路径中Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Classes ,如果你是mono的,那么路径为Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Classes

image

增加Unity默认的classes.jar进入模块

image

然后打开build.gradle文件,注意是Module里面的这个文件,不是整个安卓工程中的文件,如下图我的module是install,所以是下面的红框中标的这个,不是再下面那个,打开之后右侧红框中的默认是implementation改成compileOnly,这边简单解释下,导入外部的包,默认implementation关键词,最后打包aar时会将这个外部包一起打包进去,但是最后我们是在unity中使用,因此unity中打包apk时已经有一个classes.jar的包去调用了,所以如果打包这个aar包里在加入classes.jar的内容的话,会重复起冲突,因此需要改成compileOnly关键词,这样打aar的时候不会将classes.jar这个外部包打包进去。

image

接着打开install下的src,如果里面有res文件夹的话直接右键创建一个provider_paths.xml文件(如果没有res文件夹的话可以自己创建一个,或者直接创建xml应该会自动创建这个文件夹,如果没创建就自己创建了放进去)

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="publicDir"
path="." />
</paths>

image

接着打开install下的AndroidManifest.xml文件,然后将下面这段内容复制进去,不过需要注意的是(见下图)右侧两个红框中打的路径是前面创建的xml文件的路径,因此如果命名不一样的话,需要这边改成你创建的路径和文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.install">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application>
<meta-data
android:name="com.google.android.actions"
android:resource="@xml/provider_paths" />
<!-- 适配android 7.0以及以上更新APK路径 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>


image

编写Java

好了到这里就准备工作做好了,接下去就是编写java脚本(安装apk的方法了)

我们还是打开InstallApk->src->main,然后选中com.example.install右键New->Java Class,创建一个Java类,类名自己定义,我这边定义的是Install。

image

编写代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.install;

import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import androidx.core.content.FileProvider;

import java.io.File;
import com.unity3d.player.UnityPlayer;

public class Install {
public static boolean InstallApk(String apkPath){
File apkFile = new File(apkPath);
if (apkFile.exists()) {
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(UnityPlayer.currentActivity, UnityPlayer.currentActivity.getPackageName()+".fileprovider", apkFile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
UnityPlayer.currentActivity.startActivity(intent);
return true;
} else {
Log.d("TAG", "文件不存在"+apkPath);
return false;
}
}
}

image

编写完代码保存文件后,就可以点击Build->Make Project,打包出aar文件了。

image

到这部Android Studio上的操作就全部完成了。

Unity3d 调用

接下来将生成的aar文件,拷贝到unity工程的Plugins/Android文件夹下。

然后在unity工程的ProjectSettings->Player->PublishingSettings里开启两个自定义文件的勾,见下图,Custom Main Gradle Template和Custom Gradle Properties Template这两个勾选上后会在Plugins->Android文件夹中。

image

然后分别打开这两个文件进行修改,先打开gradleTemplate.properties文件,在最后加入下面在行语句,加入完保存关闭

1
2
3
android.overridePathCheck=true
android.useAndroidX=true
android.enableJetifier=true

image

再打开mainTemplate.gradle文件,在dependencies后面的大括号中加入下面的语句,加入完保存关闭

1
implementation 'androidx.appcompat:appcompat:1.2.0' 

image

代码调用

然后unity中调用aar包里的安卓apk方法代码如下,不过需要注意的是下图第一个红框中的内容是你安卓工程里写的java脚本中第一行的package加上一个类名,com.android.install.Install类名,第二个红框中的字符串是个java类中写的静态的安装apk的方法名,传的参数是你apk的路径

1
2
3
4
5
public static bool InstallApk(string apkPath)
{
AndroidJavaClass javaClass = new AndroidJavaClass("com.android.install.Install");
return javaClass.CallStatic<bool>("install", apkPath);
}

ref: https://www.bilibili.com/read/cv15111125/

打赏点小钱
支付宝 | Alipay
微信 | WeChat