Home

Awesome

UnityAndroidHotUpdate

release tag license +issue Welcome

[README English]
提供了一个在Android上热更新Unity开发的app的方案,支持代码和资源;不依赖其他语言(lua,js等)不干涉项目开发过程;它通过直接加载新版本apk文件来实现的。
( 依赖的库 ApkDiffPatch, xHook. )

该方案的效果

Android用户在使用app过程中,更新逻辑可以在后台完成下载新版本的任务,当app重新启动后用户看到的是新版本的app(不需要系统安装); 这里的“热更”就是指不需要经过系统的重新安装就拥有了新版本!

热更原理

Android程序在安装后,apk文件存放在getApplicationContext().getPackageResourcePath();并将其中相应abi的库文件解压存放到了getApplicationContext().getApplicationInfo().nativeLibraryDir,其中包括libmain.so,libunity.so,libil2cpp.so or libmono*.so,等;
本方案会在app运行中,将更新到的新版本apk存放到getApplicationContext().getFilesDir().getPath()的更新路径,并将apk中本机abi并发生了改变的库文件解压到更新路径; 当app重启后用hook和java层代码配合,将unity相关库访问apk文件和lib库文件路径的c文件访问函数映射到访问我们准备好的新的apk文件和lib路径。
( Hook Unity库的C文件API来实现热更的思路来源于UnityAndroidIl2cppPatchDemo,感谢,这里做了一些简化和改进。 )

特性

如何接入你的项目测试

<!-- if androidx: provider android:name="androidx.core.content.FileProvider" -->
<provider 
android:name="android.support.v4.content.FileProvider" android:authorities="{YourAppPackageName}.fileprovider" android:exported="false" android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/update_files" />
</provider>

在安卓工程的res目录创建/xml/update_files.xml文件,内容为:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external" path="."/>
</paths>

如何在正式app里自动化热更

app热更应该是一个程序自动化的过程,它将代替我们上面的手工测试过程;(本方案提供了一种可选实现路径)

推荐一个多版本更新流程(较复杂的示例,考虑了支持需要重新安装的情况)

v0 -> new install(v0)

v1 -> diff(v0,v1) -> pat01 ; v0: patch(v0,download(pat01)) -> v1 + cache_lib(v1)
      ( 如果patch时发生错误: download(v1) -> v1 + install(v1) )

v2 -> diff(v0,v2) -> pat02 ; v0: patch(v0,download(pat02)) -> v2 + cache_lib(v2)
      diff(v1,v2) -> pat12 ; v1: patch(v1,download(pat12)) -> v2 + cache_lib(v2)

v3 -> (假设放弃了对v0的补丁) ; v0: download(v3) -> v3 + install(v3)
      diff(v1,v3) -> pat13 ; v1: patch(v1,download(pat13)) -> v3 + cache_lib(v3)
      diff(v2,v3) -> pat23 ; v2: patch(v2,download(pat23)) -> v3 + cache_lib(v3)

if is_need_install(v3,v4):
v4 -> (假设放弃了对v0的补丁) ; v0: download(v4) -> v4 + install(v4)
      diff(v1,v4) -> pat14 ; v1: patch(v1,download(pat14)) -> v4 + install(v4)
      diff(v2,v4) -> pat24 ; v2: patch(v2,download(pat24)) -> v4 + install(v4)
      diff(v3,v4) -> pat34 ; v3: patch(v3,download(pat34)) -> v4 + install(v4)

v5 -> (假设放弃了对v0的补丁) ; v0: download(v5) -> v5 + install(v5)
      (假设放弃了对v1的补丁) ; v1: download(v5) -> v5 + install(v5)
      diff(v2,v5) -> pat25 ; v2: patch(v2,download(pat25)) -> v5 + install(v5)
      diff(v3,v5) -> pat35 ; v3: patch(v3,download(pat35)) -> v5 + install(v5)
      diff(v4,v5) -> pat45 ; v4: patch(v4,download(pat45)) -> v5 + cache_lib(v5)

这个新版本和补丁的发布过程,需要自动化:Apk标准化、重新签名、创建补丁、生成配置等。

已知缺点

by housisong@gmail.com