通俗易懂接入阿里Sophix热修复

作者: AOCCG | 来源:发表于2019-06-27 16:15 被阅读77次

    Sophix平台:https://emas.console.aliyun.com/
    移动热修复(Mobile Hotfix)是面向移动互联网的APP热修复解决方案。产品基于阿里巴巴首创Hotpatch技术,提供细粒度热修复能力,无需等待,实时修复应用线上问题。
    说明:Sophix平台创建应用,创建完根据提示下载aliyun-emas-services.json文件,需要用到三个参数:App ID、App Secret、RSA密钥。

    接入SDK

    编辑项目级build.gradle

    buildscript {
        repositories {
            google()
            jcenter()
            //阿里
            maven { url "http://maven.aliyun.com/nexus/content/repositories/releases" }
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.4.1'
            //阿里
            // 添加emas-services插件
            classpath 'com.aliyun.ams:emas-services:1.0.1'
    
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            //阿里
            maven { url "http://maven.aliyun.com/nexus/content/repositories/releases" }
            
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
    

    编辑app级build.gradle

    在 apply plugin: 'com.android.application'下面加入

    apply plugin: 'com.android.application'
    

    在dependencies里加入

     //阿里SopHix热修复
     implementation 'com.aliyun.ams:alicloud-android-hotfix:3.2.6'
    

    编辑 AndroidManifest.xml

    <!--网络权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--外部存储读权限,调试工具加载本地补丁需要-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    

    在application

          <application
            android:name=".app.MyApplication"
            ......>
    

    在application里加入

    <meta-data
         android:name="com.taobao.android.hotfix.IDSECRET"
         android:value="你的App ID" />
    <meta-data
        android:name="com.taobao.android.hotfix.APPSECRET"
        android:value="你的App Secret" />
    <meta-data
        android:name="com.taobao.android.hotfix.RSASECRET"
        android:value="你的RSA密钥" />
    

    把下载的aliyun-emas-services.json文件放到项目app目录下

    如果运行报错

    java.lang.RuntimeException: Manifest merger failed with multiple errors, see logs
    解决方法
    打开AndroidManifest.xml
    点击下面的Merged Manifest
    这时你会看到具体报错信息,修改掉即可


    20180710145100369.jpg

    MainActivity

    public class MainActivity extends AppCompatActivity {
        private static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 0;
    
        private TextView mStatusTv;
        private String mStatusStr = "";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mStatusTv = findViewById(R.id.text_tv);
            updateConsole(MyApplication.cacheMsg.toString());
    
            changedImageViewSrc();
            if (Build.VERSION.SDK_INT >= 23) {
                requestExternalStoragePermission();
            }
            MyApplication.msgDisplayListener = new MyApplication.MsgDisplayListener() {
                @Override
                public void handle(final String msg) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            updateConsole(msg);
                        }
                    });
                }
            };
        }
    
        /**
         * 如果本地补丁放在了外部存储卡中, 6.0以上需要申请读外部存储卡权限才能够使用. 应用内部存储则不受影响
         */
        private void requestExternalStoragePermission() {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                        REQUEST_EXTERNAL_STORAGE_PERMISSION);
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            switch (requestCode) {
                case REQUEST_EXTERNAL_STORAGE_PERMISSION:
                    if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                        updateConsole("本地外部存储补丁无效,因为没有读取外部存储权限");
                    }
                    break;
                default:
            }
        }
    
        /**
         * 更新监控台的输出信息
         *
         * @param content 更新内容
         */
        private void updateConsole(String content) {
            mStatusStr += content + "\n";
            if (mStatusTv != null) {
                mStatusTv.setText(mStatusStr);
            }
        }
    
        //要修复的内容
        private void changedImageViewSrc() {
            final ImageView imageView = findViewById(R.id.iv_girl);
            imageView.setImageResource(R.mipmap.add);
        }
    }
    

    MyApp

    public class MyApp extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
        }
    }
    

    MyApplication

    public class MyApplication extends SophixApplication {
    
        private final String TAG = "SophixStubApplication";
    
        private final String hotfixId = "你的App ID";
        private final String hotfixappKey = "你的App Secret";
        private final String hotfixRSASECRET = "你的RSA密钥";
    
    
        @Override
        public void onCreate() {
            super.onCreate();
            //联网下载新的插件
            SophixManager.getInstance().queryAndLoadNewPatch();
        }
    
        public interface MsgDisplayListener {
            void handle(String msg);
        }
    
        public static MsgDisplayListener msgDisplayListener = null;
        public static StringBuilder cacheMsg = new StringBuilder();
    
        // 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。
        @Keep
        @SophixEntry(MyApp.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)
                    .setSecretMetaData(hotfixId, hotfixappKey, hotfixRSASECRET)
                    .setEnableDebug(true)
                    .setEnableFullLog()
                    .setPatchLoadStatusStub(new PatchLoadStatusListener() {
                        @Override
                        public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
                            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.");
                            }
    
                            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);
                            }
                        }
                    }).initialize();
        }
    }
    

    布局 activity_main

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 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:layout_height="match_parent"
        tools:context=".MainActivity">
    
    
        <TextView
            android:id="@+id/text_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:text="Hello World!"
            android:textColor="#000000"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/iv_girl" />
    
        <ImageView
            android:id="@+id/iv_girl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/old" />
    
    </android.support.constraint.ConstraintLayout>
    

    项目代码大功告成啦

    最后下载补丁和调试工具

    patch补丁包生成需要使用到打补丁工具SophixPatchTool, 如还未下载打包工具,请前往下载Android打包工具。

    生成补丁包后到Sophix平台提交补丁版本

    3864402-e1ff8ff7e2140c08.png

    相关文章

      网友评论

        本文标题:通俗易懂接入阿里Sophix热修复

        本文链接:https://www.haomeiwen.com/subject/ulsrcctx.html