Atlas指南
Atlas簡介
一洼哎、遠程Bundle:Bundle類似于Android項目中的Module的概念噩峦,遠程Bundle是項目編譯時不會打包進APK的模塊族淮,在項目編譯時祝辣,Atlas框架會將遠程Bundle生成一個.so文件蝙斜,我們將這個.so文件置于服務(wù)器孕荠,用戶使用APP時如果需要打開這個模塊岛琼,就從服務(wù)器上下載這個.so文件槐瑞,并加載到應(yīng)用中困檩,以此來減小安裝包的體積。
二等舔、熱更新:就是打補丁包,對一個版本進行代碼修改后义郑,可以通過Atlas框架根據(jù)修改的代碼生成差量補丁包非驮,客戶端可以通過下載服務(wù)器上的補丁包并部署劫笙,在不需要用戶更新應(yīng)用的情況下完成更新填大。
Atlas接入
參考:
1.新建項目
新建項目后施逾,再新建幾個 類型的Module(Bundle):
app
主工程
LibraryBundle
所有的項目依賴都在這個Bundle完成(比如Retrofit)汉额,其他的Bundle再依賴于這個Bundle
LocalBundle
本地Bundle蠕搜,在打包時就會打包到APK中
RemoteBundle
遠程Bundle妓灌,編譯后會生成.so文件虫埂,當(dāng)用戶需要打開某個模塊時掉伏,從服務(wù)器上下載這個.so文件供常,并加載到應(yīng)用中
2.修改Gradle
以下內(nèi)容基于 Android Studio3.0 栈暇,初始Gradle版本 4.1源祈, compileSdkVersion 26
這個步驟將會修改Gradle版本及compiledSdkVersion
修改Gradle版本至3.3
將工程目錄下的 gradle\wrapper\gradle-wrapper.properties 文件中的最后一行的值改成
https\://services.gradle.org/distributions/gradle-3.3-all.zip
這時Gradle報了一個錯: Gradle DSL method not found: 'google()'
可以將項目目錄下的build.gradle文件中兩個google()
去掉,點及Try Again
Gradle又報了一個Minimum support Gradle version is 4.1. Current version is 3.3
的錯脚草,這是因為剛剛我們修改的那個文件中的dependencies
閉包中的classpath
聲明的gradle版本不對
本來應(yīng)該是2.3.3版本,這里直接將classpath這一行替換成
classpath "com.taobao.android:atlasplugin:2.3.3.rc12"
引入阿里的依賴(需要將原來的刪除)写隶,阿里依賴里面默認是2.1版本的Gradle
順便在這個文件中加入mavenLocal()
如圖示
點擊Try Again之后Gradle又報了一個Could not find method implementation() ..............
啥的錯...
這是因為之前建項目的時候是4.1版本的Gradle,它把項目的依賴從compile
改成了implementation
....
我們這時候?qū)odule下的build.gradle文件中的implementation
改成compile
改完之后dependencies成了這樣:
在示例中直接將compileSdkVersion改成25冕房,同時需要修改的還有buildToolsVersion耙册,修改成'25.0.2'详拙,targetSdkVersion也改成25
同時之前新建的Module也像上面這樣修改
注意:
Android Studio會提示更新Gradle版本到4.1饶辙,不要讓Android Studio更新脯爪,點擊Don't remind me for this project
3.引入Atlas框架
修改app下的build.gradle
group = 'com.gavynzhang.myatlastest'
version = getEnvValue("versionName", "1.0.0"); //版本號
def apVersion = getEnvValue("apVersion", "");
apply plugin: 'com.android.application'
apply plugin: 'com.taobao.atlas'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.gavynzhang.myatlastest"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
testCompile 'junit:junit:4.12'
//atlas的依賴
compile('com.taobao.android:atlas_core:5.0.7.42@aar') {
transitive = true
}
compile 'com.taobao.android:atlasupdate:1.1.4.11@aar'
compile 'com.alibaba:fastjson:1.1.45.android@jar'
//項目依賴
compile project(':librarybundle')
compile project(':localbundle')
compile project(':remotebundle')
}
//加入以下配置
atlas {
atlasEnabled true //打開atlas
tBuildConfig {
// autoStartBundles = ['com.android.homebundle'] //自啟動bundle配置
outOfApkBundles = ['remotebundle'] //遠程module,列表來的守屉,可填多個
preLaunch = 'com.gavynzhang.myatlastest.AtlasLaunch' //AppApplication啟動之前調(diào)用拇泛,這個類下面放出代碼
}
patchConfigs {
debug {
createTPatch true
}
}
buildTypes {
debug {
if (apVersion) {
// 打差異補丁 gradlew assembleDebug -DapVersion=1.1.0 -DversionName=1.1.1
// 對應(yīng)著本地maven倉庫地址 .m2/repository/com/gavynzhang/myatlastest/AP-debug/1.0.0/AP-debug-1.0.0.ap
baseApDependency "com.gavynzhang.myatlastest:AP-debug:${apVersion}@ap"
patchConfig patchConfigs.debug
}
}
}
}
String getEnvValue(key, defValue) {
def val = System.getProperty(key);
if (null != val) {
return val;
}
val = System.getenv(key);
if (null != val) {
return val;
}
return defValue;
}
apply plugin: 'maven'
apply plugin: 'maven-publish'
publishing {
// 指定倉庫位置
repositories {
mavenLocal()
}
publications {
// 默認本地倉庫地址 用戶目錄/.m2/repository/
maven(MavenPublication) {
//讀取ap目錄上傳maven
artifact "${project.buildDir}/outputs/apk/${project.name}-debug.ap"
//生成本地maven目錄
groupId group
artifactId "AP-debug"
}
}
}
修改RemoteBundle和LocalBundle中的build.gradle
apply plugin: 'com.android.library'
apply plugin: 'com.taobao.atlas'
atlas {
bundleConfig{
awbBundle true
}
buildTypes {
debug {
baseApFile project.rootProject.file('app/build/outputs/apk/app-debug.ap')
}
}
}
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
//依賴lib中間bundle
compile project(':librarybundle')
}
需要將其中的applicationId刪去
修改LibraryBundle中的build.gradle
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
testCompile 'junit:junit:4.12'
compile 'com.squareup.okhttp3:okhttp:3.9.0' //在librarybundle中添加依賴
}
修改AndroidManifest.xml文件
將LocalBundle
和RemoteBundle
中的AndroidManifest.xml
修改成如下形式:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gavynzhang.localbundle">
<application>
<activity android:name=".LocalMainActivity">
</activity>
</application>
</manifest>
將LibraryBundle
中的AndroidManifest.xml
中的application
標簽刪去
增加MyApplication
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
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;
}
});
}
}
增加類AtlasLaucher
public class AtlasLauncher implements AtlasPreLauncher {
@Override
public void initBeforeAtlas(Context context) {
}
}
Atlas使用
加載遠程Bundle
先在 項目/app目錄下執(zhí)行 ..\gradlew.bat clean assembleDebug
负间,執(zhí)行完成之后遠程Bundle的.so文件將在app/build/outputs/remote-bundles-debug
目錄下
將遠程Bundle的.so文件下載到/sdcard/Android/data/應(yīng)用包名/cache目錄政溃,然后通過
Intent intent = new Intent();
intent.setClassName(view.getContext(),"com.gavynzhang.remotebundle.RemoteActivity");
activity.startActivity(intent);
來啟動這個遠程Bundle
加載本地Bundle
使用以下代碼即可:
Intent intent = new Intent();
intent.setClassName(view.getContext(), "com.gavynzhang.localbundle.MainActivity");
startActivity(intent);
項目構(gòu)建及運行
打包APK
在項目中的APP目錄下使用..\gradlew.bat clean assembleDebug
安裝
上一個步驟完成之后,生成的apk文件會在app/build/outputs/apk
目錄下空扎,使用adb install build/outputs/apk/app-debug.apk
將APK安裝到手機上
動態(tài)修補(TPatch)
發(fā)布基線版本
在app目錄下執(zhí)行..\gradlew.bat clean assembleDebug
命令,執(zhí)行完成之后再執(zhí)行..\gradlew.bat publish
命令
此時將會生成app-debug.apk文件盘寡,在app/build/outputs/apk目錄下
使用adb install 命令將app-debug.apk安裝到虛擬機或測試機上
生成動態(tài)修補相關(guān)文件
在項目中進行一些想要的修改之后(不支持AndroidManifest.xml的修改), 在app的build.gradle文件中修改versionName為新的version(如將"1.0.0"修改成"1.0.1");
然后在app目錄下執(zhí)行
..\gradlew.bat clean assembleDebug -DapVersion=apVersion -DversionName=newVersion
命令竿痰,其中apVersion為修改之前的versionName影涉,newVersion為修改之后的versionName规伐;
如 ..\gradlew.bat clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.1
此時相關(guān)的文件將在app/build/outputs/tpatch-debug
目錄中生成蟹倾,我們需要將其中的
patch-1.0.1@1.0.0.tpatch
和update.json
放到服務(wù)器上(.tpatch文件名由修改前后的versionName決定)
加載到app中
將之前生成的.tpatch文件和update.json文件下載到/sdcard/Android/data/應(yīng)用包名/cache
目錄下,并執(zhí)行如下代碼:(需要在子線程中運行)
File updateInfo = new File(getExternalCacheDir(), "update.json");
String jsonStr = new String(FileUtils.readFile(updateInfo));
UpdateInfo info = JSON.parseObject(jsonStr, UpdateInfo.class);
File patchFile = new File(getExternalCacheDir(), "patch-" + info.updateVersion + "@" + info.baseVersion + ".tpatch");
try {
AtlasUpdater.update(info, patchFile); //調(diào)用Atlas進行動態(tài)修補
} catch (Throwable e) {
e.printStackTrace();
showToast("更新失敗, " + e.getMessage());
}
Atlas單模塊部署
當(dāng)項目越來越大猖闪,每次調(diào)試都重新構(gòu)建整個項目會非常地慢鲜棠,在Atlas中,可以使用
..\gradlew.bat clean assemblePatchDebug
在不重新安裝APP的情況下進行快速地調(diào)試(在APP運行的情況下)
具體流程如下:
- 先啟動已經(jīng)安裝的app
- 在Android Studio的命令行中切換到需要調(diào)試的Bundle的目錄下培慌,如 cd firstbundle
- 執(zhí)行
..\gradlew.bat clean assemblePatchDebug
執(zhí)行完成后就能夠看到app重啟豁陆,單模塊部署生效