Atlas插件框架集成总结
仅记录集成Atlas的过程和遇到的问题与总结。 文档书写日期中atlas版本可能稍早,且atlas更新较快,不保证准确性,欢迎指正。 另:不怎么写文档,口水较多。
更新记录:
2017/12/22
简单记录当需要手动分配bunlde的packageID时的方法
参考插件源码码:https://github.com/alibaba/atlas/blob/7de5c34d807a03036d0f9e55711ffaab9e8b9ddc/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/app/prepare/PreparePackageIdsTask.java
原来以为插件的packageID是根据插件的引入顺序决定的,所以为了不出现些奇怪的问题,一再叮嘱不要改变插件引入的顺序,新的插件也只能放在后面(主要是没找到手动分配id的方式,文档里有写但是并不清楚)。但是看源码后比较清晰了。其实并没有严格按手动还是自动分配来区分,因为如果你只给某个插件分配id也是可以的。没有手动分配的插件就会自动给一个,当然不会重复就是了。而且自动分配的时候会根据插件的唯一标识(groupid+artifactId)做一个排序,所以和插件引用的顺序也无关。总的来说自定义id有三种方式,一种是在插件的module里加一个customPackageID.txt文件,里面直接放数字id.第二种是在host项目的gradle中的altas配置部分加packageIdFile,对应值是一个文件路径,内容为groupid:artifactId=number的格式,可配多个插件。第三种是直接在host项目里加一个packageIdFile.properties文件,内容格式和第二种方式一样。三种方式优先级是递增的。最后没有配置的插件会从minPackageId(配置35)开始找一个没被用到的。呃呃呃。。以上都是从代码上看的结论.第一种没试,第三种无效,应该是理解的不对,可能不是通过properties文件方式。第二种方式是可行的。
2017/04/13
1.原先没有找到以坐标方式(awb)引用插件正确打开姿势(主要是因为插件中有单独的包依赖问题,本以为插件单独依赖的包会把资源和代码打包到awb中,最后发现是打到了apk里的插件生成文件so中),现改正。 首先如果某个包只是在一个插件中引用到,并不需要在host中预先引用这个包,只是在上传awb到仓库时pom中的依赖需要配置正确。其次,引用插件时可以用compile或者bundleCompile都可以(个人感觉用bundleCompile好点,能清楚知道它就是个插件),并且不能直接用类似bundleCompile('com.test:secondbundle:1.0.0@awb')方式,这样不会依赖到它自己的依赖,要么直接用bundleCompile('com.test:secondbundle:1.0.0'),要么手动配递归依赖bundleCompile('com.test:secondbundle:1.0.0@awb'){
transitive =true
}
和demo里配依赖atlas-core时一样
直接写成compile('com.taobao.android:atlas_core:5.0.6-rc29')也是可以的
2.修改了插件通过maven publish上传至仓库时pom中没有依赖信息的问题.
1.gradle配置
Atlas的gradle配置应该是最重要也是许多人一直困惑的部分,开始我也不是很明白,现在可能也没完全弄懂,但是集成应该是没问题了。官网和git上都有集成文档,这里只是简单列一下,并对一些之前不太理解的配置做解释。
引入Atlas的插件
这里不需要在引入android插件,里面应该包含了当前能适配的版本。还需要注意的是atlas插件一直在更新,毕竟才放出来问题挺多,所以尽量用最新的。
app(host/main bundle)中gradle配置。分几个部分:
1.基本配置
a.这里仅仅是引入application和atlas,并且对一些环境做配置。
b.如果项目里面分出来的module多建议各种配置写到一个单独的地方管理,可以避免后期修改的时候麻烦一堆。
2.依赖配置
awb:atlas自己定义的一种格式,可以直接理解为普通的aar
host的dependencya.一些atlas基本依赖,仅仅是host需要依赖,插件module不需要
b.引入一些公共的module,根据自己需要,如果是有两个以上插件用到的就可以放到host里面,如果仅是一个插件中用到的模块可以单独放到插件中引用。
c.所引用的插件bundle.建议还是把bundle也打包发布到仓库中通过坐标(group:artifactid:version)的方式引用。这里不要在后面加@awb,否则插件不会依赖到自己pom中的dependencies(看顶部2017/04/13 更新中的1).
3.host打包发布配置
因为做动态更新时是需要历史版本做对比的,所以host打包后需要发布到本地maven中管理(以awb方式引用插件时也需要把插件的awb发布管理)
maven发布配置a.发布时的group和version配置,artifactid写死的AP-debug,可以改
b.引入maven插件,并配置发布时的仓库位置和要发布的东西(*.ap文件,用来后面打包patch时做基准包)。仓库位置可以是公司自己的maven库,也可以是本地库。
c.其中apVersion后面解释打包patch配置时用的
4.atlas插件配置
a. autoStartBundles我理解的是在app启动时就加载的插件bunlde,如果你引用了几个插件并没有配为自启动,那根据文档只能通过触发插件中Component的加载而启动插件,比如start一个bundle中的activity或者service。或者是通过手动调用代码加载一个插件(http://atlas.taobao.org/docs/guide-for-use/guide_for_bundle.html).
b.outOfApkBunldes是配置一些不需要打包到apk的插件,就像demo中的remoteBundle。下图
打包host后的输出结构这种插件中在打包生成apk后不会直接保存到apk中,而是放入单独的文件夹,然后根据自己的需求push或者down到手机上的指定目录。 可以参考官方demo中的DemoApplication,下图
通过设置component查找失败的回调来根据自己的需求获取远程插件。另:getBundleForComponet中componet应该为component - -.
c.patch的配置。之前有见过apVersion,这个默认是空的,代表的是打包patch时的基准线apk.在打包patch时根据命令参数传入.只有apVersion不为空时createTPatch=true才能生效。
这几个地方联系起来才能看懂。还有就是apk的版本也是用这里的version,默认1.0.0可修改。
插件bundle的gradle配置
插件的配置比较简单,一般的android配置跳过了
1.atlas插件配置
根据官方文档配就可以,其中version是发布到仓库中时用的。还有就是打patch时也会用到,demo中没有这个version所以打patch时就是unspecified。baseApFile配成apk打包输出的位置就行,猜测也是打patch时用的。
打patch后的update.json2.依赖配置
这里有三种依赖方式,一般的compile,如果要引用的包只是这个插件使用可以用这种方式(多个插件用到的包需要放到host里面引用).另一种providedCompile,如果不使用altas的插件的话也只可以使用这种引入方式,但是只支持jar包,aar和project不可以(atlas进行了扩展应该)。这种方式引用的包不会打到插件的包中。最后一种bundleCompile也是atlas插件里面的,表示这个插件引用了其它的插件。
3.插件发布配置
如果想要以awb方式引用插件时需要把插件发布到仓库,这里以maven为例,用maven插件中的publish将awb发布到本地库。这种方式暂时没有找到授权相关的配置(求解求指教),所以只能发布到本地或者是不需要授权的maven服务。尝试过用另一种uploadArchive的方式但是不成功(求解求指教)..
2017/04/13更新
上面的配置打包上传后pom中没有依赖信息,需要在publications里手动添加
判断某个依赖是否在providedCompile的依赖集中如图,需要通过pom.withXml配置依赖,并且configurations.compile的依赖集里会包含所有compile或者providedCompile的依赖,需要过滤掉,当前只找到从providedCompile依赖集中遍历的方式,如有更好方式求普及。 通过上面加的配置就可以在插件的仓库pom中添加dependencies结点,并且只有compile引用方式依赖的包。
问题
1.集成项目时原有工程中有productFlavors配置,现在当做插件引用后报错。暂时改为其它方式实现。
2.当集成多个插件(其实是多个app工程,想尝试放到一个里面)后,sync gradle时总是报依赖重复的问题,通过dependencies查看依赖后发现两个插件的一级依赖都有multidex的引用,但是两个插件的gradle配置没有明显的依赖multidex,而且即使有间接依赖multidex的包也是provided的方式依赖。最后看另外一个atlas的demo中有过滤掉support相关的配置,加入之后没有问题。
3.因为插件默认是放到armeabi里面的,所以如果引用的其它三方包中含有其它abi的只能过滤掉了或者选择其它so的输出目录(暂时没看到相关配置).
4.动态更新时遇到部分由于window系统导致的问题(ali开发用的mac), 新版基本已解决,更新很快很给力。
5.【已解决,看2014/04/13更新】以awb方式引用插件时,awb里面如果引用了其它host里面没引用的包,需要把这些包都在host里面引用,因为打包awb后里面并没有所引用包的代码或者资源,所以编译时引用awb时会出现找不到资源的问题。(这点不知道是本来就不支持还是方法没弄对)
6.因为项目中没有和demo一样的动态更新入口,所以用了atlas update中的广播(AwoPatchReceiver)做动态更新测试,打包patch步骤都一样,只是上传的目录有点不同。具体看命令
update.json push到手机上时需要改为patch-*@*.json
还有AwoPatchReceiver缺少一行代码,改了重新发布后可行
经验
1.需要注意的是虽然host里面已经有一个application但是在插件中也是可以指定自己义的application的,只在第一次加载插件时初始化调用。所以如果插件中有需要初始化的操作可以和以前一样放到application,但是要小心在代码中getApplication得到的并不是插件中定义的。
2.有时插件可能需要访问host里面的资源或者代码(如appname,launcher),可以单独建一个library存放公共资源和代码,并且一些公共的三方库引用也可以放到里面,这样所有插件都只需要以provided的方式引这个library就可以,不用在每个插件里面都引用相同的库。
3.为了开发插件时方便,插件在开发过程中应该是可以直接运行的application而不是library,而且打包插件和开发时gralde配置是有区别的。这时可以分开创建两个单独的gradle(build_app.gradle,build_lib_gradle),在build.gradle中根据开发还是打包选择引用对应的文件。
4.有上面一点基础上,我们还可以根据是打包app还是打包插件,在gradle中引用不同的代码目录,或者是不同的manifest文件。这样就可以把平时当作app的项目中很多代码和资源区分开来,manifest也可以简化许多,这样还可以配不同的application。(老项目还是eclipse结构。。studio结构也是可以的)
5.开始时是使用项目依赖的方式引用插件,速度慢而且经常出现编译时插件中R类和资源不正常导致n多个dex文件的65535问题。改为awb后好很多。
6.还要注意插件间的资源是独立的,所以可以存在相同的资源名。使用时也要稍加注意。
7.开发时若出现莫名奇妙的问题(可能执行过动态更新),在clean之后也无用时,把手机上已安装的app卸载试试。
8.看dingding群里问的很多的问题build中某个文件被占用,经常出现(window),所以host中每次执行task前把java杀一下。其实也就2秒的时间而已,不用太吹毛求疵
9.使用awb的方式引用插件时格式为bundleCompile或者compile都可以,bundleCompile更直观。
10.许多人对gradle命令不熟悉(我也不是很熟,偶尔发现的),提几个经常遇到人问的点 :
a.terminal中默认在项目根目录。所以如果在根目录直接执行task(如clean)时会执行所有的module的clean任务。有时这样做并不是必需的而且部分任务并不是所有module都支持的,这时就会出错。
b.如果只想对某个module执行task
方法一:可以cd到这个module的目录在执行gradlew操作。根据module的目录层级加..\ 。mac系统换成/
..\gradlew clean
..\..\gradlew clean
方法二: 一直在根目录,不用切换目录,不用管目录的层级多深。自己用这种方式
gradlew :moduleName:taskname(如clean)
c.多个task一条命令
gradlew :moduleB:clean :moduleA:clean :moduleA:asR(可以缩写,代表assembleRelease) :moduleA:publish
11.使用坐标方式引用插件时,每个插件都要配置maven publish上传的配置,如果在每个插件的gradle中都配置一次的话会导致很多重复并且修改时也不方便。这时我们可以新建一个单独的publish.gradle文件存放上传相关配置,至于每个插件的group,artifactId和version相关信息在插件的module中新增一个gradle.properties里单独配置就ok.这样在插件的gradle中apply一下就行,修改也只用改一份.
插件gradle中引用 publish.gradle中存publish相关配置,并且groupid,version等用配置而不是定死 gradle.properties中配置
最后
总的来说Atlas的集成算比较简单的,修改的地方也比较少,大多是gradle的配置,插件中没有引入任何atlas相关的包,可以说完全无感知。简单了解实现原理更加觉得nubility.不管是从class的加载还是资源的加载方式都感觉很聪明,这两块一直是插件化的大问题所在。而且所说不久的将来就会放出动态添加activity和service的功能,这是很多插件框架做不到的。
官网上有讲解部分框架原理,还算比较容易理解。http://atlas.taobao.org/docs/principle-intro/Runtime_principle.html
最后的最后
感谢啊里的同学在dingding群中耐心的解答各种问题,态度是相当好。也挺佩服的,毕竟许多问题已经回答了n遍。。。 但是我觉得啊里的牛牛们应该花更多的时间去改变世界而不是帮我们普及各种不是那么高级的知识或者回答n遍相同的问题,许多东西还是自己摸索理解的深刻,呵呵嗒。