阿里热修复之Sophix——专有云发布版集成步骤

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Dota_wy/article/details/82688440

阿里热修复之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 **************************/
}

到这里基本结束了,下面附上我的github上的demo

https://github.com/gitwangyang/SophixEMASDemo.git

猜你喜欢

转载自blog.csdn.net/Dota_wy/article/details/82688440