几乎都是支持的。但严格来说,也是有一些特殊情况:
首先,SophixManager的initialize被调用之前的代码无法修复。很好理解,热修复框架都没加载起来,怎么可能修复到呢?所以最好的做法是把初始化放在Application.attachBaseContext或者Application.onCreate的最开始。并且如果是冷启动方式修复,调用initialize的所在类无法被修复。
其次,AndroidManifest.xml里面的变动无法修复。因为AndroidManifest.xml是由系统在安装app时解析,因此在运行时app无法修改它的逻辑的。所以四大组件的新增和修改以及其中主题资源等配置都无法修复到。除非用比较hack的方式预先留空和提早注册,而这种方式就显得不够优雅了。
另外,Sophix里热修复框架本身的代码默认不进行修复
除这两种情况,其他方面的所有热修复都可以得到支持。
这是根据代码变动情况决定的。
代码若变动小,一般会走即时生效热修复,而如果代码变动大,比如在已存在的类中新增方法,修改了so等情况,都会走冷启动。这是由打包工具自行检测代码变化来判断的,开发者无需考虑。
并且,在运行期如果在所运行的设备上检测到不支持即时生效热修复,也会在该机型上走强制冷启动修复。
而如果对稳定性有极高要求,可开启强制冷启动选项,这样任何变动都会按强制冷启动方式打包。
目前发现的崩溃大多是即时生效修复不支持,而补丁工具难以检测到的情况,如修复反射方法之类的。此时可以在补丁工具中开启强制冷启动选项重新打包,即可解决。
发布前请严格按照:扫码内测 => 灰度发布 => 全量发布的流程进行,以保证补丁包能够正常在所有Android版本的机型上生效。为了保险起见,理论上应该对每个版本的android手机都测一遍是否生效会比较好。不过,其实只需测试通过以下具有代表性的Android版本就基本没什么大问题了:2.3、4.4、5.1、7.0
只有调用queryAndLoadNewPatch才会请求新的补丁,并且,如果本地已经有一个补丁正在被应用,那么会等到下次重启才会加载新补丁生效。
因此如果你是在Application的onCreate里面这么写的:
SophixManager.getInstance().setContext(this) .setAppVersion(appVersion) .setPatchLoadStatusStub(new PatchLoadStatusListener() { @Override public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) { // 补丁加载回调通知 if (code == PatchStatus.CODE_LOAD_SUCCESS) { // 表明补丁加载成功 } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) { // 表明新补丁生效需要重启. 开发者可提示用户或者强制重启; // 建议: 用户可以监听进入后台事件, 然后应用自杀 } else if (code == PatchStatus.CODE_LOAD_FAIL) { // 内部引擎异常, 推荐此时清空本地补丁, 防止失败补丁重复加载 // SophixManager.getInstance().cleanPatches(); } else { // 其它错误信息, 查看PatchStatus类说明 } } }).initialize(); SophixManager.getInstance().queryAndLoadNewPatch();
那么,假设你现在发布了一个新补丁,此时app已经加载了一个老版本的补丁并在运行中。而其他地方没有再调用到queryAndLoadNewPatch。
第一次重启,会调用queryAndLoadNewPatch,会完成下载和补丁预加载。但由于已经initialize,不会马上加载新补丁。
第二次重启,initialize会发现刚才已经加载的新补丁,加载,新补丁生效。
因此通常就会重启两次。
而如果你是在没有加载补丁的时候queryAndLoadNewPatch,对于即时生效的热修复会马上应用补丁,对于强制冷启动的热修复会在下次重启后应用补丁。
而如果想要重启一次就生效,可以在app运行过程中定期调用queryAndLoadNewPatch,以提早查询新补丁并进行预加载,这样只要以后重启一次就可以生效了。
所以加载新补丁的时机取决于queryAndLoadNewPatch。
需要用**混淆后**的新旧两个包打补丁。并且新包的混淆逻辑需要和旧包保持一致,一般就是使用mapping.txt文件来做到。具体请参考demo中的注释说明。
如果app中用到了加固,切记需要在加固前打补丁包。而是否支持要看这个加固框架是以什么方式实现的。注意混淆和加固是不一样的,加固可能包含了混淆,并且做了很多特殊处理。
顺带说明一下,这个问题开发者应该咨询加固厂商如何做到兼容热修复的情况,因为加固做了很多特殊处理,所以由那边支持是比较合理的。不过后期我们也会针对几个主流的加固框架进行调研。
请将补丁工具移到“应用程序”目录下即可。
如果你遇到了java.lang.NoClassDefFoundError: Failed resolution of: Lcom/alibaba/sdk/android/utils/AMSDevReporter$AMSSdkTypeEnum;
一般是build.gradle配置有问题。可能是你配成了
compile ('com.taobao.android:alisdk-hotfix:2.0.8') { transitive = false }
从而将相关依赖排除了,导致类找不到而报错。因此,可改为
compile 'com.taobao.android:alisdk-hotfix:2.0.8'
若改完出现utdid包冲突,可再改为
compile ('com.taobao.android:alisdk-hotfix:2.0.8') { exclude(module:'utdid4all') }
如果你遇到了这个问题
一般就是你build.gradle里面百川仓库配置错误导致的。
请确认要在app目录下的build.gradle中添加了百川仓库:
repositories { maven { url "http://repo.baichuan-android.taobao.com/content/groups/Baichua?nRepositories" } }
或者是在根目录的build.gradle里面的allprojects里面添加仓库:
allprojects { repositories { mavenLocal() //百川仓库 maven { url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories" } jcenter() } }
Sophix包括了arm64-v8a、armeabi、armeabi-v7a、x86 、x86_64五种架构。若超出了用户自己定义的jni架构范围,可以在ndk配置中添加abiFilters进行过滤:
defaultConfig { ndk { moduleName "my-native-lib" abiFilters 'armeabi', 'arm64-v8a' } }