TinkerPatch热修复接入笔记

Tinker热修复框架接入

Android现在开发App基本都开始接入热修复框架,为的就是能够修复一些线上紧急Bug。热门的热修复框架以及对比,网上介绍的也很多,个人而言就用过腾讯的tinker以及阿里的sophix。

腾讯tinkerTinker简介,根据官方文档接入tinker,然后测试热修复补丁,总是莫名地失败(或许是自己技术太渣)。无奈就不去折腾它,而选择了第三方的tinkerpatch这个sdk,并测试补丁ok。

注:参照网上的tinker接入博客,以及官方文档,自己总是搞不定,说是自己技术渣吧,也可能。反正我参照阿里的文档接入sophix就很顺利。

闲言少续,言归正传,以下为接入tinkerpatch的大致步骤

  • 在项目根build.gradle加入依赖配置
  buildscript {
        repositories {
        ...
        maven { url 'https://dl.bintray.com/wemobiledev/maven' }
        maven { url 'https://dl.bintray.com/tinker/maven' }
        }
        dependencies {
        ...
        // TinkerPatch 插件
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.8"
        }
      }
  • appbuild.gradle中,添加依赖
 apply from: '../tinkerpatch.gradle'
      ​
      ​
      dependencies{
          // 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
        implementation 'com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8'
        annotationProcessor 'com.tinkerpatch.tinker:tinker-android-anno:1.9.8'
        //dex分包,用于tinker
          implementation "com.android.support:multidex:1.0.3"
          ...
      }

  • 根据上面的配置,就需要创建换一个tinkerpatch.gradle文件,路径与appbuilde.gradle同级。一般来说,需要注意两个位置

    1. appKey就是你在tinkerpatch平台上的key

    2. sevenZip的版本和路径配置,对应到你本地的路径。(注意,这里可能你会下载不到,maven仓库配置一下阿里的jcenter比较好)

    3. 7zip文件的下载,7za这个好多人没有,需要https://www.7-zip.org/download.html这里面的download目录下

      7-Zip Extra: standalone console version, 7z DLL, Plugin for Far Manager这一栏。然后解压到你对应路径,配置到下面就好。

    4. com.tencent.mm:SevenZip:1.2.12有时候加载不出来,你就在app的buidle.gradle中添加这个依赖implementation com.tencent.mm:SevenZip:1.2.12来下载,就好。

    5. 这里用到一个变量 appversionName需要你配置在gradle中的一个变量,就是app的版本号。可以在根目录的gradle.properties中配置,如:

 appVersionCode=16
          appVersionName=2.0.2

注意,有时候AS设置中去掉compile设置项下的--offline参数比较好

 import java.util.regex.Matcher
      import java.util.regex.Pattern
      ​
      apply plugin: 'tinkerpatch-support'
      ​
      /**
       * TODO: 请按自己的需求修改为适应自己工程的参数
       */
      def bakPath = file("${buildDir}/bakApk/")
      ​
      tinkerpatchSupport {
          /** 可以在debug的时候关闭 tinkerPatch **/
          tinkerEnable = true
      ​
          /** 是否使用一键接入功能  **/
          reflectApplication = true
      ​
          /** 是否开启加固模式,只有在使用加固时才能开启此开关 **/
          protectedApp = false
      ​
          /** 补丁是否支持新增 Activity •(exported必须为false•)**/
          supportComponent = false
      ​
          autoBackupApkPath = "${bakPath}"
      ​
          /** 在tinkerpatch.com得到的appKey **/
          appKey = "20155552655555522"
          /** 注意: 若发布新的全量包, appVersion一定要更新 **/
          appVersion = appVersionName
      ​
          baseApkFile = "${bakPath}/app-${appVersionName}.apk"
          baseProguardMappingFile = "${bakPath}/app-${appVersionName}-mapping.txt"
          baseResourceRFile = "${bakPath}/app-${appVersionName}-R.txt"
      ​
          /**
           * (可选)重命名备份文件的格式化字符串,默认为'${appName}-${variantName}'
           *
           * Available vars:
           * 1\. projectName
           * 2\. appName
           * 3\. packageName
           * 4\. buildType
           * 5\. versionName
           * 6\. versionCode
           * 7\. buildTime
           * 8\. fileSHA1
           * 9\. flavorName
           * 10\. variantName
           *
           * default value: '${appName}-${variantName}'
           * Note: plz use single-quotation wrapping this format string
           */
          backupFileNameFormat = '${appName}-${variantName}'
      ​
          /**
           *  若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample
           *  注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)
           **/
      }
      ​
      /**
       * 用于用户在代码中判断tinkerPatch是否被使能
       */
      android {
          defaultConfig {
              buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
          }
      }
      ​
      /**
       * 一般来说,我们无需对下面的参数做任何的修改
       * 对于各参数的详细介绍请参考:
       * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
       */
      tinkerPatch {
          ignoreWarning = false
          useSign = true
          dex {
              dexMode = "jar"
              pattern = ["classes*.dex"]
              loader = []
          }
          lib {
              pattern = ["lib/*/*.so"]
          }
      ​
          res {
              pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
              ignoreChange = []
              largeModSize = 100
          }
      ​
          packageConfig {
          }
          sevenZip {
              zipArtifact = "com.tencent.mm:SevenZip:1.2.12"
              path = "D:\\Android\\7z\\x64\\7za.exe"
          }
          buildConfig {
              keepDexApply = false
          }
      }
      ​
      /**
       * 如果只想在Release中打开tinker,可以把tinkerEnable赋值为这个函数的return
       * @return 是否为release
       */
      def isRelease() {
          Gradle gradle = getGradle()
          String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
      ​
          Pattern pattern
          if (tskReqStr.contains("assemble")) {
              println tskReqStr
              pattern = Pattern.compile("assemble(\\w*)(Release|Debug)")
          } else {
              pattern = Pattern.compile("generate(\\w*)(Release|Debug)")
          }
          Matcher matcher = pattern.matcher(tskReqStr)
      ​
          if (matcher.find()) {
              String task = matcher.group(0).toLowerCase()
              println("[BuildType] Current task: " + task)
              return task.contains("release")
          } else {
              println "[BuildType] NO MATCH FOUND"
              return true
          }
      }

其他基本不做修改,或者可以根据自身项目配置。

  • 在自定义的application中,配置并初始化tinkerpatch
   private ApplicationLike tinkerApplicationLike;//Tinker
      ​
        @Override
        public void onCreate() {
        super.onCreate();
        //init tinkerpatch
        initTinkerPatch();
              ...
        }
      ​
        @Override
        public void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        //you must install multiDex whatever tinker is installed!
        MultiDex.install(base);
        }
      ​
        /**
        * 我们需要确保至少对主进程跟patch进程初始化 TinkerPatch
        */
        @SuppressLint("LongLogTag")
        private void initTinkerPatch() {
        // 我们可以从这里获得Tinker加载过程的信息
        if (BuildConfig.TINKER_ENABLE) {
            tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
            // 初始化TinkerPatch SDK
            TinkerPatch.init(tinkerApplicationLike)
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true)
                    .setFetchPatchIntervalByHours(3);
            // fetchPatchUpdateAndPollWithInterval 与 fetchPatchUpdate(false)
            // 不同的是,会通过handler的方式去轮询
            TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
        }
        }

这里需要注意的是,如果app使用了多进程,就尽可能只初始化一次。多次初始化有没有问题,我没试过。

  • 然后在启动的activity或者你需要的地方自动调用在activity的需要的地方,调用TinkerPatch.with().fetchPatchUpdate(true);就会联网请求tinkerpatch平台上你所发布的对应版本的补丁。

  • 以上配置ok的话,每次打包就会在project/app/build/bakapk/下面生成如app-2.0.2-1012-11-25-31样式的文件夹,里面有debug文件夹,下有app-debug.apk以及app-debug-R.txt。

    如果你运行的release的build,就是release文件夹下

    1. 在AS的右侧Gradle栏目下,找到app-build下运行assembleRelease就能生成release的包。

    2. 然后将上述的app-release.apk以及app-release-R.txt移动到bakapk目录下,并更改名称如app-2.0.2.apk以及app-2.0.2-R.txt。(这实在tinkerpatch.gradle中配置的)。

    3. 如果开启了混淆,则也需要生成基础包的时候把mapping.txt文件也放到如上的bakapk目录下。

    4. 运行AS的Gradle下app--tinker--tinkerPatchRelease的task,就会生成补丁包。在app--build--outputs--apk--tinkerPatch--release下有patch-signed-7z.apk的补丁包。

    5. 上传之tinkerpatch平台,你的项目下,创建项目,创建补丁,然后选择发布补丁。

    6. 此时app启动,会联网下载补丁,再次退出启动的时候,就会应用补丁。有的可能需要启动三次(冷启动)。

注意的是,这里使用的演示是release构建,如果测试debug,你只需要build 对应debug包,然后tinkerpatch也是debug就行。

还有一点说明,好像tinkerpatch这个平台免费版的下发补丁次数有限制,如果是大型项目,还是自己研究如何使用tinker官方接入方式。或者可以使用阿里的sophix,接入也是很方便。打补丁也方便。

你可能感兴趣的:(TinkerPatch热修复接入笔记)