Android 热修复之阿里的Sophix

产品倒闭
• 阅读 3030

Android 热修复之阿里的Sophix

一:简介
移动热修复(Mobile Hotfix)是面向Android、iOS平台应用提供的在线热修复服务方案,产品基于阿里巴巴首创的Hotpatch技术,提供细粒度热修复能力,无需等待发版即可实时修复应用线上问题,用户全程无感知。
Android 热修复之阿里的Sophix
二:Android SDK稳健接入
第一步:在项目下的build.gradle下添加

buildscript {
    ext.kotlin_version = '1.3.50'

    repositories {
        google()
        jcenter()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven { url 'http://maven.aliyun.com/nexus/content/repositories/releases/' }

    }
    }
allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
        maven { url 'http://maven.aliyun.com/nexus/content/repositories/releases/' }//Maven仓库地址
    }
}

额外话题:
在rootProject下的build.gradle中:buildscript的repositories和allprojects的repositories有什么区别?
1、 buildscript里是gradle脚本执行所需依赖,分别是对应的maven库和插件
2、 allprojects里是项目本身需要的依赖,比如代码中某个类是打包到maven私有库中的,那么在allprojects—>repositories中需要配置maven私有库,而不是buildscript中,不然找不到。
第二步:在app下build.gradle添加热修复的依赖

android {
    ......
    defaultConfig {
        applicationId "com.xxx.xxx" //包名
 ndk {
            //选择要添加的对应cpu类型的.so库。热修复支持5种
            abiFilters 'arm64-v8a','armeabi', 'armeabi-v7a', 'x86_64','x86'
        }
        }
        }
dependencies {
   implementation 'com.aliyun.ams:alicloud-android-hotfix:3.2.18'
   }

第三步添加应用权限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" />
//外部存储读权限,调试工具从SD卡加载本地补丁需要。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

第四步:除了下面配置文文件引入App ID等,下面这种方式直接引入也可以

 <application
        android:name="com.alibaba.sophix.demo.SophixStubApplication"
        android:allowBackup="true"
        android:icon="@mipmap/app_logo"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
       <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密钥" />

第四步:下载我们在平台上添加的项目的生成的配置文件
为方便EMAS各产品SDK快速、轻量接入,EMAS提供了统一的SDK依赖方式,供各产品SDK添加依赖使用。用户使用统一接入后,无需手动管理各产品SDK依赖,由插件自行接管完成读取和配置。
并将json文件放到应用根目录下(/app/)。Android端配置文件:aliyun-emas-services.json其内容如下:
配置文件:

{
  "config": {
    "emas.appKey":"xxxxx",
    "emas.appSecret":"xxxxxx",
    "emas.packageName":"com.xxx.xxx.demo",
    "hotfix.idSecret":"xxxxx",
    "hotfix.rsaSecret":"xxxxx",
    "httpdns.accountId":"xxxxx",
    "httpdns.secretKey":"xxxxxxxxx"
    "appmonitor.tlog.rsaSecret":"xxxxxxxxxx",
    "appmonitor.rsaSecret":"xxxxxxxxxx"
},
  "services": {
    "hotfix_service":{//移动热修复,status=1,表示使用对应产品,status=0不使用
        "status":1,
        "version":"3.2.14"
    },
    "ha-adapter_service":{//性能分析/远程日志的基础库
        "status":1,
        "version":"1.1.3.4-open"
    },
    "feedback_service":{//移动用户反馈
        "status":1,
        "version":"3.3.1"
    },
    "tlog_service":{//远程日志
        "status":1,
        "version":"1.1.2.3-open"
    },
    "httpdns_service":{
        "status":1,
        "version":"1.3.2.3"
    },
    "apm_service":{//性能分析
        "status":1,
        "version":"1.0.7.9-open"
    },
    "man_service":{//移动数据分析
        "status":1,
        "version":"1.2.4"
    },
    "cps_service":{//移动推送
        "status":1,
        "version":"3.1.12"
    }
},
  "use_maven":true,
  "proguard_keeplist":"\n#httpdns\n-keep class com.taobao.** {*;}\n-keep class com.alibaba.** {*;}\n-keep class com.ta.**{*;}\n-keep class com.ut.**{*;}\n-dontwarn com.taobao.**\n-dontwarn com.alibaba.**\n-dontwarn com.ta.**\n-dontwarn com.ut.**\n\n#cps\n-keep class com.taobao.** {*;}\n-keep class com.alibaba.** {*;}\n-keep class com.ta.**{*;}\n-keep class com.ut.**{*;}\n-dontwarn com.taobao.**\n-dontwarn com.alibaba.**\n-dontwarn com.ta.**\n-dontwarn com.ut.**\n-keepclasseswithmembernames class ** {\nnative <methods>;\n}\n-keepattributes Signature\n-keep class sun.misc.Unsafe { *; }\n-keep class com.alipay.** {*;}\n-dontwarn com.alipay.**\n-keep class anet.**{*;}\n-keep class org.android.spdy.**{*;}\n-keep class org.android.agoo.**{*;}\n-dontwarn anet.**\n-dontwarn org.android.spdy.**\n-dontwarn org.android.agoo.**\n\n#hotfix\n#基线包使用,生成mapping.txt\n-printmapping mapping.txt\n#生成的mapping.txt在app/buidl/outputs/mapping/release路径下,移动到/app路径下\n#修复后的项目使用,保证混淆结果一致\n#-applymapping mapping.txt\n#hotfix\n-keep class com.taobao.sophix.**{*;}\n-keep class com.ta.utdid2.device.**{*;}\n#防止inline\n-dontoptimize\n\n#man\n-keep class com.taobao.** {*;}\n-keep class com.alibaba.** {*;}\n-keep class com.ta.**{*;}\n-keep class com.ut.**{*;}\n-dontwarn com.taobao.**\n-dontwarn com.alibaba.**\n-dontwarn com.ta.**\n-dontwarn com.ut.**\n\n#feedback\n-keep class com.taobao.** {*;}\n-keep class com.alibaba.** {*;}\n-keep class com.ta.**{*;}\n-keep class com.ut.**{*;}\n-dontwarn com.taobao.**\n-dontwarn com.alibaba.**\n-dontwarn com.ta.**\n-dontwarn com.ut.**\n"
}

配置文件引用
在项目级目录下build.gradle(/build.gradle)文件中添加阿里云Maven仓库地址和emas-services插件。

buildscript {
  repositories {
    maven {
        url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
    }
  }
  dependencies {
    // 添加emas-services插件
    classpath 'com.aliyun.ams:emas-services:1.0.1'//引入
  }
}
allprojects {
    repositories {
      ...
        maven {
            url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
        }
    }
}

在应用级build.gradle(<project>/<app-module>/build.gradle)文件中添加代码段,应用插件。

apply plugin: 'com.aliyun.ams.emas-services'

第五步:初始化
初始化的调用应该尽可能的早,必须在Application.attachBaseContext()的最开始(在super.attachBaseContext之后,如果有Multidex,也需要在Multidex.install之后)进行SDK初始化操作,初始化之前不能用到其他自定义类,否则极有可能导致崩溃。而查询服务器是否有可用补丁的操作可以在后面的任意地方。不建议在Application.onCreate()中初始化,因为如果带有ContentProvider,就会使得Sophix初始化时机太迟从而引发问题。

/**
 * Sophix入口类,专门用于初始化Sophix,不应包含任何业务逻辑。
 * 此类必须继承自SophixApplication,onCreate方法不需要实现。
 * 此类不应与项目中的其他类有任何互相调用的逻辑,必须完全做到隔离。
 * AndroidManifest中设置application为此类,而SophixEntry中设为原先Application类。
 * 注意原先Application里不需要再重复初始化Sophix,并且需要避免混淆原先Application类。
 * 如有其它自定义改造,请咨询官方后妥善处理。
 */
public class SophixStubApplication extends SophixApplication {
    private final String TAG = "SophixStubApplication";
    // 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。
    @Keep
    @SophixEntry(MyApplication .class)
    static class RealApplicationStub {}
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
//         如果需要使用MultiDex,需要在此处调用。
//         MultiDex.install(this);
        initSophix();
    }
    private void initSophix() {
        String appVersion = "1.1.1";//app对应的版本名
        try {
            appVersion = this.getPackageManager()
                             .getPackageInfo(this.getPackageName(), 0)
                             .versionName;
        } catch (Exception e) {
        }
        final SophixManager instance = SophixManager.getInstance();
        instance.setContext(this)
                .setAppVersion(appVersion)
                .setSecretMetaData(null, null, null)
                .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.");
                        }
                    }
                }).initialize();
    }
}

其中最重要的是

  @Keep
    @SophixEntry(MyApplication .class)
    static class RealApplicationStub {}
    
    //SophixEntry应指定项目中原先真正的Application(原项目里application的android::name指定的)
public class MyApplication extends Application {
 @Override
    public void onCreate() {
        super.onCreate();
 SophixManager.getInstance().queryAndLoadNewPatch();
 
 /// queryAndLoadNewPatch为拉取控制台补丁
//不可放在attachBaseContext 中,否则无网络权限,建议放在主进程任意时刻,如Application的onCreate中
//SophixManager.getInstance().queryAndLoadNewPatch();这个方法用来查询有没有补丁包生成
 }
}
//现在的application
 <application
        android:name=".SophixStubApplication"
        android:allowBackup="false"/>

第六步:混淆配置

#基线包使用,生成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

阿里热修复接入文档
https://help.aliyun.com/docum...

END:当你真正喜欢做一件事时,自律就会成为你的本能。

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
4年前
tinker接入
对于热修复无非就是两大类,一类是tencent代表的classloader模式的,另一类是阿里系代表的底层方面替换。下面以本人的经验介绍下微信的tinker接入:  命令行接入方式;gradle接入方式1\.核心库引入,在你应用的app模块下build.gradle文件加入//tinkerhotfix//可选,用于生
御弟哥哥 御弟哥哥
5年前
半小时掌握Android Gradle
目前国内对Android领域的探索已经越来越深,不少技术领域如插件化、热修复、构建系统等都对Gradle有迫切的需求,不懂Gradle将无法完成上述事情。所以Gradle必须要学习。Gradle里的几乎任何东西都是基于这两个基础概念:taskproject掌握了这两个,你就掌握了一大半的Gradle知识了。首先讲Task
红橙Darren 红橙Darren
4年前
Android热修复之 - 收集崩溃信息上传服务器
1.概述开始想收集崩溃信息是因为测试的哥们老是说崩了,但是一过来就开始拍脑袋说我\怎么好了?所以后来上网查了很多信息,找到了一种方法。大致的流程就是在用户崩溃的时候,我们获取崩溃信息、应用当前的信息和手机信息,然后把它保存到手机内存卡,再找我就直接找出来看看。后来衍生到上线后某些奇葩机型会有部分问题,所以不得不上传到服务器,后来发现居然可以配合热修复一
Stella981 Stella981
4年前
OCRunner 第零篇:从零教你写一个 iOS 热修复框架
作者:SilverFruity,https://github.com/SilverFruity为什么要热修复在软件开发过程中,很难避免BUG的存在,尤其是对于一些达到一定规模的App因为协作模式错综复杂,就很容易带着问题上线。一旦问题上线之后,问题就麻烦了,不仅需要重新打包、测试,而且还需要重新提交审核,而这种修复
Wesley13 Wesley13
4年前
unity热更(一)
Agenda•  什么是热更新•  为何要热更新•  如何在iOS 上对Unity 应用进行热更新•  支持UnityiOS 热更新的各种Lua 插件的对比什么是热更新• 广义定义• 无需关闭服务器,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码。• 狭义定义(iOS热更新)• 无需将代码重新打包提交至Ap
Stella981 Stella981
4年前
OCRunner 第一篇:实现一个简单版热修复功能
作者:SilverFruity,https://github.com/SilverFruity小编寄语:上一周我们发布了《OCRunner第零篇:从零教你写一个iOS热修复框架》(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fmp.we
Wesley13 Wesley13
4年前
1月2日云栖精选夜读:【2018新年巨献】像阿里巴巴一样高效工作!(含视频、文章、PDF文件)
WorkLikeAlibaba通过线下沙龙、线上直播、内容输出三个维度,携手阿里云的典型企业用户,联合云栖社区、阿里云、钉钉阿里产品,将阿里的前沿产品技术理念、敏捷研发模式、智能运维方法、智能办公、移动办公等渐渐渗透到外部的企业用户,形成了阿里特色的技术社区——你也可以像阿里巴巴一样高效工作。热点热议【2018新年巨献】像阿里巴巴一样高效工作
Stella981 Stella981
4年前
DevOps世界中的软件开发
!(https://oscimg.oschina.net/oscnet/f40e68cbfe8148deb00f040b4e917a0a.jpg)在整个软件开发过程中,开发人员通常需要花费大量时间来修复错误和漏洞,以便一切按计划进行交付。但是,通过DevOps实践,可以更轻松地管理和保护这些问题。这是由于以下事实:使用DevOps实践的软
Flutter热更新技术探索 | 京东云技术团队
APP发布到市场后,难免会遇到严重的BUG阻碍用户使用,因此有在不发布新版本APP的情况下使用热更新技术立即修复BUG需求。原生APP(例如:Android&IOS)的热更新需求已经比较成熟,但Flutter技术栈目前还缺少类似的技术方案,因此Flutter研发团队,也需要类似的热更新技术。