Tinker热修复框架接入

版权声明:博文网络共享,尊重知识原创。 https://blog.csdn.net/binglumeng/article/details/83059493

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"
      	}
      }
  • 在app的build.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文件,路径与app的builde.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,接入也是很方便。打补丁也方便。

猜你喜欢

转载自blog.csdn.net/binglumeng/article/details/83059493