概念
atlas:容器化框架,提供組件化開發(fā),熱更新。

如上圖所示,atlas主要分為以下幾個層級:
- 最底下的hack工具層: 包括了容器所需的所有系統(tǒng)層面的注入和hack的工具類初始化和校驗,容器啟動時先校驗設備是否支持容器運行,不支持則采取降級并記錄原因;
- Bundle Framework 負責bundle的安裝 更新 操作以及管理整個bundle的生命周期;
- runtime層:主要包括清單管理、版本管理、以及系統(tǒng)代理三大塊,基于不同的觸發(fā)點按需執(zhí)行bundle的安裝和加載;runtime層同時提供了開發(fā)期快速debug支持和監(jiān)控兩個功能模塊。從Delegate層可以看到,最核心的兩個代理點:一個是DelegateClassLoader:負責路由class加載到各個bundle內(nèi)部,第二個是DelegateResource:負責資源查找時能夠找到bundle內(nèi)的資源;這是bundle能夠真正運行起來的根本;其余的代理點均是為了保證在必要的時機按需加載起來目標bundle,讓其可以被DelegateClassloader和DelegateResource使用
- 對外接入層:AtlasBridgeApplication是atlas框架下apk的真正Application,在基于Atlas框架構(gòu)建的過程中會替換原有manifest中的application,所以Atlas沒入的接入并不存在任何初始化代碼,構(gòu)建腳本完成了接入的過程。AtlasBridgeApplication里面除了完成了Atlas的初始化功能,同時內(nèi)置了multidex的功能,這樣做的原因有兩個:
很多大型的app不合理的初始化導致用multidex分包邏輯拆分的時候主dex的代碼就有可能方法數(shù)超過65536,?AtlasBridgeApplication與業(yè)務代碼完全解耦,所以拆分上面只要保證atlas框架在主dex,其他代碼無論怎么拆分都不會有問題;
如果不替換Application,那么atlas的初始化就會在application里面,由于基于Atlas的動態(tài)部署實際上是類替換的機制,那么這種機制就會必然存在包括Application及其import的class等部分代碼在dalvik不支持部署的情況,這個在使用過程中造成一定成本,需要小心的使用以避免dalivk內(nèi)部class resolve機制導致部分class沒成功,替換以后該問題得到最好的解決,除atlas本身以外,所有業(yè)務代碼均可以動態(tài)部署;
另外內(nèi)置的原生的multidex在dalvik上面性能并不好,atlas內(nèi)部對其進行了優(yōu)化提高了在dalvik上面的體驗。
除AtlasBridgeApplication之外,接入層對外提供了部分工具類,包括主動install bundle,start bundle,以及獲取全局的application等各種功能。
集成
-
工程項目的build.gradle文件依賴插件:
image -
app目錄下的build.gradle使用插件,并且添加相關(guān)依賴
image
image
image 加載自啟動的bundle
switchToActivity("home","com.taobao.firstbundle.FirstBundleActivity");
//通過類名來調(diào)用
public void switchToActivity(String key,String activityName){
Intent intent = new Intent();
intent.setClassName(getBaseContext(),activityName);
activityGroupDelegate.startChildActivity(framelayout,key,intent);
}

可以看到現(xiàn)在的fistBundle中彈出了一個toast,message 為“更新一下”,下面修改firstBundle中的代碼,然后熱更新一下
修改toast的message
@Override
protected void onResume() {
super.onResume();
Toast.makeText(this, "單模塊部署1111111", Toast.LENGTH_SHORT).show();
}
bundle熱更新步驟
1、 app的build.gradle的語句"version = getEnvValue("versionName", "1.0.0");"中修改想要生成的app的versionName(默認為1.0.0)
app目錄下執(zhí)行../gradlew clean assembleDebug publish
(生成apk同時將跟apk同目錄的ap文件發(fā)布到倉庫)
2、 手機上安裝apk,同時進到動態(tài)部署界面(側(cè)邊欄里面劃開點擊進入),且手機連接電腦adb(確保adb devices可見)
///////////////////////////////^^^^^^準備工作^^^^^^^^^////////////////////////
3、 進行一些想要的修改(暫時不支持manifest的修改,會在近期上線)
4、 app工程目錄下執(zhí)行../gradlew clean assembleDebug -DapVersion=apVersion -DversionName=newVersion,
其中apVersion為之前打的完整apk的版本,newVersion為此次動態(tài)部署要生成的新的版本號
5、 檢查build/output/tpatch-debug 目錄下文件是否生成,然后執(zhí)行下面的命令(以下為mac下的命令,windows請修改文件分隔符)
adb push build/outputs/tpatch-debug/update.json /sdcard/Android/data/cx.com.atlasdemo11111/cache/update.json
adb push build/outputs/tpatch-debug/patch-*.tpatch /sdcard/Android/data/cx.com.atlasdemo11111/cache
6、 點擊動態(tài)部署頁面紅色按鈕執(zhí)行動態(tài)部署
更改firstBundle中的代碼,然后
在app目錄下執(zhí)行命令,app/build/outputs/ 會出現(xiàn)
//DapVersion基準版本號 DversionName更新版本號
../gradlew clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.1
命令跑完后就會出現(xiàn)下面的目錄結(jié)構(gòu)

執(zhí)行
adb push build/outputs/tpatch-debug/update.json /sdcard/Android/data/cx.com.atlasdemo11111/cache/update.json
adb push build/outputs/tpatch-debug/patch-*.tpatch /sdcard/Android/data/cx.com.atlasdemo11111/cache
然后點擊動態(tài)部署按鈕,效果如下

可以看到熱更新已經(jīng)成功。
遠程bundle使用
- 遠程bundle必須在gradle中配置,如上圖
atlas {
atlasEnabled true
tBuildConfig {
autoStartBundles = ['com.taobao.firstbundle'] //自啟動bundle配置
outOfApkBundles = ['remotebundle']//配置遠程bundle
}
manifestOptions{
addAtlasProxyComponents true
}
patchConfigs {
debug {
createTPatch true
}
}
buildTypes {
debug {
if (apVersion) {
baseApDependency "com.taobao.android.atlasdemo:AP-debug:${apVersion}@ap"
patchConfig patchConfigs.debug
}
}
}
}
2.在Application中添加安裝遠程bundle的回調(diào)
Atlas.getInstance().setClassNotFoundInterceptorCallback(new ClassNotFoundInterceptorCallback() {
@Override
public Intent returnIntent(Intent intent) {
final String className = intent.getComponent().getClassName();
final String bundleName = AtlasBundleInfoManager.instance().getBundleForComponet(className);
if (!TextUtils.isEmpty(bundleName) && !AtlasBundleInfoManager.instance().isInternalBundle(bundleName)) {
//遠程bundle
Activity activity = ActivityTaskMgr.getInstance().peekTopActivity();
File remoteBundleFile = new File(activity.getExternalCacheDir(),"lib" + bundleName.replace(".","_") + ".so");
String path = "";
if (remoteBundleFile.exists()){
path = remoteBundleFile.getAbsolutePath();
}else {
Toast.makeText(activity, " 遠程bundle不存在,請確定 : " + remoteBundleFile.getAbsolutePath() , Toast.LENGTH_LONG).show();
return intent;
}
PackageInfo info = activity.getPackageManager().getPackageArchiveInfo(path, 0);
try {
Atlas.getInstance().installBundle(info.packageName, new File(path));
} catch (BundleException e) {
Toast.makeText(activity, " 遠程bundle 安裝失敗," + e.getMessage() , Toast.LENGTH_LONG).show();
e.printStackTrace();
}
activity.startActivities(new Intent[]{intent});
}
return intent;
}
});
3.把app/build/outputs/remote-bundles-debug/libcom_taobao_remotebundle.so 放到sd卡的cache目錄,執(zhí)行命令
adb push build/outputs/remote-bundles-debug/libcom_taobao_remotebunle.so /sdcard/Android/data/cx.com.atlasdemo11111/cache/libcom_taobao_remotebunle.so
點擊添加遠程bundle看效果

可以看到已經(jīng)將遠程bundle加載成功。
在自己集成的demo中也有很多的坑。跑命令失敗的情況。記錄一下
集成atlas時的坑
- app工程目錄下執(zhí)行../gradlew clean assembleDebug -DapVersion=apVersion -DversionName=newVersion
這個命令中的apVersion必須是存在的版本號,比如在gradle中設置的1.0.0,不然會報找不到依賴
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "cx.com.atlasdemo11111"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName version //這里的versionName要和腳本中的一致,如果設置死,在熱修復merge的時候不會起作用
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
3.這個版本的單模塊調(diào)試模擬還不穩(wěn)定
atlas不得不說是良心之作,這個demo只是簡單地集成,以供參考。


