Android 快速集成

更新时间:2018-09-11 10:46:23

本文档为EMAS Android SDK快速集成手册。

一、 APP 工程准备

新建或者使用已有的Android工程。

在接入前,确保工程能编译通过,顺利运行后,再开始接入, 避免增加不必要的麻烦。

二、 集成准备

EMAS包括以下SDK能力,可选择性接入:

应用更新SDK:提供应用的完整APK更新能力、动态部署更新/DexPatch补丁更新能力(如接入了)

高可用SDK:提供客户端整个性能、稳定性监控分析,包括crash、性能、日志、埋点等等

WEEX-SDK:一套构建高性能、可扩展的原生应用跨平台开发方案

Atlas组件化框架:提供组件化架构、动态部署、DexPatch热修复能力

2.1 应用信息和SDK配置信息

集成前需获取应用的信息和SDK相关配置信息,SDK初始化需要这些信息才能正常的工作。

以下局部变量名均来自脚手架工程中的EmasInit.java文件,此处仅仅作为说明示例,本文后面会用到。可以将这些数据配置到一个json文件中放置到assets目录,初始化的时候通过读取该文件获取数据(参考脚手架工程里的DemoApplication.java),可以参考脚手架工程中assets目录中的aliyun-emas-services.json文件。

应用基本信息:AppKey和SecretKey,在控制台注册应用后获取。

  • mAppkey = 10000039
  • mAppSecret = c7795717b2306055f21fb33418c1d011

SDK配置信息:域名需接入方申请(POC环境的域名配置信息可参考POC Demo)。

  • 统一网关域名: 示例:mMTOPDoman = “aserver.emas-ha.cn”

  • APP渠道号:开发者自定义。渠道号组成规则(渠道ID@应用英文名_应用os_版本号),示例:mChannelID = “1001@DemoApp_Android_1.0.0”。

  • 高可用SDK长连通道域名:示例:mACCSDoman = “acs.emas-ha.cn”

  • 高可用SDK数据上报域名:示例:mHAUniversalHost = “adash.emas-ha.cn”

  • 高可用SDKOssBucket:示例:mHAOSSBucketName = “emas-ha-remote-log-poc”

  • 高可用SDK公钥:示例:mHARSAPublicKey = “xxxx”

  • 高可用SDK启动Activity:APP的启动Activity。示例:mStartActivity = “com.taobao.demo.WelcomActivity”

  • WEEX预加载url:示例:mCacheURL = @”http://mobilehubdev.taobao.com/eweex/"。

2.2 配置依赖下载MAVEN地址

修改文件位置:项目根目录的build.gradle(Demo位置:Android-EMAS-Demo/build.gradle)

修改文件内容:allprojects.repositories中配置maven仓库地址用于拉取EMAS相关SDK

示例

  1. allprojects {
  2. repositories {
  3. maven { url "http://nexus-ce.emas-poc.com/repository/maven-public/" //SDK中心仓库地址
  4. credentials {
  5. username = "xxx" //SDK中心仓库账号密码
  6. password = "xxx"
  7. }
  8. }
  9. maven { url "xxx" } //业务模块aar/awb snapshot仓库地址(体验时可填POC产物仓库snapshot地址)
  10. maven { url "xxx" } //业务模块aar/awb release仓库地址(体验时可填POC产物仓库release地址)
  11. }
  12. }

2.3 接入EMAS插件

1、引入插件库

修改文件位置:工程根目录的build.gradle(Demo位置:Android-EMAS-Demo/build.gradle)

修改文件内容:在buildscript中

(1)配置maven仓库地址[maven {url “xxx”}]用于拉取EMAS插件

(2)加入classpath “com.taobao.android.gradle:emas-plugin:2.1.3”(注:如仍使用gradle4.0以下环境,emas插件请使用1.7.2-SNAPSHOT)示例

  1. buildscript {
  2. repositories {
  3. maven {
  4. url "http://nexus-ce.emas-poc.com/repository/maven-public/" //EMAS SDK中心仓库地址
  5. credentials {
  6. username = "xxx" //SDK中心仓库账号密码
  7. password = "xxx"
  8. }} //SDK中心仓库地址
  9. maven { url "http://maven.aliyun.com/nexus/content/repositories/google/"}
  10. }
  11. dependencies {
  12. classpath "com.taobao.android.gradle:emas-plugin:2.1.3"
  13. }
  14. }

2、创建common.gradle

新建文件位置: 在app项目根目录新建common.gradle(Demo位置:Android-EMAS-Demo/app/common.gradle)

配置作用:用于从EMAS控制台获取环境信息

文件内容

  1. def emas_version_name = getEnvValue('EMAS_VERSION_NAME', "1.0")
  2. def emas_version_code = getEnvValue('EMAS_VERSION_CODE', "1")
  3. def emas_base_version = getEnvValue('EMAS_BASE_VERSION', "1")
  4. //设置渠道包
  5. def emas_channel_list = getEnvValue("EMAS_CHANNEL_LIST","")
  6. if (emas_version_code) {
  7. android.defaultConfig.versionCode = emas_version_code.toInteger()
  8. println("emas_version_code=" + emas_version_code)
  9. }
  10. if (emas_base_version) {
  11. println("emas_base_version=" + emas_base_version)
  12. }
  13. if (emas_version_name) {
  14. android.defaultConfig.versionName = emas_version_name
  15. println("emas_version_name=" + emas_version_name)
  16. }
  17. if (emas_channel_list) {
  18. println("emas_channel_list=" + emas_channel_list)
  19. }
  20. String getEnvValue(key, defValue) {
  21. def val = System.getProperty(key);
  22. if (null != val) {
  23. return val;
  24. }
  25. val = System.getenv(key);
  26. if (null != val) {
  27. return val;
  28. }
  29. return defValue;
  30. }

3、应用common.gradle及EMAS插件

修改文件位置:app项目根目录的build.gradle(Demo位置:Android-EMAS-Demo/app/build.gradle)

(1)拷贝下文脚本到build.gradle

(2)拷贝完后,去掉工程中所有原有的 apply plugin: ‘com.android.application’

  1. apply plugin: 'com.taobao.android.emas'
  2. apply from: 'common.gradle'
  3. configurations {
  4. providedCompile
  5. all*.exclude group: 'com.taobao.android', module: 'tnet-jni'
  6. all*.exclude group: 'com.taobao.android', module: 'tlog_adapter'
  7. all*.exclude group:'com.aliyun.ams', module:'alicloud-android-utdid'
  8. }
  9. configurations.all {
  10. resolutionStrategy {
  11. cacheChangingModulesFor(0, 'SECONDS')
  12. cacheChangingModulesFor(0, 'SECONDS')
  13. }
  14. }
  15. task wrapper(type: Wrapper) {
  16. gradleVersion = '3.3'
  17. distributionUrl = 'http://emas-deploy.oss-cn-hangzhou.aliyuncs.com/gradle-3.3-all.zip'
  18. }

4、在android标签中去掉系统生成的versionCode、versionName配置,加入dexOptions配置

配置作用:防止默认的version覆盖控制台传入的version(EMAS平台在做每次发布时会托管这两个参数达到自动更新的效果)

  1. android{
  2. ...
  3. //versionCode 1
  4. //versionName "1.0"
  5. dexOptions {
  6. javaMaxHeapSize = '2048m'
  7. additionalParameters=["--no-strict"]
  8. }
  9. ...
  10. }

5、 按需配置lib目前平台类型,语言类型支持

  1. android{
  2. ...
  3. defaultConfig {
  4. ...
  5. ndk {
  6. abiFilters "x86", "armeabi" //默认只启用x86,armeabi
  7. }
  8. resConfigs "en", "fr"
  9. ...
  10. }
  11. ...
  12. }

6、 加入插件配置

新建文件位置: 在app项目根目录新建emasConfig.properties(Demo位置:Android-EMAS-Demo/app/emasConfig.properties)

配置作用:插件功能开关

文件内容

  1. atlas.tBuildConfig.classInject=false
  2. atlas.enhanceConfigs.debug.enabled=false
  3. atlas.enhanceConfigs.release.enabled=false
  4. #构建配置
  5. atlas.tBuildConfig.fastProguard=true
  6. atlas.tBuildConfig.atlasMultiDex=true
  7. atlas.tBuildConfig.mergeOverride=false
  8. atlas.multiDexConfigs.debug.fastMultiDex=true
  9. atlas.multiDexConfigs.release.fastMultiDex=true
  10. #构建渠道包开关
  11. atlas.atlasChannelConfigs.debug.enabled=false
  12. atlas.atlasChannelConfigs.release.enabled=false

7、 加入Gradle官方配置

新建文件位置: 在app项目根目录新建gradle.properties(Demo位置:Android-EMAS-Demo/app/gradle.properties)

配置作用:gradle官方配置,优化构建效率及处理兼容性等

文件内容

  1. android.enableBuildCache=true
  2. org.gradle.daemon=false
  3. android.enableAapt2=false

2.4 添加SDK依赖

依赖说明

以下步骤会集成以下三个SDK:

1、应用更新SDK(UPDATE SDK)

2、高可用SDK(HA SDK)

3、跨平台SDK(WEEX SDK)

如只需部分能力,可在build.gradle脚本、EmasInit.java、AndroidMenifest.xml中删除掉对应gradle依赖/代码/配置即可。

集成方式

Gradle依赖:标准gradle方式依赖各SDK版本(首次接入推荐采用该方式)

通过EMAS研发平台管理依赖:在EMAS研发平台配置各SDK模块后,可通过平台来发布,更新各SDK模块到APP中。(首次接入不建议采用,对平台模块管理有足够理解后再陆续迁移到平台上)

  • Gradle依赖

    ``` dependencies {

    1. /************基础库 START**********/
    2. compile('com.alibaba:fastjson:1.1.54.android@jar') { transitive true }
    3. compile('com.taobao.android:mtopsdk_allinone:3.0.8.2-open@jar') { transitive true }
    4. compile('com.taobao.android:networksdk:3.3.7-open@jar') { transitive true }
    5. compile('com.taobao.android:tnet4android:3.1.14.6@aar') { transitive true }
    6. compile('com.taobao.android:utdid4all:1.1.5.3_proguard@jar') { transitive true }
    7. /************基础库 END**********/
    8. /************UPDATE START**********/
    9. compile('com.taobao.android:update-datasource:1.0.1-open@jar') { transitive false }
    10. compile('com.taobao.android:update-common:1.0.1-open@aar') { transitive false }
    11. compile('com.taobao.android:update-manager:1.0.1-open@aar') { transitive false }
    12. compile('com.taobao.android:update-adapter:1.0.1-open@jar') { transitive false }
    13. compile('com.taobao.android:update-main:1.0.1-open@aar') { transitive false }
    14. compile('com.taobao.android:downloader:2.0.2.12@jar') { transitive true }
    15. /************UPDATE END**********/
    16. /************高可用 SDK START**********/
    17. compile('com.taobao.android:ut-analytics:1.1.0.1-open@aar') { transitive true }
    18. compile('com.alibaba.ha:alihatbadapter:1.1.0.7-open@aar') {
    19. transitive true
    20. //exclude group:'com.taobao.android', module:'tlog_uploader_oss'
    21. }
    22. //compile ('com.taobao.android:tlog_uploader_ceph:1.1.0.7-open@aar')
    23. //默认oss通道需要依赖oss的三方库
    24. compile 'com.squareup.okhttp3:okhttp:3.4.1@jar'
    25. compile 'com.squareup.okio:okio:1.9.0@jar'
    26. compile 'com.aliyun.dpa:oss-android-sdk:2.4.2@aar'
    27. /************高可用 SDK END**********/
    28. /************WEEX SDK START**********/
    29. compile ("com.taobao.android:weex_sdk:0.18.16.28") { transitive true }
    30. compile('com.taobao.android:zcache:0.1.2-open') { transitive true }
    31. compile('com.alibaba.mtl:dynamicConfig:0.1.0.10') { transitive true }
    32. compile('com.alibaba.mtl:dynamicconfigadapter:0.1.0.10') { transitive true }
    33. compile('com.android.support:recyclerview-v7:26.+') { transitive true }
    34. compile 'com.android.support:appcompat-v7:26.+'
    35. //Weex调试工具,线上发布包无需引入
    36. compile 'com.taobao.android:weex_inspector:0.16.15'
    37. compile 'com.google.code.findbugs:jsr305:2.0.1'
    38. /************WEEX SDK END**********/
    39. /************WEEX 扩展 START**********/
    40. //EMAS开放组件库
    41. compile("com.emas.weex:emas-weex:1.0.1")
    42. //开源图片库
    43. compile 'com.facebook.fresco:fresco:1.5.0'
    44. //加载gif动图需添加此库
    45. compile 'com.facebook.fresco:animated-gif:1.5.0'
    46. //加载webp动图需添加此库
    47. compile 'com.facebook.fresco:animated-webp:1.5.0'
    48. //支持webp需添加此库
    49. compile 'com.facebook.fresco:webpsupport:1.5.0'
    50. /************WEEX 扩展 END**********/
    51. /************通道服务 SDK START**********/
    52. compile('com.taobao.android:accs_sdk_taobao:3.3.3.1-open') { transitive true }
    53. /************通道服务 SDK START**********/

    }

  1. ```
  • 通过EMAS研发平台集成。

    在研发平台新建模块(Maven坐标和版本信息参考下面gradle依赖信息), 再将模块关联到EMAS研发平台上的指定应用即可。参考研发平台使用手册模块管理

三、 SDK初始化

1、拷贝以下配置到AndroidManifest.xml中对应的位置

  1. <!-- permission -->
  2. <uses-permission android:name="android.permission.WRITE_SETTINGS" />
  3. <uses-permission android:name="android.permission.INTERNET" />
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  6. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  7. <uses-permission android:name="android.permission.WAKE_LOCK" />
  8. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  9. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  10. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  11. <uses-permission android:name="android.permission.BROADCAST_PACKAGE_ADDED" />
  12. <uses-permission android:name="android.permission.BROADCAST_PACKAGE_CHANGED" />
  13. <uses-permission android:name="android.permission.BROADCAST_PACKAGE_INSTALL" />
  14. <uses-permission android:name="android.permission.BROADCAST_PACKAGE_REPLACED" />
  15. <uses-permission android:name="android.permission.RESTART_PACKAGES" />
  16. <uses-permission android:name="android.permission.GET_TASKS" />
  17. <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  18. <uses-permission android:name="android.permission.VIBRATE" />
  19. <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
  1. <!-- EMAS Services -->
  2. <!-- HA SDK START -->
  3. <service
  4. android:name="com.taobao.accs.data.MsgDistributeService"
  5. android:exported="false" >
  6. <intent-filter>
  7. <action android:name="com.taobao.accs.intent.action.RECEIVE" />
  8. </intent-filter>
  9. </service>
  10. <!-- HA SDK END -->
  11. <!-- UPDATE SDK START -->
  12. <service android:exported="false" android:name="anetwork.channel.aidl.NetworkService" >
  13. <intent-filter>
  14. <action android:name="anetwork.channel.aidl.IRemoteNetworkGetter" />
  15. </intent-filter>
  16. </service>
  17. <service android:exported="false" android:name="mtopsdk.xstate.XStateService" >
  18. <intent-filter>
  19. <action android:name="mtopsdk.xstate.aidl.IXState" />
  20. </intent-filter>
  21. </service>
  22. <!-- UPDATE SDK END -->

2、拷贝EmasInit.java类到工程(或者直接拷贝脚手架项目里面该文件)

  1. package com.xxx.xxx;
  2. import android.app.Application;
  3. import android.content.Context;
  4. import android.content.res.Resources;
  5. import android.text.TextUtils;
  6. import android.util.Log;
  7. import com.alibaba.dynamic.DynamicSdk;
  8. import com.alibaba.dynamicconfigadapter.DefaultDynamicSDKEngine;
  9. import com.alibaba.ha.adapter.AliHaAdapter;
  10. import com.alibaba.ha.adapter.AliHaConfig;
  11. import com.alibaba.ha.adapter.Plugin;
  12. import com.alibaba.ha.adapter.Sampling;
  13. import com.taobao.accs.ACCSClient;
  14. import com.taobao.accs.ACCSManager;
  15. import com.taobao.accs.AccsClientConfig;
  16. import com.taobao.accs.AccsException;
  17. import com.taobao.accs.IAppReceiver;
  18. import com.taobao.accs.common.Constants;
  19. import com.taobao.accs.utl.ALog;
  20. import com.taobao.update.adapter.UpdateAdapter;
  21. import com.taobao.update.apk.ApkUpdater;
  22. import com.taobao.update.common.Config;
  23. import com.taobao.update.common.framework.UpdateRuntime;
  24. import com.taobao.update.datasource.UpdateDataSource;
  25. import com.taobao.weex.InitConfig;
  26. import com.taobao.weex.WXSDKEngine;
  27. import com.taobao.zcache.ZCache;
  28. import com.taobao.zcache.config.ConfigOrigin;
  29. import com.taobao.zcache.config.EnvEnum;
  30. import com.taobao.zcache.config.ZCacheConfigManager;
  31. import com.taobao.zcache.utils.ILog;
  32. import com.taobao.zcache.utils.ZLog;
  33. import org.android.spdy.SpdyProtocol;
  34. import java.util.ArrayList;
  35. import java.util.HashMap;
  36. import java.util.List;
  37. import java.util.Map;
  38. import anet.channel.SessionCenter;
  39. import anet.channel.strategy.ConnEvent;
  40. import anet.channel.strategy.ConnProtocol;
  41. import anet.channel.strategy.IConnStrategy;
  42. import anet.channel.strategy.IStrategyInstance;
  43. import anet.channel.strategy.IStrategyListener;
  44. import anet.channel.strategy.StrategyCenter;
  45. import anet.channel.strategy.dispatch.HttpDispatcher;
  46. import anetwork.channel.config.NetworkConfigCenter;
  47. import anetwork.channel.http.NetworkSdkSetting;
  48. import mtopsdk.common.util.TBSdkLog;
  49. import mtopsdk.mtop.domain.EnvModeEnum;
  50. import mtopsdk.mtop.global.SwitchConfig;
  51. import mtopsdk.mtop.intf.Mtop;
  52. import mtopsdk.mtop.intf.MtopEnablePropertyType;
  53. import mtopsdk.mtop.intf.MtopSetting;
  54. import mtopsdk.security.LocalInnerSignImpl;
  55. /**
  56. * Created by jason on 18/1/15.
  57. */
  58. public class EmasInit {
  59. public static final int DEBUG = 1; //测试环境
  60. public static final int RELEASE = 2; //发布环境
  61. /*配置信息*/
  62. protected String mAppkey = "20000062";//"10000066";//"10000039";//"10000078";//"60039748";
  63. protected String mAppSecret = "b8bc185ec225c3e784f1a0dddaaa6694";//"1426c10c5ce57d6cb29e016a816421a7";//"c7795717b2306055f21fb33418c1d011";//"2e00a7e9ab2048daabd4977170d37c4a";//"ab5ff148782b467bb0b310c4acd70abd"//"fe240d4b8f4b31283863cc9d707e2cb1"
  64. protected String mCacheURL = "http://publish-poc.emas-ha.cn/eweex/";
  65. protected String mACCSDoman = "accs-pre-k8s-poc.emas-poc.com";
  66. protected Map<String, String> mIPStrategy;
  67. protected String mMTOPDoman = "aserver-pre-k8s-poc.emas-poc.com:30080";
  68. protected String mHAUniversalHost = "adash-pre-k8s-poc.emas-poc.com:32080";
  69. protected String mHAOSSBucketName = "emas-ha-remote-log-poc";
  70. protected String mHARSAPublicKey;
  71. protected String mStartActivity = "com.taobao.demo.WelcomActivity";
  72. protected String mChannelID = "1001@DemoApp_Android_" + BuildConfig.VERSION_NAME;
  73. protected String PUSH_TAG = "POC";
  74. protected boolean mUseHttp = false;
  75. protected int mEnv = RELEASE;
  76. private Application mApplication;
  77. private static final String TAG = "EmasInit";
  78. /**
  79. * 切换成单例
  80. */
  81. private static class CreateInstance {
  82. private static EmasInit instance = new EmasInit();
  83. }
  84. public static EmasInit getInstance() {
  85. return CreateInstance.instance;
  86. }
  87. private EmasInit() {
  88. //不能生成对象
  89. }
  90. //先设置mApplication
  91. public EmasInit setmApplication(Application application) {
  92. this.mApplication = application;
  93. //初始化
  94. firstInit();
  95. return this;
  96. }
  97. private void firstInit() {
  98. Application application = mApplication;
  99. StringBuilder builder = new StringBuilder();
  100. try {
  101. int id = application.getResources().getIdentifier("ttid", "string", application.getPackageName());
  102. if (id > 0) {
  103. mChannelID = builder.append(application.getString(id))
  104. .append("@")
  105. .append(application.getResources().getString(application.getApplicationInfo().labelRes))
  106. .append("_")
  107. .append("Android")
  108. .append("_")
  109. .append(BuildConfig.VERSION_NAME).toString();
  110. }
  111. } catch (Resources.NotFoundException e) {
  112. Log.d(TAG, "no channel id in res" + e.toString());
  113. }
  114. }
  115. /********************UPDATE SDK START **************************/
  116. public void initUpdate() {
  117. initMtop();
  118. Config config = new Config();
  119. config.group = mAppkey + "@android";//AppInfoHelper.getGroup();
  120. config.ttid = mChannelID;
  121. config.isOutApk = false;
  122. config.appName = "EMAS Demo";
  123. UpdateAdapter updateAdapter = new UpdateAdapter();
  124. UpdateDataSource.getInstance().init(mApplication, config.group, config.ttid, config.isOutApk, updateAdapter);
  125. UpdateRuntime.init(mApplication, config.ttid, config.appName, config.group);
  126. ApkUpdater apkupdate = new ApkUpdater();
  127. UpdateDataSource.getInstance().startUpdate(true, false);
  128. }
  129. private void initMtop() {
  130. if (mEnv == DEBUG) {
  131. TBSdkLog.setTLogEnabled(false);
  132. TBSdkLog.setLogEnable(TBSdkLog.LogEnable.DebugEnable);
  133. }
  134. //关闭密文
  135. if (mUseHttp) {
  136. NetworkConfigCenter.setSSLEnabled(false);
  137. }
  138. //[option]关闭MTOP请求长链,调用后Mtop请求直接调用NetworkSDK的HttpNetwork发请求
  139. SwitchConfig.getInstance().setGlobalSpdySwitchOpen(false);
  140. //关闭MTOPSDK NewDeviceID逻辑
  141. MtopSetting.setEnableProperty(Mtop.Id.INNER, MtopEnablePropertyType.ENABLE_NEW_DEVICE_ID, false);
  142. //设置自定义全局访问域名
  143. MtopSetting.setMtopDomain(Mtop.Id.INNER, mMTOPDoman, mMTOPDoman, mMTOPDoman);
  144. //设置自定义签名使用的appKey和appSecret
  145. MtopSetting.setISignImpl(Mtop.Id.INNER, new LocalInnerSignImpl(mAppkey, mAppSecret));
  146. MtopSetting.setAppVersion(Mtop.Id.INNER, BuildConfig.VERSION_NAME);
  147. Mtop mtopInstance = Mtop.instance(Mtop.Id.INNER, mApplication.getApplicationContext(), mChannelID);
  148. }
  149. /********************UPDATE SDK END **************************/
  150. /********************WEEX SDK START **************************/
  151. public void initWeex() {
  152. try {
  153. ImagePipelineConfig imageConfig = ImagePipelineConfig.newBuilder(mApplication)
  154. .setDownsampleEnabled(true)
  155. .build();
  156. Fresco.initialize(mApplication, imageConfig);
  157. EmasWeex.Config econfig = new EmasWeex.Config.Builder()
  158. .setAppkey(mAppkey)
  159. .setAppVersion(BuildConfig.VERSION_NAME)
  160. .setZcacheUrl(mCacheURL).build();
  161. EmasWeex.getInstance().init(mApplication, econfig);
  162. } catch (WXException var6) {
  163. var6.printStackTrace();
  164. }
  165. }
  166. /********************WEEX SDK END **************************/
  167. /********************HA SDK START **************************/
  168. public void initHA() {
  169. //开启
  170. if (mEnv == DEBUG) {
  171. AliHaAdapter.getInstance().openDebug(true);
  172. }
  173. AliHaAdapter.getInstance().changeHost(mHAUniversalHost);
  174. AliHaAdapter.getInstance().tLogService.changeRemoteDebugHost(mHAUniversalHost);
  175. AliHaAdapter.getInstance().tLogService.changeRemoteDebugOssBucket(mHAOSSBucketName);
  176. if (!TextUtils.isEmpty(mHARSAPublicKey)) {
  177. AliHaAdapter.getInstance().tLogService.changeRasPublishKey(mHARSAPublicKey);
  178. }
  179. initHACrashreporterAndUt();
  180. AliHaAdapter.getInstance().openHttp(mUseHttp);
  181. initAccs();
  182. AliHaAdapter.getInstance().removePugin(Plugin.crashreporter); //tlog 依赖accs
  183. AliHaAdapter.getInstance().removePugin(Plugin.ut);
  184. AliHaAdapter.getInstance().telescopeService.setBootPath(new String[]{mStartActivity}, System.currentTimeMillis());
  185. AliHaAdapter.getInstance().start(buildAliHaConfig());
  186. //AliHaAdapter.getInstance().crashService.addJavaCrashListener(new WeexCrashListener());
  187. }
  188. private AliHaConfig buildAliHaConfig() {
  189. //ha初始化
  190. AliHaConfig config = new AliHaConfig();
  191. config.isAliyunos = false;
  192. config.appKey = mAppkey;
  193. config.userNick = "you need set user name";
  194. config.channel = mChannelID;
  195. config.appVersion = BuildConfig.VERSION_NAME;
  196. config.application = mApplication;
  197. config.context = mApplication;
  198. return config;
  199. }
  200. private void initHACrashreporterAndUt() {
  201. AliHaAdapter.getInstance().startWithPlugin(buildAliHaConfig(), Plugin.crashreporter);
  202. AliHaAdapter.getInstance().startWithPlugin(buildAliHaConfig(), Plugin.ut);
  203. AliHaAdapter.getInstance().utAppMonitor.changeSampling(Sampling.All);
  204. }
  205. /********************HA SDK END **************************/
  206. /********************ACCS SDK START **************************/
  207. public final static String TEST_SERVICE_ID = "4272_mock";
  208. private final static Map<String, String> SERVICES = new HashMap<String, String>() {
  209. private static final long serialVersionUID = 2527336442338823324L;
  210. {
  211. put(TEST_SERVICE_ID, "com.taobao.demo.accs.TestAccsService");
  212. }
  213. };
  214. private void initAccs() {
  215. if (mIPStrategy != null && mIPStrategy.size() > 0) {
  216. initNetwork();
  217. }
  218. boolean isDebug = ((mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
  219. if (isDebug) { //debug版本, 打开日志开关, 方便排查问题
  220. ALog.setUseTlog(false);
  221. anet.channel.util.ALog.setUseTlog(false);
  222. }
  223. new Thread() { //建议异步进行初始化
  224. @Override
  225. public void run() {
  226. int env = Constants.RELEASE;
  227. int pubkey = SpdyProtocol.PUBKEY_PSEQ_EMAS;//SpdyProtocol.PUBKEY_SEQ_TEST
  228. String appkey = mAppkey;//"4272"
  229. String appsecret = mAppSecret;//"257461a8005f538382640d4894dd193a04d18e1b4a7a5ee214b6d660778d3943"
  230. String emasHost = mACCSDoman;
  231. SharedPreferences sp = mApplication.getSharedPreferences("emas_accs", Context.MODE_PRIVATE);
  232. String key = sp.getString("appkey", null);
  233. String secret = sp.getString("appsecret", null);
  234. appkey = TextUtils.isEmpty(key) ? appkey : key;
  235. appsecret = TextUtils.isEmpty(secret) ? appsecret : secret;
  236. try {
  237. ACCSManager.setAppkey(mApplication.getApplicationContext(), mAppkey, env);//兼容老接口 如果有任意地方使用老接口,必须setAppkey
  238. NetworkSdkSetting.init(mApplication.getApplicationContext());
  239. //关闭AMDC请求
  240. HttpDispatcher.getInstance().setEnable(false);
  241. ACCSClient.setEnvironment(mApplication.getApplicationContext(), env);
  242. AwcnConfig.setAccsSessionCreateForbiddenInBg(false);
  243. AccsClientConfig clientConfig = new AccsClientConfig.Builder()
  244. .setAppKey(appkey)
  245. .setAppSecret(appsecret)
  246. .setInappHost(emasHost)
  247. .setInappPubKey(pubkey)
  248. .setTag(AccsClientConfig.DEFAULT_CONFIGTAG)
  249. .setConfigEnv(env)
  250. .build();
  251. ACCSClient.init(mApplication, clientConfig);
  252. ACCSClient.getAccsClient(AccsClientConfig.DEFAULT_CONFIGTAG).bindApp(mChannelID, mAppReceiver);
  253. } catch (AccsException e) {
  254. ALog.w(TAG, "initDefaultAccs", e);
  255. }
  256. }
  257. }.start();
  258. }
  259. private IAppReceiver mAppReceiver = new IAppReceiver() {
  260. private String TAG = "mAppReceiver";
  261. @Override
  262. public void onBindApp(int errorCode) {
  263. ALog.i(TAG, "onBindApp", "errorCode", errorCode);
  264. try {
  265. ACCSClient.getAccsClient(AccsClientConfig.DEFAULT_CONFIGTAG).bindUser("123324234");
  266. } catch (AccsException e) {
  267. e.printStackTrace();
  268. }
  269. }
  270. @Override
  271. public void onUnbindApp(int errorCode) {
  272. ALog.i(TAG, "onUnbindApp", "errorCode", errorCode);
  273. }
  274. @Override
  275. public void onBindUser(String userId, int errorCode) {
  276. ALog.i(TAG, "onBindUser", "errorCode", errorCode);
  277. }
  278. @Override
  279. public void onUnbindUser(int errorCode) {
  280. ALog.i(TAG, "onUnbindUser", "errorCode", errorCode);
  281. }
  282. @Override
  283. public void onSendData(String dataId, int errorCode) {
  284. ALog.i(TAG, "onSendData");
  285. }
  286. @Override
  287. public void onData(String userId, String dataId, byte[] data) {
  288. ALog.i(TAG, "onData");
  289. }
  290. @Override
  291. public String getService(String serviceId) {
  292. String service = SERVICES.get(serviceId);
  293. return service;
  294. }
  295. @Override
  296. public Map<String, String> getAllServices() {
  297. return SERVICES;
  298. }
  299. };
  300. private void initNetwork() {
  301. SessionCenter.init(mApplication);
  302. final IStrategyInstance instance = StrategyCenter.getInstance();
  303. StrategyCenter.setInstance(new IStrategyInstance() {
  304. @Override
  305. public void initialize(Context context) {
  306. instance.initialize(context);
  307. }
  308. @Override
  309. public void switchEnv() {
  310. instance.switchEnv();
  311. }
  312. @Override
  313. public void saveData() {
  314. instance.saveData();
  315. }
  316. @Override
  317. public String getFormalizeUrl(String rawUrlString) {
  318. return instance.getFormalizeUrl(rawUrlString);
  319. }
  320. @Override
  321. public List<IConnStrategy> getConnStrategyListByHost(String host) {
  322. String strategy = mIPStrategy.get(host);
  323. if (TextUtils.isEmpty(strategy)) {
  324. return instance.getConnStrategyListByHost(host);
  325. }
  326. final String[] ipPort = strategy.split(":");
  327. List<IConnStrategy> list = new ArrayList<IConnStrategy>();
  328. IConnStrategy connStrategy = new IConnStrategy() {
  329. @Override
  330. public String getIp() {
  331. return ipPort[0];
  332. }
  333. @Override
  334. public int getIpType() {
  335. return 0;
  336. }
  337. @Override
  338. public int getIpSource() {
  339. return 0;
  340. }
  341. @Override
  342. public int getPort() {
  343. return Integer.parseInt(ipPort[1]);
  344. }
  345. @Override
  346. public ConnProtocol getProtocol() {
  347. return ConnProtocol.valueOf("http2", "0rtt", "emas", false);
  348. }
  349. @Override
  350. public int getConnectionTimeout() {
  351. return 10000;
  352. }
  353. @Override
  354. public int getReadTimeout() {
  355. return 10000;
  356. }
  357. @Override
  358. public int getRetryTimes() {
  359. return 1;
  360. }
  361. @Override
  362. public int getHeartbeat() {
  363. return 0;
  364. }
  365. };
  366. list.add(connStrategy);
  367. return list;
  368. }
  369. @Override
  370. public String getSchemeByHost(String host) {
  371. return instance.getSchemeByHost(host);
  372. }
  373. @Override
  374. public String getSchemeByHost(String host, String dftScheme) {
  375. return instance.getSchemeByHost(host, dftScheme);
  376. }
  377. @Override
  378. public String getCNameByHost(String host) {
  379. return instance.getCNameByHost(host);
  380. }
  381. @Override
  382. public String getClientIp() {
  383. return instance.getClientIp();
  384. }
  385. @Override
  386. public void notifyConnEvent(String host, IConnStrategy connStrategy, ConnEvent connEvent) {
  387. instance.notifyConnEvent(host, connStrategy, connEvent);
  388. }
  389. @Override
  390. public String getUnitByHost(String s) {
  391. return null;
  392. }
  393. @Override
  394. public void forceRefreshStrategy(String host) {
  395. instance.forceRefreshStrategy(host);
  396. }
  397. @Override
  398. public void registerListener(IStrategyListener listener) {
  399. instance.registerListener(listener);
  400. }
  401. @Override
  402. public void unregisterListener(IStrategyListener listener) {
  403. instance.unregisterListener(listener);
  404. }
  405. });
  406. }
  407. /********************ACCS SDK END **************************/
  408. }

3、将应用及SDK配置信息替换掉(或者通过上文提到的通过读取assets中json文件的方式获取,具体可以参考脚手架代码)

示例代码

  1. private String mAppkey = "10000032";
  2. private String mAppSecret = "11e929a1bc36382fcfe613a2aae5cf02";
  3. private String mZcachePrefix = "http://publish-poc.emas-ha.cn/eweex/";
  4. private String mAccsHost = "emaspoc-acs.emas-ha.cn";
  5. private Map<String, String> mIPStrategy; //一般无需设置
  6. private String mMtopHost = "emaspoc-aserver.emas-ha.cn";
  7. private String mAdashHost = "emaspoc-adash.emas-ha.cn";
  8. private String mHAOssBucket = "emas-ha-remote-log-poc";
  9. private String mHAPubKey;
  10. private String mStartActivity = "com.taobao.demo.WelcomActivity";
  11. private String mTTid = "1001@
  12. App_Android_" + BuildConfig.VERSION_NAME;
  13. private boolean mUseHttp = false;

4、按需调用初始化接口(需要在Application执行)

  1. EmasInit emas = EmasInit.getInstance().setmApplication(this);
  2. //初始化高可用
  3. emas.initHA();
  4. //初始化应用更新
  5. emas.initUpdate();
  6. //初始化Weex
  7. emas.initWeex();

四、使用EMAS-WEEX

EMAS-WEEX是EMAS官方提供的组件库,提供对weex官方sdk的实用封装以及各种实用、通用组件,目的在于降低EMAS用户对于WEEX的接入、使用成本。

以上章节中已经在gradle依赖和初始化中对EMAS-WEEX做了相应的依赖和初始化操作,这里讲解一些开发过程中使用EMAS-WEEX的使用要点,推荐用户使用EMAS-WEEX而不是weex官方sdk。

WeexPageFragment

除了weex官方sdk的Activity用法外,EMAS-WEEX提供了fragment的方式供渲染weex界面,建议直接继承自WeexPageFragment使用。

可以使用WeexPageFragment的newInstanceWithUrl/newInstanceWithTemplate方法渲染一个weex fragment,支持远程和本地文件渲染,渲染后将绘制到最后一参数所指定的view中

  1. WeexPageFragment fragment;
  2. if (jsSource.startsWith("http")) {
  3. fragment = (WeexPageFragment) WeexPageFragment
  4. .newInstanceWithUrl(this, WeexFragment.class, jsSource, getRenderUrl(jsSource), R.id.frame_root_layout);
  5. } else {
  6. fragment = (WeexPageFragment) WeexPageFragment.newInstanceWithTemplate(this, WeexFragment.class,
  7. WXFileUtils.loadAsset(jsSource, mContext),jsSource,
  8. null, null, R.id.frame_root_layout);
  9. }
  10. fragment.setDynamicUrlEnable(true);

降级

WeexPageFragment提供了默认的降级处理机制,当weex脚本因为各种问题出错且。以被降级时,将通过webview来渲染界面提供兜底策略,避免crash发生。只需要调用setEnableDowngrade方法打开开关即可。

  1. public class WeexFragment extends WeexPageFragment {
  2. @Override
  3. public void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setEnableDowngrade(true);//打开weex跨平台降级处理
  6. }
  7. }

注意,只有渲染线上url方式的weex界面,降级服务才是可用的,同时需要url服从以下格式:

  1. http://h5.taobao.com?_wx_tpl=http://dotwe.org/raw/dist/df16904d7d5a693b231df97c7c575cc4.bundle.wx

_wx_tpl标记后是需要渲染的weex脚本地址(后缀名js/wx等都可以),_wx_tpl标记前是发生错误时需要降级到的H5地址。

WEEX DEVTOOL

EMAS-WEEX集成了官方WEEX DEVTOOL SDK,可以通过WeexInspectorManager.startInspector开启。

使用示例:

  1. private void handleScanCodeResult(String result) {
  2. Uri uri = Uri.parse(result);
  3. if (uri == null) {
  4. Log.e(TAG, "scan result null, return");
  5. } else {
  6. if (WeexInspectorManager.startInspector(uri, mContext)) {
  7. Toast.makeText(this, "连接调试模式", Toast.LENGTH_SHORT).show();
  8. } else {
  9. // 展示weex界面
  10. }
  11. }
  12. }

您可以将扫码后的结果传入到handleScanCodeResult方法中做处理。

WEEX DEVTOOL使用方式可以参考 官方文档

五、开启ATLAS(可选)

Atlas是阿里巴巴集团内部广泛使用的APP组件化框架,通过实现组件化来帮助业务独立开发和上线,并提供动态部署能力使业务具备实时更新和发布的特性。

ATLAS源码可参考ATLAS开源文档地地址

4.1 添加依赖

  • 通过EMAS研发平台集成。

    在研发平台新建模块(Maven坐标和版本信息参考下面gradle依赖信息), 再将模块关联到EMAS研发平台上的指定应用即可。参考研发平台使用手册模块管理

  • Gradle本地集成

修改文件位置:app项目根目录的build.gradle(Demo位置:Android-EMAS-Demo/app/build.gradle)

修改文件内容:configurations中排除mltidex依赖, dependencies中添加atlas相关依赖

示例

  1. configurations {
  2. ...
  3. all*.exclude group: 'com.android.support', module: 'multidex'
  4. ...
  5. }
  1. /************ATLAS START**********/
  2. compile('com.taobao.android:atlas_core:5.0.8.7-rc2-all@aar') { transitive true }/****注:如使用gradle4.0以下环境atlas_core请仍使用5.0.8.0版本****/
  3. compile("com.taobao.android:open-update-aar:1.0.1-open@aar") { transitive true }
  4. compile("com.taobao.android:downloader:2.0.2.12@jar") { transitive true }

4.2 ALTAS配置

1、修改emasConfig.properties

修改文件位置:app根目录的emasConfig.properties(Demo位置:Android-EMAS-Demo/app/emasConfig.properties)

修改文件内容:修改atlas.tBuildConfig.classInject为false, 其他配置直接加入

[]中为需填充的变量,参考示例。

  1. atlas.atlasEnabled=true
  2. atlas.tBuildConfig.autoStartBundles=xxx
  3. atlas.patchConfigs.debug.appSignName = [appkey]@android
  4. atlas.patchConfigs.release.appSignName = [appkey]@android
  5. atlas.tBuildConfig.appCoordinate = [groupId]:[artifactId]
  6. atlas.atlasChannelConfigs.debug.enabled=false
  7. atlas.atlasChannelConfigs.release.enabled=true

示例

  1. //开启atlas
  2. atlas.atlasEnabled=true
  3. //自启动的bundle列表,值是Bundle的packageName
  4. atlas.tBuildConfig.autoStartBundles=com.taobao.firstbundle
  5. //应用唯一标识
  6. atlas.patchConfigs.debug.appSignName = 10000011@android
  7. atlas.patchConfigs.release.appSignName = 10000011@android
  8. //动态部署需要AP包(包含基线apk完整信息的包),定义AP包的发布坐标(确保唯一性)
  9. atlas.tBuildConfig.appCoordinate = com.alibaba.emas:AP
  10. atlas.atlasChannelConfigs.debug.enabled=false
  11. atlas.atlasChannelConfigs.release.enabled=true

2、修改build.gradle

修改文件位置:app项目根目录的build.gradle(Demo位置:Android-EMAS-Demo/app/build.gradle)

修改文件内容:拷贝以下片段到build.gradle,注意替换xxx字段

group: 前文所述AP包的

坐标groupId

repositories url: 发布AP基线包maven仓库地址

username/password: maven仓库账号密码

  1. group = 'xxx.xxx.xxx'
  2. version = android.defaultConfig.versionName + '-SNAPSHOT'
  3. apply plugin: 'maven'
  4. apply plugin: 'maven-publish'
  5. publishing {
  6. publications {
  7. maven(MavenPublication) {
  8. if (project.gradle.startParameter.toString().contains("assembleDebug")) {
  9. artifact "${project.buildDir}/outputs/apk/${project.name}-debug.ap"
  10. artifactId "AP-debug"
  11. } else {
  12. artifact "${project.buildDir}/outputs/apk/${project.name}-release.ap"
  13. artifactId "AP-release"
  14. }
  15. }
  16. }
  17. repositories {
  18. if (version.endsWith("-SNAPSHOT")) {
  19. maven {
  20. url "xxx" //基线包发布仓库snapshot地址(体验时可填POC产物仓库snapshot地址)
  21. credentials {
  22. username = "xxx"
  23. password = "xxx"
  24. }
  25. }
  26. } else {
  27. maven {
  28. url "xxx" //基线包发布仓库release地址(体验时可填POC产物仓库release地址)
  29. credentials {
  30. username = "xxx"
  31. password = "xxx"
  32. }
  33. }
  34. }
  35. }
  36. }

3、修改update sdk初始化方式

修改文件位置:源码目录EmasInit类(Demo位置:Android-EMAS-Demo/app/src/main/java/com.taobao.demo.EmasInit.java)

修改文件内容:替换initUpdate()方法, import对应头文件。

  1. public void initUpdate() {
  2. initMtop();
  3. Config config = new Config();
  4. config.group = mAppkey + "@android";//AppInfoHelper.getGroup();
  5. config.ttid = mChannelID;
  6. config.isOutApk = false;
  7. config.appName = "EMAS Demo";
  8. UpdateManager.getInstance().init(config,
  9. new ClassNotFoundInterceptorCallback() {
  10. @Override
  11. public Intent returnIntent(Intent intent) {
  12. Log.e("APP", "returnIntent" + intent.toString());
  13. return null;
  14. }
  15. }, true);
  16. }

六、新建ATLAS Bundle(可选)

  • ATLAS BUNLDE 源于OSGI规范里面bundle(组件)的概念, 与GOOGLE AAR包的结构类似,可以理解为一个完整的业务模块。

  • 较为独立的业务模块建议转化为Bundle, 基础库(如网路库、图片库等)无需转化,保持为AAR或者JAR库形式

  • 为了更好实现模块间的并行开发及平台自动构建Bundle模块,Bundle代码需要放在单独的git地址,即不与APP工程同在一个Git project。

5.1 Bundle工程准备

如果已有Android Library工程(AAR/JAR工程),可直接使用。

没有则:

(1)创建Android Project工程

(2)再创建Android Library Module,模块代码放在该Module中

基于Android Studio的Android Library工程目录结构如下:

Bundle目录

5.2 引入ATLAS插件

确保5.1准备的工程能编译通过

修改文件位置: 工程根目录build.gradle文件

修改文件内容: 在buildscript中加入以下内容:

  1. buildscript {
  2. repositories {
  3. maven {url SDK_REPOSITORY_URL
  4. credentials {
  5. username = SDK_REPOSITORY_USERNAME
  6. password = SDK_REPOSITORY_PASSWORD
  7. }
  8. }
  9. maven{url"http://maven.aliyun.com/nexus/content/groups/public/"}
  10. maven { url"http://maven.aliyun.com/nexus/content/repositories/google/"}
  11. google()
  12. }
  13. dependencies {
  14. classpath "com.taobao.android:atlasplugin:3.0.1-rc68-3"
  15. }
  16. }

5.3 gradle.properties配置

修改文件位置: 工程根目录gradle.properties文件,如没有则新建

修改文件内容:配置仓库地址及账号

其中 MAVEN_GROUP/MAVEN_ARTIFACTID为Maven仓库的发布坐。MAVEN_GROUP 一般取Bundle包名,例如”com.emas.test”MAVEN_ARTIFACTID 一般取Bundle名字,保证唯一性即可 例如”mybundle”

  1. #### SDK中心仓库
  2. SDK_REPOSITORY_URL = http://nexus-ce.emas-poc.com/repository/maven-public/
  3. SDK_REPOSITORY_USERNAME = developer
  4. SDK_REPOSITORY_PASSWORD = fT&iXg$16jIh##yL
  5. #### 产物仓库
  6. CUSTOM_REPOSITORY_HOST = nexus.emas-ha.cn:8081
  7. CUSTOM_REPOSITORY_USERNAME = developer
  8. CUSTOM_REPOSITORY_PASSWORD = RSs6KfAdXJOrA6rx
  9. #### 发布坐标
  10. MAVEN_GROUP = xxx.xxx.xxx
  11. MAVEN_ARTIFACTID = xxx

5.4 修改build.gradle

修改文件位置: module目录的build.gradle文件(如上图的:mylibrary/build.gradle)

修改文件内容:atlas bundle配置及发布脚本。

拷贝以下内容build.gradle:

  1. apply plugin: 'com.taobao.atlas'
  2. apply plugin: 'maven-publish'
  3. atlas.bundleConfig.awbBundle = true
  4. def emas_version_name = getEnvValue('EMAS_VERSION_NAME', "1.0.0-SNAPSHOT")
  5. String getEnvValue(key, defValue) {
  6. def val = System.getProperty(key);
  7. if (null != val) {
  8. return val;
  9. }
  10. val = System.getenv(key);
  11. if (null != val) {
  12. return val;
  13. }
  14. return defValue;
  15. }
  16. group = MAVEN_GROUP
  17. version = emas_version_name
  18. task sourcesJar(type: Jar) {
  19. from('src/main/java') {
  20. include '**'
  21. }
  22. classifier = 'sources'
  23. }
  24. publishing {
  25. publications {
  26. maven(MavenPublication) {
  27. if (project.gradle.startParameter.toString().contains("assembleDebug")) {
  28. artifact "${project.buildDir}/outputs/awb/${project.name}-debug.awb"
  29. artifactId MAVEN_ARTIFACTID
  30. } else {
  31. artifact "${project.buildDir}/outputs/awb/${project.name}-release.awb"
  32. artifactId MAVEN_ARTIFACTID
  33. }
  34. artifact sourcesJar
  35. pom.withXml {
  36. def dependenciesNode = asNode().appendNode('dependencies')
  37. configurations.compile.allDependencies.each {
  38. if (it.group != null && (it.name != null || "unspecified" == it.name) && it.version != null) {
  39. def dependencyNode = dependenciesNode.appendNode('dependency')
  40. dependencyNode.appendNode('groupId', it.group)
  41. dependencyNode.appendNode('artifactId', it.name)
  42. dependencyNode.appendNode('version', it.version)
  43. }
  44. }
  45. }
  46. }
  47. }
  48. repositories {
  49. if (version.endsWith("-SNAPSHOT")) {
  50. maven {
  51. url "http://" + CUSTOM_REPOSITORY_HOST + "/repository/maven-snapshots/"
  52. credentials {
  53. username = CUSTOM_REPOSITORY_USERNAME
  54. password = CUSTOM_REPOSITORY_PASSWORD
  55. }
  56. }
  57. } else {
  58. maven {
  59. url "http://" + CUSTOM_REPOSITORY_HOST + "/repository/maven-releases"
  60. credentials {
  61. username = CUSTOM_REPOSITORY_USERNAME
  62. password = CUSTOM_REPOSITORY_PASSWORD
  63. }
  64. }
  65. }
  66. }
  67. }

5.5 Bundle构建及发布

本地工程构建及发布指令:./gradlew assembleRelease publish

通过平台构建指引:https://help.aliyun.com/document_detail/66901.html?spm=a2c4g.11186623.4.1.xRWFM9

七、混淆配置

混淆配置参考Demo progurad.cfg文件

Demo git地址:

http://gitlab.emas-ha.cn/EMAS-Android/Android-EMAS-Demo master分支

账号/密码:POCExperience/jkHHliks#al

八、Q&A

  • 问题1

    1. /Users/jason/android/TempTestDemo/app/src/main/AndroidManifest.xml:6:9-35 Error:
    2. Attribute application@allowBackup value=(true) from AndroidManifest.xml:6:9-35
    3. is also present at [com.taobao.android:open-update-aar:5.6.5-emax-SNAPSHOT] AndroidManifest.xml:13:9-36 value=(false).
    4. Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:5:5-19:19 to override.
  • 解决方法:

    在AndroidManifest.xml里manifest标签里加入xmlns:tools=”http://schemas.android.com/tools“application标签里加入tools:replace=”android:allowBackup”

  • 问题2:

    接入atlas后怎么确认altas正常接入?

  • 解决方法:

    (1)debug包有BridgeApplication 日志

    (2)反编译apk, menifest里面application被替换为了android.taobao.atlas.startup.AtlasBridgeApplication

  • 问题3:

    1. UNEXPECTED TOP-LEVEL EXCEPTION:
    2. java.lang.RuntimeException: Exception parsing classes
    3. at com.android.dx.command.dexer.Main.processClass(Main.java:781)
    4. at com.android.dx.command.dexer.Main.processFileBytes(Main.java:747)
    5. at com.android.dx.command.dexer.Main.access$1200(Main.java:88)
    6. at com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1689)
    7. at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
    8. at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
    9. at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
    10. at com.android.dx.command.dexer.Main.processOne(Main.java:695)
    11. at com.android.dx.command.dexer.Main.processAllFiles(Main.java:592)
    12. at com.android.dx.command.dexer.Main.runMonoDex(Main.java:321)
    13. at com.android.dx.command.dexer.Main.run(Main.java:292)
    14. at com.android.builder.internal.compiler.DexWrapper.run(DexWrapper.java:54)
    15. at com.android.builder.core.DexByteCodeConverter.lambda$dexInProcess$0(DexByteCodeConverter.java:174)
    16. at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    17. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    18. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    19. at java.lang.Thread.run(Thread.java:745)
  • 解决方案:

    gradle脚本andorid标签中加入以下配置

    1. android {
    2. xxx

    3. dexOptions {
    4. javaMaxHeapSize = '2048m'
    5. additionalParameters=["--no-strict"]}
    6. }