Atlas Demo过程记录。有这个是因为项目中的插件不是放在apk里面,也不是自动下载安装的。而是有个插件管理界面,里面和app应用市场一样的可以安装,更新和卸载插件(其中还涉及到一些用户/插件/插件中的功能 之间的权限问题,这里不需要关心)。Atlas自带的动态部署和dexPatch不满足需求,比如更新是要针对单个插件的更新而不是整个apk和所有插件。 为了找到解决方案和复习Atlas的动态部署,这才用新的demo重新走了遍流程。最后还好发现条路子可以解决我的问题~~!。
1。打包
assembleDebug
1.0.0
gradlew publish -DversionName=1.0.0(这里不加参数默认也是1.0.0,但是得有这个概念)
本地maven
3.安装运行apk
mo\app\build\outputs\remote-bundles-debug\libcom_taobao_remotebunle.so /sdcard/Android/data/com.taobao.demo/cache/libcom_taobao_remotebunle.so
直接打开运程bundle中的component加载bundle运行。
5.查看目前为止手机上生成的产物。Adb shell下
在往下本地bundle和remote的稍微不一样
--------------------------------------------------------动态部署------------------------------------------------------
1.分别对publicBundle,firstbundle,secondbundle,remotebundle做简单修改。
2.gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=2.0.0
*这里第一次打patch时失败,原因是修改过的bundle没有改version.
3.maven上传新的ap
gradlew publish -DversionName=2.0.0
首先demo文档中没有指示这一步,其次,需要指定版本,不然把原先maven中的1.0.0覆盖掉,这样是不对的,而且又得重来。
4..tpatch差异包文件
根据修改的情况不同,每个bundle包中结果可能不同。
比如只改了代码,就只有classes.dex;改了界面但是没有加id操作,就会多res但是不会有resources.arsc. Maindex.so也差不多,只是多了manifest,因为最起码版本号变了,所以manifest肯定需要更新。
6.上传手机
adb push build/outputs/tpatch-debug/update-1.0.0.json /sdcard/Android/data/com.taobao.demo/cache/update-1.0.0.json
adb push build/outputs/tpatch-debug/patch-2.0.0@1.0.0.tpatch/sdcard/Android/data/com.taobao.demo/cache/patch-2.0.0@1.0.0.tpatch
8.so far so good. 疑惑的地方是,文档里面说动态部署后bundle和hostbundle在文件夹里面都为升级,如version1到version2,备份了为回滚做准备,但是并没有看到。手机里面目录结构和动态部署前差不多,只是bundle文件夹下面那一串unitTag的文件夹名变成新的了。
------------------------------------------第二次动态部署----------------------------------------
1.修改部分bundle。
3.上传测试,因为当前手机是2.0.0,所以上传的是2.0.0到3.0.0的patch
adb push build/outputs/tpatch-debug/update-2.0.0.json /sdcard/Android/data/com.taobao.demo/cache/update-2.0.0.json
adb push build/outputs/tpatch-debug/patch-3.0.0@2.0.0.tpatch /sdcard/Android/data/com.taobao.demo/cache/patch-3.0.0@2.0.0.tpatch
4.so for so gud. 查看手机文件夹还是和第一次动态部署情况一样。
----------------------------测试直接从安装状态更新到3.0.0,并且在安装时不上传加载remote------------------------------
1.把1.0.0的ap中的apk安装到手机
2.在把3.0.0对于1.0.0的patch上传到手机
3.动态部署后,内部bundle能正常更新,但是外部bundle因为没有安装过so不能启动,所以也谈不上更新。
4.把1.0.0的remote上传后可正常运行,但是这样就失去了3.0.0的更新。
5.但是把1.0.0的remote完全从手机中删除后,重新上传3.0.0remote的so,加载后就是3.0.0的状态。
6.震精!!!重新卸载安装1.0.0,上传3.0.0的remote,可行。那么就是说,我可以单独更新某个remote bundle,不需要动态部署的升级版本,也不仅限于dexPatch只能更新代码。只要安装前把原来已经安装的remote的文件夹删除就可以。但是需要考虑几个问题:1.已经运行状态,内存中关于remote bundle的信息已经加载是否会造成影响,比如说已经删除了文件夹,但是还是能查到这个bundle的信息。2.后面的更新不能依赖于host的更新。3.如果此次启动已经运行过remote,是否会有影响,是否需要直接关闭应用让用户重启。
7.最后一试,上一条否定。不用直接删除文件夹处理,用自带的Atlas里面的uninstall方法卸载可行。但是不会删除上传的so,所以要注意处理。这样的话单独更新一个remotebunlde是确实可行的。。。
8.So far so fucking gud.
9.新发现,现在通过AtlasBundleInfoManager查询到的插件版本都是null,不管是否是remote. Why? I need it.
10.Debug时发现通过uninstall把remote插件卸载之后,通过Atlas.getBundle是获取不到了,但是AtlasBundleInfoManager中还是有保存。
11.测试发现AtlasBundleInfoManager中的远程插件的信息和有没有安装或者安装的是那个版本的remote没什么关系,不会变化。
12.测试发现从Altas获取Bundle时如果插件还没有运行过得到的是null.
最后,过程中记录一下还是挺有好处的,有好几次需要各种命令,比如push文件到手机啊,run-as看手机目录啊这种,本来路径就长记不住,需要的时候回来文档里面找一下,美滋滋。
-----------------后续在实际项目中遇到的新问题---------------------
1.通过uninstall在install的方式更新远程插件时,如果这个要更新的插件在这次启动app还没有加载过,那么会导致uninstall失败。 解决办法有:设置成启动就加载,虽然有可能还没有安装过插件会导致异常,但是应该不至于崩溃。这样的话能保证更新的时候如果之前已经安装过,在启动的时候已经加载了,就不会异常。 还可以在uninstall前判断下有没有加载,没有的话就先执行一次加载在卸载。项目中我使用的是后者。
2.如果更新成功需要重启app.不是因为需要重启才能看到更新,且是不重启会崩溃。日志里面看不出什么异常,因为是框架里面的原因。
2017/11/14更新
最新发现,按照上面的逻辑管理插件时。当手机上安装了插件后,开发时如果apk修改后installDebug安装,这时storage下面编译后的插件还在,但是一旦启动apk后,storage下面的插件文件夹就消失了。 猜测是发现插件的那个类似唯一码的东西和apk里面的对应插件的不相同,所有系统把它删除了。
解决办法:这个时候就体现出我之前备份安装过的插件so的英明之处了,哈哈。
利用Atlas.getInstance().setClassNotFoundInterceptorCallback
回调,重新安装备份插件即可。如果找不到插件或者安装失败,则直接清除表里面的插件信息,跳转到插件管理界面提示用户重新安装插件即可。no毛病~!
2018/05/23更新
使用中发现在插件间通过intent传递数据时会有问题。比如class找不到,或者类型转换异常等,具体细节忘了。只记得解决方法是把Searializable换成Parceable,还有就是在activity中设置调用intent的setExtrasClassLoader方法,把类加载器设置为插件的BundleClassLoader,不然这些系统类会用默认的加载器,如果数据类是在插件中而不是在host里面就会报找不到类。还有调用Bundle里面的setClassLoader也是一样的。