全部产品
云市场

Android接入

更新时间:2019-09-25 10:26:43

本文档为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.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:3.0.0”(注:如仍使用gradle4.0以下环境,emas插件请使用1.7.2-SNAPSHOT)示例

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

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

  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、 加入Gradle官方配置

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

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

文件内容

  1. android.enableBuildCache=true
  2. #org.gradle.daemon=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.3-open@jar') { transitive false }
    10. compile('com.taobao.android:update-common:1.0.3-open@aar') { transitive false }
    11. compile('com.taobao.android:update-manager:1.0.3-open@aar') { transitive false }
    12. compile('com.taobao.android:update-adapter:1.0.3-open@jar') { transitive false }
    13. compile('com.taobao.android:update-main:1.0.3-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.6.12-open') {
    53. exclude group: 'com.taobao.android', module: 'networksdk'
    54. transitive true

    }

    1. /************通道服务 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. <provider
  23. android:name="com.taobao.update.provider.UpdateProvider"
  24. android:authorities="${applicationId}.update.provider"
  25. android:exported="false"
  26. android:grantUriPermissions="true">
  27. <meta-data
  28. android:name="android.support.FILE_PROVIDER_PATHS"
  29. android:resource="@xml/apk_paths" />
  30. </provider>
  31. <!-- UPDATE SDK END -->

2、res/xml目录加入apk_paths.xml文件,文件内容

  1. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  2. <external-cache-path name="external_apk_update" path="apkupdate/" />
  3. <cache-path name="apk_update" path="apkupdate/" />
  4. <root-path name="root_apk_update" path ="storage/"/>
  5. </paths>

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

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

示例代码

  1. private String mAppkey = "10000032";
  2. private String mAppSecret = "11e929a1bc36382fcfe613a2aae5cf02";
  3. private String mZcachePrefix = "http://cdn.emas-poc.com/eweex/";
  4. private String mAccsHost = "accs.emas-poc.com";
  5. private Map<String, String> mIPStrategy; //一般无需设置
  6. private String mMtopHost = "aserver.emas-poc.com";
  7. private String mAdashHost = "adash.emas-poc.com";
  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;

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

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

四、开启ATLAS(可选)

注:仅emas-plugin 2.1.3以下版本支持ATLAS, 3.0.0+版本后不再支持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.1.0.9-rc7-fix3@aar') { transitive true }/****注:如使用gradle4.0以下环境atlas_core请仍使用5.0.8.0版本****/
  3. compile("com.taobao.android:open-update-aar:1.0.2-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)

修改文件内容:加入以下配置

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

  1. atlas.atlasEnabled=true
  2. atlas.patchConfigs.debug.appSignName = [appkey]@android
  3. atlas.patchConfigs.release.appSignName = [appkey]@android
  4. atlas.enhanceConfigs.debug.enabled=false
  5. atlas.enhanceConfigs.release.enabled=false
  6. #构建配置
  7. atlas.tBuildConfig.appCoordinate = [groupId]:[artifactId]
  8. atlas.tBuildConfig.fastProguard=true
  9. atlas.tBuildConfig.atlasMultiDex=true
  10. atlas.tBuildConfig.mergeOverride=false
  11. atlas.tBuildConfig.autoStartBundles=xxx
  12. atlas.tBuildConfig.classInject=false
  13. atlas.multiDexConfigs.debug.fastMultiDex=true
  14. atlas.multiDexConfigs.release.fastMultiDex=true
  15. #构建渠道包开关
  16. atlas.atlasChannelConfigs.debug.enabled=false
  17. 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. }