Tinker 热修复接入

Tinker 热修复接入

tinker 平台账号密码注册

官方网址:http://www.tinkerpatch.com/

这里我填写了TinkerDemo

Tinker 理解

Tinker 热修复理解

  • Tinker 热修复,是在某一个APP版本上进行的快速修复功能。

  • 项目中引入Tinker环境,创建一个签名版的APP给用户使用,突然这个APP存在有部分问题需要立即更新。这个时候就需要使用到热修复的功能。在原APP项目的基础上做代码等的修复,然后通过tinker环境获取到补丁文件,将这个补丁文件上传到Tinker patch后台,下发。补丁下发成功之后,则会直接显示为最新版的。

Tinker 项目接入

  1. 在project 的gradle中引入Tinker plugin

    classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.8"
    
  2. tinker patch gradle配置

    在app目录下添加tinkerpatch.gradle文件

    gradle内容:

    apply plugin: 'tinkerpatch-support'
    
    import java.util.regex.Matcher
    import java.util.regex.Pattern
    
    /**
     * thinkerPatch 主要用于生成版本之间的补丁文件,
     * 如果需要通过打补丁的方式来升级部分版本,就需要对这个文件进行一个整体的配置
     */
    def bakPath = file("${buildDir}/bakApk/")
    /**
     *  TODO: 这是最基础的apk的版本路径(在哪一个基础包上进行了更改)
     */
    def baseInfo = "app-1.0.0-0726-10-43-56"
    def variantName = "release"
    
    /**
     * 对于插件各参数的详细解析请参考
     * http://tinkerpatch.com/Docs/SDK
     */
    tinkerpatchSupport {
        /**
         * TODO: appKey 需要更换成 tinker patch中新建项目的appKey
         */
        appKey = "3f83b746e732b009"
    
        /**
         * TODO: 每一次打补丁都需要进行更改
         * /
         appVersion = "1.0.0"
    
         /** 可以在debug的时候关闭 tinkerPatch, isRelease() 可以判断BuildType是否为Release **/
        tinkerEnable = true
        reflectApplication = true
        /**
         * 是否开启加固模式,只能在APK将要进行加固时使用,否则会patch失败。
         * 如果只在某个渠道使用了加固,可使用多flavors配置
         **/
        protectedApp = false
        /**
         * 实验功能
         * 补丁是否支持新增 Activity (新增Activity的exported属性必须为false)
         **/
        supportComponent = true
    
        autoBackupApkPath = "${bakPath}"
    
        def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
        def name = "${project.name}-${variantName}"
    
        baseApkFile = "${pathPrefix}/${name}.apk"
        baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
        baseResourceRFile = "${pathPrefix}/${name}-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.1.10"
    //        path = "/usr/local/bin/7za"
        }
        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;
        }
    }
    

    注意其中三个TODO的部分

    baseInfo在发布新APP 不是打补丁的情况下,这个地方不用填值。

    variantName,正式签名为release

    appKey、appVersion,必须。appVersion 填写的值为基础APP的version.

  3. tinker在app gradle中的配置

    • 签名配置

      signingConfigs {
      release {
      keyAlias ‘key0’
      keyPassword ‘123456’
      storeFile file(‘C:/tjs/keystore/tjs.jks’)
      storePassword ‘123456’
      }
      }

      buildTypes {
      debug {
      signingConfig signingConfigs.release
      }
      release {
      signingConfig signingConfigs.release
      minifyEnabled false
      proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’
      }
      }

    • dependence tinker sdk

      provided("com.tinkerpatch.tinker:tinker-android-anno:1.9.8")
      compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8")
      
    • 引入tinker gradle 配置

      apply from: 'tinkerpatch.gradle'
      
  4. 添加权限

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
  5. Application中的设置

    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            // 我们可以从这里获得Tinker加载过程的信息
            ApplicationLike tinkerPatchApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
            // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
            TinkerPatch.init(tinkerPatchApplicationLike)
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true)
                    .setFetchPatchIntervalByHours(3);
    
            // 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果
            TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
        }
    }
    

    记得配置到清单文件中。

  6. 打一个正式包给用户使用

    点击Android studio 右侧的gradle,选择app-tasks-build-assembleRelease 点击就可以打正式包了。在gradle console中可以查看打包的情况,看到build successfull就是成功了。

    APP生成路径:app\build\outputs\apk 和 app\build\bakApk\app-1.0.0-0726-14-51-59\release(app-appVersion-时间\variantName)


urgent event !!! 重大显示失误

解决方式:通过热修复,快速下发补丁。

步骤:

  1. 在项目上做最新版的修改。

  2. 配置patch 补丁

  3. gradle 打补丁

  4. 补丁生成位置

  5. 将补丁上传到 tinker patch

PS:开发预览和全量下发

开发预览需要在tinker 的 debugTool.apk中打开开发者模式,重启baseApp.开发预览比较实时,每一次打补丁可以先根据开发预览来进行测试。全量开发以小时为单位,是APP中设置的每隔多久到后台去查看是否有补丁,下载补丁。

debugTool APP,每一次开发预览模式下安装的APP,最好都先操作debugTool(不管初始状态是不是已经开开的,都需要重新操作为开,在重启baseApp)

最后运行结果:ok


还想修改?!!!!!

打的补丁是baseApp得基础上进行的

注意点:

  1. 在已经打过补丁的APP上不会再继续下载补丁。

  2. 在后台一个app上添加了多个补丁,全量下发的版本号才会自动增加,如果两个补丁都是开发预览,则会出现两个补丁版本号相同的情况。

  3. 两个补丁,一个全量模式,一个开发预览模式,baseAPP会下载第一个全量模式下发的补丁,第二个无效。

  4. 可以给接口,获取到相应的补丁,然后单独加载补丁。

猜你喜欢

转载自blog.csdn.net/u012391876/article/details/81630991