微信热更新Tinker集成遇到的坑

最近项目由于急匆匆上线,导致有低级bug出现,由于没有集成热更新,所以修复玩这些bug后还要打新版本的apk包,造成用户抱怨,所以集成热更新:然后就了解了现在的热更新框架,觉得微信的tinker集成相对比较简单,就拿来试一试。

现在拿我用的AndroidStudio和项目环境进行集成还是遇到了不少坑。再次做一下 记录:

  1. 先来说一下我用的AnroidStudio环境:

    我用的AndroidStudio3.0的稳定版,gradle的版本:

    distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

    gradle工具版本

    classpath 'com.android.tools.build:gradle:3.0.1'

    编译环境版本

    android = [
                compileSdkVersion: 26,
                buildToolsVersion: '26.0.2',
                minSdkVersion    : 19,
                targetSdkVersion : 26,
                javaVersion      : JavaVersion.VERSION_1_8,
                versionCode      : 7,
                versionName      : '3.1.0',
        ]
  2. 集成步骤:
  • app的gradle中添加tinker的依赖: 

dependencies {
    // 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
    provided("com.tinkerpatch.tinker:tinker-android-anno:1.8.0")
    compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.8")
}

apply from: 'tinkerpatch.gradle'
  • 在项目的gradle中添加
 dependencies {
        // TinkerPatch 插件
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.8"
    }
  •  在app的更目录下面添加tinkerpatch.gradle文件:
apply plugin: 'tinkerpatch-support'
apply from: 'tinkerpatch.gradle'
/**
 * TODO: 请按自己的需求修改为适应自己工程的参数
 */

//基包路径
def bakPath = file("${buildDir}/bakApk/")
//基包文件夹名(打补丁包的时候,需要修改)
def baseInfo = ""
//版本名称
def variantName = "debug"  //"release"

/**
 * 对于插件各参数的详细解析请参考
 *
 */
tinkerpatchSupport {
    //可以在debug的时候关闭 tinkerPatch
    tinkerEnable = true
    //是否使用一键接入功能 默认为false  是否反射 Application 实现一键接入;
    // 一般来说,接入 Tinker 我们需要改造我们的 Application, 若这里为 true, 即我们无需对应用做任何改造即可接入。
    reflectApplication = true
    //将每次编译产生的 apk/mapping.txt/R.txt 归档存储的位置
    autoBackupApkPath = "${bakPath}"
    appKey = ""// 注意!!!  需要修改成你的appkey

    /** 注意: 若发布新的全量包, appVersion一定要更新 **/
    appVersion = "1.0.0"

    def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
    def name = "${project.name}-${variantName}"
    /**
     * 基准包的文件路径, 对应 tinker 插件中的 oldApk 参数;编译补丁包时,
     * 必需指定基准版本的 apk,默认值为空,则表示不是进行补丁包的编译
     */
    baseApkFile = "${pathPrefix}/${name}.apk"

    /**
     * 基准包的 Proguard mapping.txt 文件路径, 对应 tinker 插件 applyMapping 参数;在编译新的 apk 时候,
     * 我们希望通过保持基准 apk 的 proguard 混淆方式,
     * 从而减少补丁包的大小。这是强烈推荐的,编译补丁包时,我们推荐输入基准 apk 生成的 mapping.txt 文件。
     */
    baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
    /**
     * 基准包的资源 R.txt 文件路径, 对应 tinker 插件 applyResourceMapping 参数;在编译新的apk时候,
     * 我们希望通基准 apk 的 R.txt 文件来保持 Resource Id 的分配,这样不仅可以减少补丁包的大小,
     * 同时也避免由于 Resource Id 改变导致 remote view 异常
     */
    baseResourceRFile = "${pathPrefix}/${name}-R.txt"
    /**
     *  若有编译多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  //是否需要签名,打正式包如果这里是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
    }
}
  •  项目的Application 中添加:
public class XscdApplication extends MultiDexApplication {
    private ApplicationLike tinkerApplicationLike;
    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.TINKER_ENABLE) {
            // 我们可以从这里获得Tinker加载过程的信息
            tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();

            // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
            TinkerPatch.init(tinkerApplicationLike)
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true);

            // 每隔3个小时去访问后台时候有更新,通过handler实现轮训的效果
            new FetchPatchHandler().fetchPatchWithInterval(3);
        }
    }
}
  • 添加类FetchHandler:
public class FetchPatchHandler extends Handler {

    public static final long HOUR_INTERVAL = 3600 * 1000;
    private long checkInterval;


    /**
     * 通过handler, 达到按照时间间隔轮训的效果
     */
    public void fetchPatchWithInterval(int hour) {
        //设置TinkerPatch的时间间隔
        TinkerPatch.with().setFetchPatchIntervalByHours(hour);
        checkInterval = hour * HOUR_INTERVAL;
        //立刻尝试去访问,检查是否有更新
        sendEmptyMessage(0);
    }


    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //这里使用false即可
        TinkerPatch.with().fetchPatchUpdate(false);
        //每隔一段时间都去访问后台, 增加10分钟的buffer时间
        sendEmptyMessageDelayed(0, checkInterval + 10 * 60 * 1000);
    }
}
  • 微信的TInker需要集成的东西就已经集成完了,然后编译一下项目,会发现出现错误,首先遇到的错误: 

Error:Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now.  The following dependencies on the compile classpath are found to contain annotation processor.  Please add them to the annotationProcessor configuration.
    - tinker-android-anno-1.8.0.jar (com.tinkerpatch.tinker:tinker-android-anno:1.8.0)
  Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior.  Note that this option is deprecated and will be removed in the future.
  See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

原因:大概原因就是我使用le Gradle3.0的工具吧,新的 gradle 不再支持 annotation processors。解决办法:

       如果需要使用需要显式声明,在app的gradle中添加

defaultConfig {
    javaCompileOptions {
        // 显式声明支持注解
        annotationProcessorOptions {
            includeCompileClasspath true
        }
    }
}

扫描二维码关注公众号,回复: 5709339 查看本文章

     要么使用低版本的gradle

 dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

这里我先用第一种方法试一下,编译由报错:

Error:Could not get unknown property 'apkVariantData' for object of type com.android.build.gradle.internal.api.ApplicationVariantImpl.

原因是:gradle升级到3.0以后去除了apkVariantData这个api,所以我们还是要使用低版本的gradle了,于是修改gradle的版本

在项目的gradle文件中修改gradle版本为2.3.2,这时编译之后可能出现gradle3.0时添加依赖是使用的implementation关键自不能用了,改成compile就好啦: 

dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'
}

接着编译,发现又报错了:

Error:Jack is required to support java 8 language features. Either enable Jack or remove sourceCompatibility JavaVersion.VERSION_1_8.

 意思就是要使用java8的特性,需要配置一下jack,Jack 是 Java Android Compiler Kit 的缩写 ,算是Android自己的java编译器,需要在app的gradle文件中,配置:

defaultConfig {
        jackOptions {
            enabled true
        }
}

 编译,又出现错误:

Error:Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.tree.JCTree$VisitorError:    at java.lang.Class.getDeclaredConstructors0(Native Method)
Error:    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
Error:    at java.lang.Class.getConstructor0(Class.java:3075)
Error:    at java.lang.Class.newInstance(Class.java:412)
Error:    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
Error:    ... 16 more

这个错误出现的原因,我也没有查出来是为什么,可能还是java8配置的Jack出的问题,所以我还是把gradle里面配置java8的地方给去掉了,以前用的很多lanmuda表达式也要改回来了。

猜你喜欢

转载自blog.csdn.net/czc448969530/article/details/84820527