阿里热修复之Sophix——专有云
应公司业务需求,和阿里云的阿里热修复相关技术人员合作,整了波专有云的热修复集成Demo
一、app/build.gradle下的代码
注意:第二行的代码在集成中要开启的,这里注释掉是为让app可以本地run起来看到界面
apply plugin: 'com.android.application'
//调试无法安装时注释掉这行
//apply plugin: 'com.taobao.sophix.emas'
configurations {
providedCompile
all*.exclude group: 'com.taobao.android', module: 'tnet-jni'
all*.exclude group: 'com.taobao.android', module: 'tlog_adapter'
all*.exclude group: 'com.aliyun.ams', module:'alicloud-android-utdid'
all*.exclude group: 'com.aliyun.ams', module: 'alicloud-android-ut'
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(0, 'SECONDS')
cacheChangingModulesFor(0, 'SECONDS')
}
}
//task wrapper(type: Wrapper) {
// gradleVersion = '4.1'
// distributionUrl = 'http://emas-deploy.oss-cn-hangzhou.aliyuncs.com/gradle-4.1-all.zip'
//}
//tasks.whenTaskAdded { task ->
// if (task.name.contains("DebugAndroidTest")) {
// task.setEnabled(false);
// }
//}
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.dotawang.sophixemasdemo"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'arm64-v8a'
}
//语言类型
resConfigs "en", "fr"
}
dexOptions{
javaMaxHeapSize = '2048m'
additionalParameters=["--no-strict"]
}
sourceSets {
main {
jniLibs.srcDirs = ['jniLibs']
}
}
signingConfigs {
releaseConfig {
storeFile file("release.keystore")
storePassword "hschyf"
keyAlias "hswinner"
keyPassword "hschyf"
}
debugConfig {
storeFile file("release.keystore")
storePassword "hschyf"
keyAlias "hswinner"
keyPassword "hschyf"
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.releaseConfig
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// signingConfig signingConfigs.debugConfig
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
compile 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support:design:26.1.0'
compile 'com.squareup.picasso:picasso:2.5.2'
//出现Error:Execution failed for task ':app:preDebugAndroidTestBuild'的解决方法
androidTestCompile('com.android.support:support-annotations:26.1.0') {
force = true
}
compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.4'
compile('com.emas.lib:emas-core:1.0.11-SNAPSHOT@aar') { transitive true }
/************基础库 START**********/
compile('com.alibaba:fastjson:1.1.54.android@jar') { transitive true }
compile('com.taobao.android:mtopsdk_allinone:3.0.6.4-open@jar') { transitive true }
compile('com.taobao.android:networksdk:3.3.5-open@jar') { transitive true }
compile('com.taobao.android:tnet4android:3.1.14.6@aar') { transitive true }
compile('com.taobao.android:utdid4all:1.1.5.3_proguard@jar') { transitive true }
/************基础库 END**********/
/************高可用 SDK START**********/
compile('com.taobao.android:accs_sdk_taobao:3.3.3.1-open') { transitive true }
compile('com.taobao.android:ut-analytics:1.1.0.1-open@aar') { transitive true }
compile('com.alibaba.ha:alihatbadapter:1.1.0.3-open@aar') {
transitive true
//exclude group:'com.taobao.android', module:'tlog_uploader_oss'
}
//compile ('com.taobao.android:tlog_uploader_ceph:1.1.0.3-open@aar')
//默认oss通道需要依赖oss的三方库
compile ('com.squareup.okhttp3:okhttp:3.4.1@jar')
compile ('com.squareup.okio:okio:1.9.0@jar')
compile ('com.aliyun.dpa:oss-android-sdk:2.4.2@aar')
/************高可用 SDK END**********/
}
//Sophix
apply from: 'common.gradle'
group = "com.dotawang.sophixemasdemo"//包名
version = android.defaultConfig.versionName + '-SNAPSHOT'
apply plugin: 'maven'
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
if (project.gradle.startParameter.toString().contains("Debug")) {
artifact "${project.buildDir}/sophix/${project.name}-debug.sar"
artifactId "sar-debug"
} else {
artifact "${project.buildDir}/sophix/${project.name}-release.sar"
artifactId "sar-release"
}
}
}
repositories {
if (version.endsWith("-SNAPSHOT")) {
maven {
url "http://nexus.emas-ha.cn:8081/repository/maven-snapshots/"
credentials {
username = CUSTOM_REPOSITORY_USERNAME
password = CUSTOM_REPOSITORY_PASSWORD
}
}
} else {
maven {
url "http://nexus.emas-ha.cn:8081/repository/maven-releases/"
credentials {
username = CUSTOM_REPOSITORY_USERNAME
password = CUSTOM_REPOSITORY_PASSWORD
}
}
}
}
}
二、在项目的app文件夹下创建个common.gradle的文件,位置如下图:
common.gradle的代码如下:
def emas_version_name = getEnvValue('EMAS_VERSION_NAME')
def emas_version_code = getEnvValue('EMAS_VERSION_CODE')
def emas_base_version = getEnvValue('EMAS_BASE_VERSION')
if (emas_version_code) {
android.defaultConfig.versionCode = emas_version_code.toInteger()
println("emas_version_code=" + emas_version_code)
}
if (emas_base_version) {
println("emas_base_version=" + emas_base_version)
}
if (emas_version_name) {
android.defaultConfig.versionName = emas_version_name
println("emas_version_name=" + emas_version_name)
}
String getEnvValue(key) {
return getEnvValue(key, null)
}
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
}
三、proguard-rules.pro混淆的代码
#基线包使用,生成mapping.txt
-printmapping mapping.txt
#生成的mapping.txt在app/build/outputs/mapping/release路径下,移动到/app路径下
#修复后的项目使用,保证混淆结果一致
#-applymapping mapping.txt
#hotfix
-keep class com.taobao.sophix.**{*;}
-keep class com.ta.utdid2.device.**{*;}
#防止inline
-dontoptimize
-keepclassmembers class com.dotawang.sophixemasdemo.WinnerApplication {
public <init>();
}
-keep class com.dotawang.sophixemasdemo.SophixStubApplication$RealApplicationStub
-dontpreverify
-dontusemixedcaseclassnames
-optimizations code/removal/simple,code/removal/advanced,code/removal/variable,code/removal/exception,code/simplification/branch,code/simplification/field,code/simplification/cast,code/simplification/arithmetic,code/simplification/variable
-keepattributes Exceptions,InnerClasses,Signature,SourceFile,LineNumberTable,*Annotation*
-renamesourcefileattribute Taobao
-allowaccessmodification
-optimizationpasses 1
#防止inline
-dontoptimize
-target 1.6
#-verbose
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.**
-dontwarn com.android.volley.toolbox.**
-dontwarn com.facebook.infer.**
-dontwarn org.mozilla.javascript.**
-dontwarn org.mozilla.classfile.**
-dontwarn java.awt.**
-dontwarn com.taobao.**
-dontwarn com.google.android.maps.**
-dontwarn android.support.v7.widget.**
-dontwarn android.support.v4.**
-dontwarn com.tencent.mm.sdk.**
-dontwarn org.android.agoo.**
-dontwarn com.amap.api.**
-dontwarn com.autonavi.amap.**
-dontwarn com.ut.**
-dontwarn com.robotium.**
-dontwarn com.alibaba.fastjson.**
-dontwarn android.taobao.**
-dontwarn com.alibaba.mobileim.**
-dontwarn com.autonavi.**
-dontwarn com.amap.**
-dontwarn ***
#############公共的混淆keep选项, 可删除与工程中有重复部分 #############
-keep class * extends android.app.Application
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class com.google.inject.Binder
-keepclassmembers class * {
@com.google.inject.Inject <init>(...);
}
# There's no way to keep all @Observes methods, so use the On*Event convention to identify event handlers
-keepclassmembers class * {
void *(**On*Event);
}
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keep public class roboguice.**
-keep class rx.**{*;}
# 为了atlas注入
-keepclassmembers class ** {
private <init>(...);
public <init>(...);
<init>(...);
}
-keepclassmembernames class **.R$* {*;}
-keepclassmembernames class **.R {*;}
-keepclassmembers class **{
public static final <fields>;
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
-keepclassmembers class * {
public static ** asInterface(***);
}
-keepclassmembers class ** {
public void onEvent*(***);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(...);
**[] $VALUES;
}
-keepclasseswithmembernames class * {
native <methods>;
}
# Keep native methods
-keepclassmembers class * {
native <methods>;
}
-keepclassmembers class * implements java.io.Serializable {
public <fields>;
public <methods>;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keep class * implements android.os.Parcelable {
public <fields>;
public <methods>;
public static final android.os.Parcelable$Creator *;
}
#############公共的混淆keep选项, 可删除与工程中有重复部分 #############
##########################基础库##########################
#fastjson
-keep class com.alibaba.fastjson.** {*;}
#tnet
#-keepclasseswithmembernames class org.android.spdy.** {
# native <methods>;
#}
-keep public class org.android.spdy.**{*;}
#mtop
-keep class anetwork.network.cache.**{*;}
-keep class com.taobao.tao.remotebusiness.**{*;}
-keep class mtopsdk.**{*;}
#network
-keep class anet.channel.**{*;}
-keep class anetwork.channel.**{*;}
##########################基础库##########################
##########################高可用##########################
#keep ha alihatbadapter
-keep class com.alibaba.ha.**{*;}
-keep class com.taobao.tlog.**{*;}
#keep ha utdid
-keep class com.ut.device.**{*;}
-keep class com.ta.utdid2.device.**{*;}
#keep ha ut
-keep public class com.alibaba.mtl.** { *;}
-keep public class com.ut.mini.** { *;}
#keep ha crashreporter
-keep class com.alibaba.motu.crashreporter.**{ *;}
-keep class com.uc.crashsdk.**{*;}
#keep ha telescope
-keep class com.ali.telescope.**{ *;}
-keep class libcore.io.**{*;}
-keep class android.app.**{*;}
-keep class dalvik.system.**{*;}
#keep ha tlog
-keep class com.taobao.tao.log.**{*;}
-keep class com.taobao.android.tlog.**{*;}
#keep tbrest
-keep class com.alibaba.motu.**{*;}
##########################高可用##########################
###########################远程配置##########################
-keep class com.taobao.orange.**{*;}
###########################远程配置##########################
###########################其他##########################
-keep class sun.misc.Unsafe { *; }
-keep class com.alibaba.** {*;}
#关闭日志
#-assumenosideeffects class android.util.Log {
# public static boolean isLoggable(java.lang.String, int);
# public static int v(...);
# public static int w(...);
# public static int d(...);
# public static int i(...);
#}
#-assumenosideeffects class java.lang.Throwable {
# public void printStackTrace();
#}
-keep public class android.support.design.widget.BottomNavigationView { *; }
-keep public class android.support.design.internal.BottomNavigationMenuView { *; }
-keep public class android.support.design.internal.BottomNavigationPresenter { *; }
-keep public class android.support.design.internal.BottomNavigationItemView { *; }
###########################其他##########################
## 去除BottomNavigationView的tab大于三个的时候的切换效果
-keepclassmembers class android.support.design.internal.BottomNavigationMenuView {
boolean mShiftingMode;
}
四、项目下的build.gradle代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenLocal()
maven {
url SDK_REPOSITORY_URL
credentials {
username = SDK_REPOSITORY_USERNAME
password = SDK_REPOSITORY_PASSWORD
}
}
maven { url "http://maven.aliyun.com/nexus/content/repositories/google/"}
maven { url "http://maven.aliyun.com/nexus/content/repositories/releases/"}
maven { url "http://maven.aliyun.com/nexus/content/groups/public/"}
maven { url "http://nexus.emas-ha.cn:8081/repository/maven-releases/" }
maven { url "http://nexus.emas-ha.cn:8081/repository/maven-snapshots/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.taobao.android:sophix-emas-plugin:0.5.10-SNAPSHOT'//Sophix
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
url SDK_REPOSITORY_URL
credentials {
//SDK中心仓库
username = SDK_REPOSITORY_USERNAME
password = SDK_REPOSITORY_PASSWORD
}
}
maven { url "http://maven.aliyun.com/nexus/content/repositories/google/"}
maven { url "http://maven.aliyun.com/nexus/content/repositories/releases/"}
maven { url "http://maven.aliyun.com/nexus/content/groups/public/"}
maven { url "http://nexus.emas-ha.cn:8081/repository/maven-releases/" }
maven { url "http://nexus.emas-ha.cn:8081/repository/maven-snapshots/" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
五、gradle.properties的代码中加入下面代码
注意:这里代码主要是用来配置sdk仓库和产物仓库的2组账号密码
#SDK中心仓库
SDK_REPOSITORY_URL = http://nexus-ce.emas-poc.com/repository/maven-public/
SDK_REPOSITORY_USERNAME = developer
SDK_REPOSITORY_PASSWORD = fT&iXg$16jIh##yL
#产物仓库
CUSTOM_REPOSITORY_HOST = nexus.emas-ha.cn:8081
CUSTOM_REPOSITORY_USERNAME = developer
CUSTOM_REPOSITORY_PASSWORD = RSs6KfAdXJOrA6rx
六、各大界面的代码
1)MainActivity的布局xml代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_gravity="center"
tools:context="com.dotawang.sophixemasdemo.MainActivity">
<ImageView
android:id="@+id/iv"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center"
android:layout_width="200dp"
android:layout_height="200dp" />
<TextView
android:id="@+id/tv1"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="补丁内容修改"
android:layout_gravity="center"
android:gravity="center"/>
<Button
android:id="@+id/bt_crash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="崩溃"
android:layout_gravity="center"
android:gravity="center"/>
<Button
android:id="@+id/bt_ca"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="线程卡顿"
android:layout_gravity="center"
android:gravity="center"/>
<Button
android:id="@+id/bt_query"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拉取补丁"
android:layout_gravity="center"
android:gravity="center" />
<TextView
android:id="@+id/tv_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
</LinearLayout>
2)MainActivity的界面代码
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import com.taobao.sophix.SophixManager;
/**
1、AndroidManifest不支持
2、build 基础依赖包升级不支持
3、导入sophix插件,无法直接打包
*/
public class MainActivity extends Activity {
private ImageView imageView;
private TextView textView;
private TextView tv_code;
private Button bt_crash,bt_ca,bt_query;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initListener();
initThread();
}
private void initThread() {
updata(SophixStubApplication.cacheMsg.toString());
SophixStubApplication.msgDisplayListener = new SophixStubApplication.MsgDisplayListener() {
@Override
public void handle(final String msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
updata(msg);
}
});
}
};
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 请求补丁
SophixManager.getInstance().queryAndLoadNewPatch();
handler.postDelayed(this, 10 * 1000);
}
}, 1 * 1000);
}
private void updata(String cacheMsg) {
if (cacheMsg != null){
tv_code.setText(cacheMsg);
}
}
private void initListener() {
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//1、ic_launcher
//2、https://i.loli.net/2018/09/12/5b9881e9ed5e8.jpg
//3、test本地
Picasso.with(MainActivity.this).load("https://i.loli.net/2018/09/12/5b9881e9ed5e8.jpg").into(imageView);
}
});
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textView.setText("修复1");
//textView.setText("修复2");
//textView.setText("修复3");
}
});
bt_crash.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
throw new RuntimeException();
}
});
bt_ca.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try{
Thread.sleep(20*1000);
}catch (Exception e){
e.printStackTrace();
}
}
});
bt_query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SophixManager.getInstance().queryAndLoadNewPatch();
}
});
}
private void initData() {
imageView = findViewById(R.id.iv);
textView = findViewById(R.id.tv1);
tv_code = findViewById(R.id.tv_code);
bt_crash = findViewById(R.id.bt_crash);
bt_ca = findViewById(R.id.bt_ca);
bt_query = findViewById(R.id.bt_query);
}
}
3)SophixStubApplication的代码
import android.content.Context;
import android.support.annotation.Keep;
import android.util.Log;
import com.taobao.sophix.PatchStatus;
import com.taobao.sophix.SophixApplication;
import com.taobao.sophix.SophixEntry;
import com.taobao.sophix.SophixManager;
import com.taobao.sophix.listener.PatchLoadStatusListener;
/**
* Created on 2018/9/12
* Title:
* Description:
*
* @author Android-汪洋
* update 2018/9/12
*/
public class SophixStubApplication extends SophixApplication {
private final String TAG = "SophixStubApplication";
// 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。
@Keep
@SophixEntry(WinnerApplication.class)
static class RealApplicationStub {}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// 如果需要使用MultiDex,需要在此处调用。
// MultiDex.install(this);
initSophix();
}
private void initSophix() {
String appVersion = "0.0.0";
try {
appVersion = this.getPackageManager()
.getPackageInfo(this.getPackageName(), 0)
.versionName;
} catch (Exception e) {
}
final SophixManager instance = SophixManager.getInstance();
instance.setContext(this)
.setAppVersion(appVersion)
//host 域名
.setHost("hotfix-gate.emas-poc.com", false)
.setEnableDebug(true)
.setEnableFullLog()
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
String msg = new StringBuilder("").append("Mode:").append(mode)
.append(" Code:").append(code)
.append(" Info:").append(info)
.append(" HandlePatchVersion:").append(handlePatchVersion).toString();
if (msgDisplayListener != null) {
msgDisplayListener.handle(msg);
} else {
cacheMsg.append("\n").append(msg);
}
if (code == PatchStatus.CODE_LOAD_SUCCESS) {
Log.i(TAG, "sophix load patch success!");
} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
// 如果需要在后台重启,建议此处用SharePreference保存状态。
Log.i(TAG, "sophix preload patch success. restart app to make effect.");
}
}
}).initialize();
}
public interface MsgDisplayListener {
void handle(String msg);
}
public static MsgDisplayListener msgDisplayListener = null;
public static StringBuilder cacheMsg = new StringBuilder();
}
4)WinnerApplication的代码
import android.app.Application;
import com.taobao.sophix.SophixManager;
/**
* Created on 2018/9/12
* Title:
* Description:
*
* @author Android-汪洋
* update 2018/9/12
*/
public class WinnerApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
EmasInit emas = EmasInit.getInstance().setmApplication(this);
emas.initHA();
SophixManager.getInstance().queryAndLoadNewPatch();
}
}
5)EmasInit的代码
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.Log;
import com.alibaba.ha.adapter.AliHaAdapter;
import com.alibaba.ha.adapter.AliHaConfig;
import com.alibaba.ha.adapter.Plugin;
import com.alibaba.ha.adapter.Sampling;
import com.taobao.accs.ACCSClient;
import com.taobao.accs.ACCSManager;
import com.taobao.accs.AccsClientConfig;
import com.taobao.accs.AccsException;
import com.taobao.accs.IAppReceiver;
import com.taobao.accs.common.Constants;
import com.taobao.accs.utl.ALog;
import org.android.spdy.SpdyProtocol;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import anet.channel.AwcnConfig;
import anet.channel.SessionCenter;
import anet.channel.strategy.ConnEvent;
import anet.channel.strategy.ConnProtocol;
import anet.channel.strategy.IConnStrategy;
import anet.channel.strategy.IStrategyInstance;
import anet.channel.strategy.IStrategyListener;
import anet.channel.strategy.StrategyCenter;
import anet.channel.strategy.dispatch.HttpDispatcher;
import anetwork.channel.config.NetworkConfigCenter;
import anetwork.channel.http.NetworkSdkSetting;
import mtopsdk.common.util.TBSdkLog;
import mtopsdk.mtop.global.SwitchConfig;
import mtopsdk.mtop.intf.Mtop;
import mtopsdk.mtop.intf.MtopEnablePropertyType;
import mtopsdk.mtop.intf.MtopSetting;
import mtopsdk.security.LocalInnerSignImpl;
/**
* Created by jason on 18/1/15.
*/
public class EmasInit {
public static final int DEBUG = 1; //测试环境
public static final int RELEASE = 2; //发布环境
/*配置信息*/
protected String mAppkey = "20000297";//"10000066";//"10000039";//"10000078";//"60039748";
protected String mAppSecret = "53b92bd7eb29931ab25580506285c9b8";//"1426c10c5ce57d6cb29e016a816421a7";//"c7795717b2306055f21fb33418c1d011";//"2e00a7e9ab2048daabd4977170d37c4a";//"ab5ff148782b467bb0b310c4acd70abd"//"fe240d4b8f4b31283863cc9d707e2cb1"
protected String mCacheURL = "http://cdn.emas-poc.com/eweex/";
protected String mACCSDoman = "accs.emas-poc.com";
protected Map<String, String> mIPStrategy;
protected String mMTOPDoman = "aserver.emas-poc.com";
protected String mHAUniversalHost = "adash.emas-poc.com";
protected String mHAOSSBucketName = "emas-ha-remote-log-poc";
protected String mHARSAPublicKey;
protected String mStartActivity = "com.taobao.demo.WelcomActivity";
protected String mChannelID = "1001@DemoApp_Android_" + BuildConfig.VERSION_NAME;
protected String PUSH_TAG = "POC";
protected boolean mUseHttp = true;
protected int mEnv = DEBUG;
private Application mApplication;
private static final String TAG = "EmasInit";
public final static String SERVICE_ID = "4272_mock";
//private static final String[] TEST_EMAS = new String[]{"acs.alibaba-inc.com", "11.163.130.35", "80"};
private final static Map<String, String> SERVICES = new HashMap<String, String>() {
private static final long serialVersionUID = 2527336442338823324L;
{
//自定义服务
put(SERVICE_ID, "com.taobao.demo.accs.TestAccsService");
}
};
/**
* 切换成单例
*/
private static class CreateInstance {
private static EmasInit instance = new EmasInit();
}
public static EmasInit getInstance() {
return CreateInstance.instance;
}
private EmasInit() {
//不能生成对象
}
//先设置mApplication
public EmasInit setmApplication(Application application) {
this.mApplication = application;
//初始化
firstInit();
return this;
}
private void firstInit() {
Application application = mApplication;
StringBuilder builder = new StringBuilder();
try {
int id = application.getResources().getIdentifier("ttid", "string", application.getPackageName());
if (id > 0) {
mChannelID = builder.append(application.getString(id))
.append("@")
.append(application.getResources().getString(application.getApplicationInfo().labelRes))
.append("_")
.append("Android")
.append("_")
.append(BuildConfig.VERSION_NAME).toString();
}
} catch (Resources.NotFoundException e) {
Log.d(TAG, "no channel id in res" + e.toString());
}
}
/********************UPDATE SDK START **************************/
private void initMtop() {
if (mEnv == DEBUG) {
TBSdkLog.setTLogEnabled(false);
TBSdkLog.setLogEnable(TBSdkLog.LogEnable.DebugEnable);
}
//关闭密文
if (mUseHttp) {
NetworkConfigCenter.setSSLEnabled(false);
}
//[option]关闭MTOP请求长链,调用后Mtop请求直接调用NetworkSDK的HttpNetwork发请求
SwitchConfig.getInstance().setGlobalSpdySwitchOpen(false);
//关闭MTOPSDK NewDeviceID逻辑
MtopSetting.setEnableProperty(Mtop.Id.INNER, MtopEnablePropertyType.ENABLE_NEW_DEVICE_ID, false);
//设置自定义全局访问域名
MtopSetting.setMtopDomain(Mtop.Id.INNER, mMTOPDoman, mMTOPDoman, mMTOPDoman);
//设置自定义签名使用的appKey和appSecret
MtopSetting.setISignImpl(Mtop.Id.INNER, new LocalInnerSignImpl(mAppkey, mAppSecret));
MtopSetting.setAppVersion(Mtop.Id.INNER, BuildConfig.VERSION_NAME);
Mtop mtopInstance = Mtop.instance(Mtop.Id.INNER, mApplication.getApplicationContext(), mChannelID);
}
/********************UPDATE SDK END **************************/
/********************HA SDK START **************************/
public void initHA() {
//开启
if (mEnv == DEBUG) {
AliHaAdapter.getInstance().openDebug(true);
}
AliHaAdapter.getInstance().changeHost(mHAUniversalHost);
AliHaAdapter.getInstance().tLogService.changeRemoteDebugHost(mHAUniversalHost);
AliHaAdapter.getInstance().tLogService.changeRemoteDebugOssBucket(mHAOSSBucketName);
if (!TextUtils.isEmpty(mHARSAPublicKey)) {
AliHaAdapter.getInstance().tLogService.changeRasPublishKey(mHARSAPublicKey);
}
initHACrashreporterAndUt();
AliHaAdapter.getInstance().openHttp(mUseHttp);
initAccs();
AliHaAdapter.getInstance().removePugin(Plugin.crashreporter); //tlog 依赖accs
AliHaAdapter.getInstance().removePugin(Plugin.ut);
AliHaAdapter.getInstance().telescopeService.setBootPath(new String[]{mStartActivity}, System.currentTimeMillis());
AliHaAdapter.getInstance().start(buildAliHaConfig());
}
private AliHaConfig buildAliHaConfig() {
//ha初始化
AliHaConfig config = new AliHaConfig();
config.isAliyunos = false;
config.appKey = mAppkey;
config.userNick = "you need set user name";
config.channel = mChannelID;
config.appVersion = BuildConfig.VERSION_NAME;
config.application = mApplication;
config.context = mApplication;
return config;
}
private void initHACrashreporterAndUt() {
AliHaAdapter.getInstance().startWithPlugin(buildAliHaConfig(), Plugin.crashreporter);
AliHaAdapter.getInstance().startWithPlugin(buildAliHaConfig(), Plugin.ut);
AliHaAdapter.getInstance().utAppMonitor.changeSampling(Sampling.All);
}
private void initAccs() {
if (mIPStrategy != null && mIPStrategy.size() > 0) {
initNetwork();
}
boolean isDebug = ((mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
if (isDebug) { //debug版本, 打开日志开关, 方便排查问题
ALog.setUseTlog(false);
anet.channel.util.ALog.setUseTlog(false);
}
new Thread() { //建议异步进行初始化
@Override
public void run() {
int env = Constants.RELEASE;
int pubkey = SpdyProtocol.PUBKEY_PSEQ_EMAS;//SpdyProtocol.PUBKEY_SEQ_TEST
String appkey = mAppkey;//"4272"
String appsecret = mAppSecret;//"257461a8005f538382640d4894dd193a04d18e1b4a7a5ee214b6d660778d3943"
String emasHost = mACCSDoman;
SharedPreferences sp = mApplication.getSharedPreferences("emas_accs", Context.MODE_PRIVATE);
String key = sp.getString("appkey", null);
String secret = sp.getString("appsecret", null);
appkey = TextUtils.isEmpty(key) ? appkey : key;
appsecret = TextUtils.isEmpty(secret) ? appsecret : secret;
try {
ACCSManager.setAppkey(mApplication.getApplicationContext(), mAppkey, env);//兼容老接口 如果有任意地方使用老接口,必须setAppkey
NetworkSdkSetting.init(mApplication.getApplicationContext());
//关闭AMDC请求
HttpDispatcher.getInstance().setEnable(false);
ACCSClient.setEnvironment(mApplication.getApplicationContext(), env);
AwcnConfig.setAccsSessionCreateForbiddenInBg(false);
AccsClientConfig clientConfig = new AccsClientConfig.Builder()
.setAppKey(appkey)
.setAppSecret(appsecret)
.setInappHost(emasHost)
.setInappPubKey(pubkey)
.setTag(AccsClientConfig.DEFAULT_CONFIGTAG)
.setConfigEnv(env)
.build();
ACCSClient.init(mApplication, clientConfig);
ACCSClient.getAccsClient(AccsClientConfig.DEFAULT_CONFIGTAG).bindApp(mChannelID, mAppReceiver);
} catch (AccsException e) {
ALog.w(TAG, "initDefaultAccs", e);
}
}
}.start();
}
private IAppReceiver mAppReceiver = new IAppReceiver() {
private String TAG = "mAppReceiver";
@Override
public void onBindApp(int errorCode) {
ALog.i(TAG, "onBindApp", "errorCode", errorCode);
try {
ACCSClient.getAccsClient(AccsClientConfig.DEFAULT_CONFIGTAG).bindUser("123324234");
} catch (AccsException e) {
e.printStackTrace();
}
}
@Override
public void onUnbindApp(int errorCode) {
ALog.i(TAG, "onUnbindApp", "errorCode", errorCode);
}
@Override
public void onBindUser(String userId, int errorCode) {
ALog.i(TAG, "onBindUser", "errorCode", errorCode);
}
@Override
public void onUnbindUser(int errorCode) {
ALog.i(TAG, "onUnbindUser", "errorCode", errorCode);
}
@Override
public void onSendData(String dataId, int errorCode) {
ALog.i(TAG, "onSendData");
}
@Override
public void onData(String userId, String dataId, byte[] data) {
ALog.i(TAG, "onData");
}
@Override
public String getService(String serviceId) {
String service = SERVICES.get(serviceId);
return service;
}
@Override
public Map<String, String> getAllServices() {
return SERVICES;
}
};
private void initNetwork() {
SessionCenter.init(mApplication);
final IStrategyInstance instance = StrategyCenter.getInstance();
StrategyCenter.setInstance(new IStrategyInstance() {
@Override
public void initialize(Context context) {
instance.initialize(context);
}
@Override
public void switchEnv() {
instance.switchEnv();
}
@Override
public void saveData() {
instance.saveData();
}
@Override
public String getFormalizeUrl(String rawUrlString) {
return instance.getFormalizeUrl(rawUrlString);
}
@Override
public List<IConnStrategy> getConnStrategyListByHost(String host) {
String strategy = mIPStrategy.get(host);
if (TextUtils.isEmpty(strategy)) {
return instance.getConnStrategyListByHost(host);
}
final String[] ipPort = strategy.split(":");
List<IConnStrategy> list = new ArrayList<IConnStrategy>();
IConnStrategy connStrategy = new IConnStrategy() {
@Override
public String getIp() {
return ipPort[0];
}
@Override
public int getIpType() {
return 0;
}
@Override
public int getIpSource() {
return 0;
}
@Override
public int getPort() {
return Integer.parseInt(ipPort[1]);
}
@Override
public ConnProtocol getProtocol() {
return ConnProtocol.valueOf("http2", "0rtt", "emas", false);
}
@Override
public int getConnectionTimeout() {
return 10000;
}
@Override
public int getReadTimeout() {
return 10000;
}
@Override
public int getRetryTimes() {
return 1;
}
@Override
public int getHeartbeat() {
return 0;
}
};
list.add(connStrategy);
return list;
}
@Override
public String getSchemeByHost(String host) {
return instance.getSchemeByHost(host);
}
@Override
public String getSchemeByHost(String host, String dftScheme) {
return instance.getSchemeByHost(host, dftScheme);
}
@Override
public String getCNameByHost(String host) {
return instance.getCNameByHost(host);
}
@Override
public String getClientIp() {
return instance.getClientIp();
}
@Override
public void notifyConnEvent(String host, IConnStrategy connStrategy, ConnEvent connEvent) {
instance.notifyConnEvent(host, connStrategy, connEvent);
}
@Override
public String getUnitByHost(String s) {
return null;
}
@Override
public void forceRefreshStrategy(String host) {
instance.forceRefreshStrategy(host);
}
@Override
public void registerListener(IStrategyListener listener) {
instance.registerListener(listener);
}
@Override
public void unregisterListener(IStrategyListener listener) {
instance.unregisterListener(listener);
}
});
}
/********************HA SDK END **************************/
}