Unity Android交互自动安装应用
🤔开始做一个安卓小游戏,没有想到要去热更新它,结果做完才想到,有bug怎么办.....
于是就有了下面的踩坑之旅。
版本环境
- Unity 2020.3.20f1c1
- Android Studio 4.1.3
踩坑之旅
Unity调用Android的方法
-
新建一个Empty Activity项目
-
点击完成后,删除红框内容无用内容
变更后的AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.linyisonger.callme"> <application > <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity> </application> </manifest>
-
添加一个测试的静态方法
-
修改继承自Activity
-
修改构建文件
-
构建arr包
-
新建一个Unity工程
-
Build Settings... Ctrl+Shift+B
切换至Android平台
-
将生成好的arr包放入
Plugins\Android
目录下 -
新建脚本调用它
新建Test脚本文件
using UnityEngine; using UnityEngine.UI; public class Test : MonoBehaviour { public Text showResult; private void Start() { var jo = new AndroidJavaObject("cn.linyisonger.android.MainActivity"); int sum = jo.CallStatic<int>("add", 1, 3); showResult.text = sum.ToString(); } }
新建一个Text随便改改样式、将脚本挂在Canvas上(😎当然挂在那里都是可以的,我就随便挂一下)、将Text组件拖至脚本的showResult字段上。
-
打包测试
添加场景、选择运行设备、构建并运行
-
效果
Unity自动更新并调用安装
示意图 😂有点糙
-
将
classes.jar
包引入项目中来D:\Unity\2020.3.20f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
右键添加类库
-
将classes.jar设置为仅编译时构建,打包时不包含此文件(Unity打包会带上)
implementation files('libs\\classes.jar') // 当前 compileOnly fileTree(dir: "libs",includes: ["*.jar"]) // 修改
-
添加安装方法
MainActivity.java
package cn.linyisonger.callme; import androidx.core.content.FileProvider; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import com.unity3d.player.UnityPlayer; import java.io.File; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public static int add(int a, int b) { return a + b; } public static void install(String apkFullPath){ Intent intent = new Intent(Intent.ACTION_VIEW); File file = new File(apkFullPath); if (Build.VERSION.SDK_INT >= 24) { Uri apkUri = FileProvider.getUriForFile(UnityPlayer.currentActivity.getApplicationContext(), UnityPlayer.currentActivity.getPackageName() +".fileprovider", file); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); } else { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = Uri.fromFile(file); intent.setDataAndType(uri, "application/vnd.android.package-archive"); } UnityPlayer.currentActivity.startActivity(intent); } }
-
构建arr包放置在Unity工程中
-
设置包名
-
添加filepaths.xml文件,放在Android/res/xml下
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="download" path="Android/data/cn.LinYisonger.CallAndroid/files/"/> </paths>
-
添加AndroidManifest.xml文件,放在Android下
<?xml version="1.0" encoding="utf-8"?> <!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN--> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <application> <provider android:name="androidx.core.content.FileProvider" android:authorities="cn.LinYisonger.CallAndroid.fileprovider" android:grantUriPermissions="true" android:exported="false" android:usesCleartextTraffic="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="@style/UnityThemeSelector"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> </application> </manifest>
-
添加更新脚本
using System; using System.Collections; using System.IO; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; public class Test1 : MonoBehaviour { /// <summary> /// 版本模型 /// </summary> public class VersionModel { /// <summary> /// Id /// </summary> public long id; /// <summary> /// 程序Key值 /// </summary> public string key; /// <summary> /// 编号 /// </summary> public string no; /// <summary> /// 描述 /// </summary> public string desc; /// <summary> /// 安卓包路径 /// </summary> public string apkUrl; } public delegate void LoadingAction(float progress); public delegate void VersionAction(VersionModel version); private VersionModel CurrentVersion; private string path => Application.persistentDataPath + "/update.apk"; public Text UpdateText; private void Start() { StartCoroutine(GetCurrentVersion((v) => { if (v.no != Application.version) { StartCoroutine(Download((p) => { // 下载进度 UpdateText.text = (p * 100).ToString("0.00"); }, () => { // 下载完成 UpdateText.text = "下载完成"; // 安装 Install(); })); } })); } public IEnumerator GetCurrentVersion(VersionAction action) { UnityWebRequest webRequest = UnityWebRequest.Get("http://y.linyisonger.cn/api/version/GetTheLatestVersion?key=cn.LinYisonger.CallAndroid"); yield return webRequest.SendWebRequest(); CurrentVersion = JsonUtility.FromJson<VersionModel>(webRequest.downloadHandler.text); action.Invoke(CurrentVersion); } public IEnumerator Download(LoadingAction loading, Action done) { UnityWebRequest webRequest = UnityWebRequest.Get(CurrentVersion.apkUrl); webRequest.SendWebRequest(); while (!webRequest.isDone) { loading(webRequest.downloadProgress); yield return 0; } File.WriteAllBytes(path, webRequest.downloadHandler.data); done(); yield return null; } public void Install() { var jo = new AndroidJavaObject("cn.linyisonger.callme.MainActivity"); jo.CallStatic("install", path); } }
-
构建调试然后就会报错🤨
WARNING: The option setting 'android.enableR8=false' is deprecated. It will be removed in version 5.0 of the Android Gradle plugin. You will no longer be able to disable R8
将构建的版本调整为3.4.0
-
构建调试打开应用闪退啦! 😲
找了很久原来是少引用了依赖库
# 添加依赖支持 implementation 'androidx.legacy:legacy-support-v4:1.0.0'
-
构建调试
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统