Atlas指南
Atlas简介
一、远程Bundle:Bundle类似于Android项目中的Module的概念,远程Bundle是项目编译时不会打包进APK的模块,在项目编译时,Atlas框架会将远程Bundle生成一个.so文件,我们将这个.so文件置于服务器,用户使用APP时如果需要打开这个模块,就从服务器上下载这个.so文件,并加载到应用中,以此来减小安装包的体积。
二、热更新:就是打补丁包,对一个版本进行代码修改后,可以通过Atlas框架根据修改的代码生成差量补丁包,客户端可以通过下载服务器上的补丁包并部署,在不需要用户更新应用的情况下完成更新。
Atlas接入
参考:
1.新建项目
新建项目后,再新建几个 类型的Module(Bundle):
app
主工程
LibraryBundle
所有的项目依赖都在这个Bundle完成(比如Retrofit),其他的Bundle再依赖于这个Bundle
LocalBundle
本地Bundle,在打包时就会打包到APK中
RemoteBundle
远程Bundle,编译后会生成.so文件,当用户需要打开某个模块时,从服务器上下载这个.so文件,并加载到应用中
01.PNG
2.修改Gradle
以下内容基于 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版本不对
03.PNG
本来应该是2.3.3版本,这里直接将classpath这一行替换成
classpath "com.taobao.android:atlasplugin:2.3.3.rc12"
引入阿里的依赖(需要将原来的删除),阿里依赖里面默认是2.1版本的Gradle
顺便在这个文件中加入mavenLocal()如图示
001.PNG
点击Try Again之后Gradle又报了一个Could not find method implementation() ..............啥的错...
这是因为之前建项目的时候是4.1版本的Gradle,它把项目的依赖从compile改成了implementation....
05.PNG
我们这时候将Module下的build.gradle文件中的implementation改成compile
改完之后dependencies成了这样:
06.PNG
在示例中直接将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启动之前调用,这个类下面放出代码
}
patchConfigs {
debug {
createTPatch true
}
}
buildTypes {
debug {
if (apVersion) {
// 打差异补丁 gradlew assembleDebug -DapVersion=1.1.0 -DversionName=1.1.1
// 对应着本地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修改成如下形式:
package="com.gavynzhang.localbundle">
将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目录下执行 ..\gradlew.bat clean assembleDebug,执行完成之后远程Bundle的.so文件将在app/build/outputs/remote-bundles-debug目录下
将远程Bundle的.so文件下载到/sdcard/Android/data/应用包名/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);
项目构建及运行
打包APK
在项目中的APP目录下使用..\gradlew.bat clean assembleDebug
安装
上一个步骤完成之后,生成的apk文件会在app/build/outputs/apk目录下,使用adb install build/outputs/apk/app-debug.apk将APK安装到手机上
动态修补(TPatch)
发布基线版本
在app目录下执行..\gradlew.bat clean assembleDebug命令,执行完成之后再执行..\gradlew.bat publish命令
此时将会生成app-debug.apk文件,在app/build/outputs/apk目录下
使用adb install 命令将app-debug.apk安装到虚拟机或测试机上
生成动态修补相关文件
在项目中进行一些想要的修改之后(不支持AndroidManifest.xml的修改), 在app的build.gradle文件中修改versionName为新的version(如将"1.0.0"修改成"1.0.1");
然后在app目录下执行
..\gradlew.bat clean assembleDebug -DapVersion=apVersion -DversionName=newVersion命令,其中apVersion为修改之前的versionName,newVersion为修改之后的versionName;
如 ..\gradlew.bat clean assembleDebug -DapVersion=1.0.0 -DversionName=1.0.1
此时相关的文件将在app/build/outputs/tpatch-debug目录中生成,我们需要将其中的
patch-1.0.1@1.0.0.tpatch和update.json放到服务器上(.tpatch文件名由修改前后的versionName决定)
加载到app中
将之前生成的.tpatch文件和update.json文件下载到/sdcard/Android/data/应用包名/cache目录下,并执行如下代码:(需要在子线程中运行)
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); //调用Atlas进行动态修补
} catch (Throwable e) {
e.printStackTrace();
showToast("更新失败, " + e.getMessage());
}
Atlas单模块部署
当项目越来越大,每次调试都重新构建整个项目会非常地慢,在Atlas中,可以使用
..\gradlew.bat clean assemblePatchDebug 在不重新安装APP的情况下进行快速地调试(在APP运行的情况下)
具体流程如下:
先启动已经安装的app
在Android Studio的命令行中切换到需要调试的Bundle的目录下,如 cd firstbundle
执行..\gradlew.bat clean assemblePatchDebug
执行完成后就能够看到app重启,单模块部署生效