转自:http://blog.csdn.net/wdd1324/article/details/76855408
如有错误请指正!
简介
Atlas是伴随着手机淘宝的不断发展而衍生出来的一个运行于Android系统上的一个容器化框架,我们也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。
atlas是一个组件框架,atlas不是一个多进程的框架,他主要完成的就是在运行环境中按需地去完成各个bundle的安装,加载类和资源。
- atlas能做什么
- 工程模块的独立加载和运行
- 及时上线新需求、快速迭代
- 业务灰度与技术灰度的快速验证
- 动态修复线上故障
- 有问题及时回滚
原理—–>具体请参考官方文档
atlas类加载机制---加载顺序:
1. 查找自身内部的class
2. 查找bundle依赖的bundle内的class
3. 查找主apk中的class
Bundle: 类似OSGI规范里面bundle(组件)的概念,每个bundle有自己的classloader,与其他bundle相隔离,同时Atlas框架下bundle有自身的资源段(PackageID,打包时AAPT指定);另外与原有OSGI所定义的service格式不同之处是Atlas里面Bundle透出所有定义在Manifest里面的component,随着service,activity的触发执行bundle的安装,运行。
awb: android wireless bundle的缩写,实际上同AAR类似,是最终构建整包前的中间产物。每个awb最终会打成一个bundle。awb与aar的唯一不同之处是awb与之对应有个packageId的定义。
host: 宿主的概念,所有的bundle可以直接调用host内的代码和资源,所以host常常集合了公共的中间件,UI资源等。host和bundle的依赖关系如下图所示:
Android打包基础(视频课时2)
1.处理资源文件
2.处理aidl文件
3.编译java文件
4.class2dex
5.apk打包
6.签名
7.zipalign对齐
参考
gradle基础
Gradle史上最详细解析
Android Gradle 插件中文指南
自定义Gradle插件
官方文档—>英文好的可以去看,我是看不懂- -!
接入
官方demo中文件
module名 | 意义 |
---|---|
activitygroupcompat | demo中的工具类 |
app | 客户端代码 |
databindbundle | 使用Google bind框架demo |
firstbundle | 第一个业务bundle代码 |
lottie | splashScreen依赖的代码 |
middlewarelibrary | 中间键library,会打包到主dex中 |
publicbundle | 共bundle代码,不会打入主dex中 |
remotebundle | 远程bundle,在发布时不会编译进apk,而在客户端使用时,先下载后加载 |
secondbundle | 第二个业务bundle代码 |
secondbundlelibrary | 第二个业务单独依赖的代码 |
splashScreen | 闪屏代码 |
在工程build.gradle文件中引入
mavenLocal()//如果有GitHub地址就换成git上地址
classpath "com.taobao.android:atlasplugin:2.3.3.rc1"
在appbuild.gradle文件中引入
- 应用plugin
apply plugin: 'com.taobao.atlas'//atlas插件()
- 添加运行库依赖
compile('com.taobao.android:atlas_core:5.0.7.30@aar') {//atlas核心库
transitive = true
}
compile 'com.taobao.android:atlasupdate:1.1.4.10@aar'//atlas框架更新功能相关的库
- 开启atlas容器功能
atlas {
atlasEnabled true //atlas开关,一般接入后都打开
tBuildConfig {//
//自启动bundle配置,跟随应用启动而加载;普通bundle是随运行而加载
autoStartBundles = ['com.taobao.firstbundle']
//打包时,不打包到包中的bundle,也就是远程bundle
outOfApkBundles = ['remotebundle']
//是指在atlas框架启动前需要启动的功能(如:崩溃信息统计。。。),并且在atlas启动前的功能是不能被动态部署的!
preLaunch = 'com.taobao.demo.DemoPreLaunch'
classInject false
dataBindingBundles = ['com.taobao.databindbundle']
}
manifestOptions {
addAtlasProxyComponents true
}
patchConfigs {
debug {
createTPatch true
}
}
buildTypes {
debug {
if (apVersion) {
//基线版本坐标
baseApDependency "com.taobao.android.atlasdemo:AP-debug:${apVersion}@ap"
patchConfig patchConfigs.debug
}
}
}
}
- 依赖中添加其他bundle
//这种依赖会当成bundle,打包会打包到apk的lib下,也就是我们的插件了
bundleCompile project(':firstbundle')
//compile 'com.taobao.android.atlasdemo:firstbudle:1.0.0@awb'
bundleCompile project(':secondbundle')
bundleCompile project(':remotebundle')
bundleCompile project(':publicbundle')
bundleCompile project(':databindbundle')
创建第二个module->FirstBundle
- 配置build.gradle
apply plugin: 'com.android.library' (这个要注意 这里是library不是application 并且在android中没有id设置!!!!!!)
apply plugin: 'com.taobao.atlas'//atlas插件()
atlas {
bundleConfig {
//标明这是一个bundle工程,产物会生成awb文件,也就是最后打入包中的so文件
awbBundle true
}
buildTypes {
debug {
//基线版本位置
baseApFile project.rootProject.file('app/build/outputs/apk/app-debug.ap')
}
}
}
//如果是用发布版本的方法:
/*group = 'com.taobao.android.atlasdemo'
version = "1.0.0";
apply plugin: 'maven'
apply plugin: 'maven-publish'
publishing {
repositories {
mavenLocal()
}
}
publishing {
publications {
maven(MavenPublication) {
artifact "${project.buildDir}/outputs/awb/${project.name}-debug.awb"
artifactId "firstbundle"
}
}
}*/
- 依赖写法
//依赖编译,但是不会打入包中
providedCompile project(':middlewarelibrary')
providedCompile project(':publicbundle')
了解官方demo app module 在../gradlew assembleDebug后生成文件意义
- 1、进入app文件目录(用as自带ter:cd app)
- 2、调用构建项目gradle命令:../gradlew assembleDebug(或点击as右侧gradle中module中的assembleDebug生成)
- 3、然后我们可以进入app,下build->outputs->apk文件目录下可以看到两个文件
- 一个是.apk debug对应的安装包文件
- 一个是.ap 被称为基线版本ap,将来在这个版本上,进行动态部署时需要的。(动态部署时,会根据这个ap生成差量的内容)
- 4、logs文件夹(不必关注)
- 5、remote-bundles-debug文件夹 存放所有远程bundle文件
- 6、apk-files.txt文件 所有文件名称、路径还有md5值,是为了以后用动态部署时进行比较文件是否变化的依据。
- 7、atlasConfig.json文件 记录所有atlas所有配置项的值,里面包含了一些默认值。
- 8、atlasFrameworkProperties.json 主要记录了bundle的信息(bundle的名称、依赖、版本信息)
- 9、build.txt 记录了gradle版本 atlas版本。。。的版本信息
- 10、dependencies、dependencyTree-debug两个文件 记录了项目中所有依赖
- 11、packageIdFile.properties文件 记录了每个bundle和它们的
资源分段
(为了避免bundle资源与apk资源冲突的问题) - 12、pluginDependencies.txt 插件的依赖(暂时不用关注)
- 13、version.properties文件 记录了所有依赖的版本好和它们的格式
atlas的apk与普通apk区别(可以观看视频 课时4)
发布基线版本
- 在app目录下执行发布命令:../gradlew publish
- 打开目录:open ~/.m2/repository/
- 我们可以在目录中看到~/.m2/repository/com/taobao/android/atlasdemo/AP-debug/1.0.0/AP-debug-1.0.0.ap 文件
那怎么设置版本好呢?
我们现在在app 的build.gradle中可以看到group、version、artifactId这三个字段,标示了我们发布的路径、名称、版本group = 'com.taobao.android.atlasdemo' version = getEnvValue("versionName", "1.0.0"); publishing { publications { maven(MavenPublication) { artifact "${project.buildDir}/outputs/apk/${project.name}-debug.ap" artifactId "AP-debug" } } }
构建Tpatch(具体可以看demo中的Tpatch.txt文件有详细说明,如下)
1、 app的build.gradle的语句"version = getEnvValue("versionName", "1.0.0");"中修改想要生成的app的versionName(默认为1.0.0)
app目录下执行../gradlew clean assembleDebug 生成apk (windows 环境的命令为 ..\gradlew.bat clean assembleDebug 以下类同)
2、 app目录下执行../gradlew publish 将跟apk同目录的ap文件发布到仓库,此时ap的版本是1.0.0
3、 手机上安装生成的apk,同时进到动态部署界面(侧边栏里面划开点击进入),且手机连接电脑adb(确保adb devices可见)
///////////////////////////////^^^^^^^准备工作^^^^^^^^^^////////////////////////
4、 进行一些想要的修改(不支持manifest的修改)
5、 app工程目录下执行../gradlew clean assembleDebug -DapVersion=apVersion -DversionName=newVersion,
其中apVersion为之前打的完整apk的版本,newVersion为此次动态部署要生成的新的版本号,
例如命令 ../gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.1
6、 检查build/output/tpatch-debug 目录下文件是否生成,然后执行下面的命令(以下为mac下的命令,windows请修改文件分隔符)
adb push build/outputs/tpatch-debug/update-1.0.0.json /sdcard/Android/data/com.taobao.demo/cache/update-1.0.0.json
(根据你手机的当前版本推送对应版本的update-**.json,和对应的tpatch文件)
adb push build/outputs/tpatch-debug/patch-1.0.1@1.0.0.tpatch /sdcard/Android/data/com.taobao.demo/cache/patch-1.0.1@1.0.0.tpatch
7、 点击动态部署页面红色按钮执行动态部署
8、 后续继续做想要的修改,我们要变成1.0.2 (某个bundle做动态部署的时候请更新版本号,因为差量会基于版本号对比)
../gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.2 这时候会生成两个 patch-1.0.2@1.0.0.tpatch patch-1.0.2@1.0.1.tpatch
根据你目前的app版本,重复6步骤,推送对应版本的update-**.json,和对应的tpatch文件。
9、 后续继续做想要的修改,我们要变成1.0.3 (某个bundle做动态部署的时候请更新版本号,因为差量会基于版本号对比)
../gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.3 这时候会生成三个 patch-1.0.3@1.0.2.tpatch patch-1.0.3@1.0.1.tpatch patch-1.0.3@1.0.0.tpatch
根据你目前的app版本,重复6步骤,推送对应版本的update-**.json,和对应的tpatch文件。
10、 如果做了多次动态部署后,需要从头开始测试,请先清楚AtlasDemo根目录下的hisTpatch文件夹。
常用命令(都需要到对应包下)
- 构建debug命令: ../gradlew assembleDebug
- 发布基线版本命令:../gradlew publish
- 单模块部署命令:../gradlew assemblePatchDebug
Activity跳转关系
Atlas Demo里面的Activity分布比较散,为了方便大家的快速入手,这里简单介绍下个Activity的跳转关系。
WelcomeActivity
splashscreen bundle是会被编译进主dex里面的,从spllashscreen的manifest文件(splashscreen/src/main/AndroidManifest.xml)我们可以看到,WelcomeActivity是接收“android.intent.action.MAIN”和“android.intent.category.LAUNCHER”的Activity,WelcomeActivity是APP的入口Activity。
WelcomeActivity->MainActivity
在WelcomeActivity.java(splashscreen目录)中的onPostCreate通过startActivity跳转到APP的首页MainActivity(app目录)。
MainActivity->FirstBundleActivity
MainActivity其实是个壳子Activity,在其onCreate函数中我们可以看到它其实是默认加载了firstbundle的FirstBundleActivity,并设置了导航栏,关于导航栏的具体实现细节大家可以参考activitygroupcompat bundle。
MainActivity->FirstBundleActivity、MainActivity->SecondBundleActivity
通过导航栏我们可以实现在FirstBundleActivity和SecondBundleActivity之间进行跳转,FirstBundleActivity和SecondBundleActivity是属于不同的bundle,通过这种方式我们就实现了不同bundle的Activity在同一个APP中的展示。
场景构建
Atlas Demo里面集成了主APK构建、动态部署构建、远程bundle构建等功能,下面我们进行单独介绍。
问题1:如何构建一个APK,发布到各个应用市场?
主APK构建步骤:
Atlas Demo中将主客户端代码和所有bundle都放在了一个工程下面,这也符合gradle工程的标准框架格式。
各个业务bundle可以根据业务需求修改更新各自bundle的代码。然后再通过修改app/build.gradle中的version = getEnvValue(“versionName”, “1.0.0”);来修改版本号,版本号默认为1.0.0。
- 然后再在app目录下面执行
../gradlew clean assembleDebug publish
命令从而进行APK打包,生成的APK文件目录是app/build/outputs/apk/app-debug.apk,上述命令也会将该目录下的ap文件发布到仓库以便于后续生成patch。 - 如果有手机连接在pc上可以直接使用adb install安装上述APK,在app目录下执行
adb install app/build/outputs/apk/app-debug.apk
。
问题2:如何在用户无感知的情况下,实现所有业务模块的独立动态更新?
#### 动态部署(patch)构建步骤:1. 各个业务bundle可以根据业务需求修改更新各自bundle的代码。2. app工程目录下执行`../gradlew clean assembleDebug -DapVersion=apVersion -DversionName=newVersion`, 其中apVersion为之前打的完整APK的版本,newVersion为此次动态部署要生成的新的版本号。这里举一个简单的例子,例如“主APK构建”步骤的APK版本是1.0.0,然后我简单更新firstbundle的string.xml里面的hello_blank_fragment属性为“this is fragment of firstBundle”,然后执行`../gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.1`。- 感兴趣的同学可以研究下update.json和tpatch文件
- 动态部署的主要优势:摆脱版本迭代周期限制,新增需求灵活发布;降低版本频繁发布给用户带来困扰;发现问题及时回滚;短时间内更高的覆盖率
问题3:如果在APK发布时,我不想把某个bundle编译进APK,而是在客户端使用时下载后加载,该怎么办?
远程bundle构建步骤:
- 添加远程bundle的依赖,参考 app/build.gradle下的
bundleCompile project(':remotebundle')
, - 声明远程bundle列表,参考 app/build.gradle下的
atlas { tBuildConfig { outOfApkBundles = ['remotebundle'] }
。 - 构建完整包,在app目录下执行
../gradlew clean assembleDebug publish
,远程bundle 路径:app/build/outputs/remote-bundles-debug。 - 将远程so下载到你的设备上(主动下载和被动推送都可以),这里直接在PC上执行
adb push app/build/outputs/remote-bundles-debug/libcom_taobao_remotebunle.so /sdcard/Android/data/com.taobao.demo/cache/libcom_taobao_remotebunle.so
。 - 打开Demo侧边栏,点击“远程组件模拟”,点击“加载远程bundle”,加载成功后就会跳到remotebundle的页面。
调试工具
单bundle调试(供线下调试使用,当只更改了单个bundle的代码时,无需对整个APP进行动态部署,可以一键进行单bundle的部署调试)
- 在设备上安装APP,设备ADB连接电脑成功。
- 修改一个bundle工程的代码或者资源(设置生效的标识)。
例如,我们这里在firstbundle中的FirstBundleActivity的onCreate的中加一个Toast提示,如下 - bundle工程的目录下执行
../gradlew clean assemblePatchDebug
,然后等应用重启或者应用关闭后点击重启”)就可以看到代码生效。
根据上述改动,我们在firstbundle的目录下执行../gradlew clean assemblePatchDebug
,然后就可以看到客户端重启,Toast提示生效。