BuglyTinker 热更新 全量更新

1 篇文章 0 订阅
0 篇文章 0 订阅

第一步:

https://bugly.qq.com/v2/upgrade/ 

注册账号,进入主页时创建产品,实际上在创建产品时所输入的一些数据并是很重要,因为我们要的只是里面的APP ID,通过一波操作后,会出现你所创建的产品,

点击设置。

第二步:

导入SDK和项目配置   https://bugly.qq.com/docs/user-guide/instruction-manual-android-hotfix/?v=20180709165613

在APP的build.gradle中添加

// 多dex配置
implementation "com.android.support:multidex:1.0.2"
// 本地集成aar方式
// compile(name: 'bugly_crashreport_upgrade-1.3.6', ext: 'aar')

// 远程依赖集成方式(推荐)
implementation "com.tencent.bugly:crashreport_upgrade:1.3.6"
// 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
implementation 'com.tencent.tinker:tinker-android-lib:1.9.9'

并且在顶部添加

apply from: 'tinker-support.gradle'

添加后会报错,原因是我们还没创建 tinker-support.gradle,创建 这个文件是一定要在app文件下第一级中,这里很容易出错(创建的位置不正确)

tinker-support.gradle内容:(代码自己复制,其他不改)

apply plugin: 'com.tencent.bugly.tinker-support'

def bakPath = file("${buildDir}/bakApk/")

/**
 * 此处填写每次构建生成的基准包目录 这里再出包时要注意修改,详细修改方式下面讲解
 */
def baseApkDir = "app-0924-17-22-04"

/**
 * 对于插件各参数的详细解析请参考
 */
tinkerSupport {

    // 开启tinker-support插件,默认值true
    enable = true

    // 自动生成tinkerId, 你无须关注tinkerId,默认为false  建议改为true让其自动,不然自己搞容易出错
    autoGenerateTinkerId = true

    // 指定归档目录,默认值当前module的子目录tinker
    autoBackupApkDir = "${bakPath}"

    // 是否启用覆盖tinkerPatch配置功能,默认值false
    // 开启后tinkerPatch配置不生效,即无需添加tinkerPatch
    overrideTinkerPatchConfiguration = true

    // 编译补丁包时,必需指定基线版本的apk,默认值为空
    // 如果为空,则表示不是进行补丁包的编译
    // @{link tinkerPatch.oldApk }
    baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
//    baseApk =  "${bakPath}/${baseApkDir}/app-debug.apk"

    // 对应tinker插件applyMapping
    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
//    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"

    // 对应tinker插件applyResourceMapping
    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
//    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"

    // 构建基准包跟补丁包都要修改tinkerId,主要用于区分
//    tinkerId = "1.0.3-ccc"

    // 打多渠道补丁时指定目录
    // buildAllFlavorsDir = "${bakPath}/${baseApkDir}"

    // 是否使用加固模式,默认为false
    // isProtectedApp = true

    // 是否采用反射Application的方式集成,无须改造Application,这里的ture或false决定Application的使用方式,建议用true
    enableProxyApplication = true

    // 支持新增Activity
    supportHotplugComponent = true

}

/**
 * 一般来说,我们无需对下面的参数做任何的修改
 * 对于各参数的详细介绍请参考:
 * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
 */
tinkerPatch {
    tinkerEnable = true
    ignoreWarning = false
    useSign = false
    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
//      tinkerId = "base-2.0.1"
    }
}

第三步:

Application的代码内容要根据tinker-support.gradle中的enableProxyApplication 的状态决定(二选一,个人建议使用第一种)

enableProxyApplication = true

public class BuglyTinkersApplication extends Application {
    
    //当bugly.tinker-support.gradle中的enableProxyApplication 为 true时
    @Override
    public void onCreate() {
        super.onCreate();
        setStrictMode();
        // 设置是否开启热更新能力,默认为true
        Beta.enableHotfix = true;
        // 设置是否自动下载补丁
        Beta.canAutoDownloadPatch = true;
        // 设置是否提示用户重启
        Beta.canNotifyUserRestart = true;
        // 设置是否自动合成补丁
        Beta.canAutoPatch = true;

        /**
         *  全量升级状态回调
         */
        Beta.upgradeStateListener = new UpgradeStateListener() {
            @Override
            public void onUpgradeFailed(boolean b) {

            }

            @Override
            public void onUpgradeSuccess(boolean b) {

            }

            @Override
            public void onUpgradeNoVersion(boolean b) {
                Toast.makeText(getApplicationContext(), "最新版本", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onUpgrading(boolean b) {
                Toast.makeText(getApplicationContext(), "onUpgrading", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDownloadCompleted(boolean b) {

            }
        };

        /**
         * 补丁回调接口,可以监听补丁接收、下载、合成的回调
         */
        Beta.betaPatchListener = new BetaPatchListener() {
            @Override
            public void onPatchReceived(String patchFileUrl) {
                Toast.makeText(getApplicationContext(), patchFileUrl, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDownloadReceived(long savedLength, long totalLength) {
                Toast.makeText(getApplicationContext(), String.format(Locale.getDefault(),
                        "%s %d%%",
                        Beta.strNotificationDownloading,
                        (int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDownloadSuccess(String patchFilePath) {
                Toast.makeText(getApplicationContext(), patchFilePath, Toast.LENGTH_SHORT).show();
//                Beta.applyDownloadedPatch();
            }

            @Override
            public void onDownloadFailure(String msg) {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onApplySuccess(String msg) {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onApplyFailure(String msg) {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPatchRollback() {
                Toast.makeText(getApplicationContext(), "onPatchRollback", Toast.LENGTH_SHORT).show();
            }
        };

        long start = System.currentTimeMillis();
//        Bugly.setUserId(this, "falue");
//        Bugly.setUserTag(this, 123456);
//        Bugly.putUserData(this, "key1", "123");
//        Bugly.setAppChannel(this, "bugly");


        // 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId,调试时将第三个参数设置为true
        Bugly.init(this, "**********", true);
        long end = System.currentTimeMillis();
        Log.e("init time--->", end - start + "ms");
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // you must install multiDex whatever tinker is installed!
        MultiDex.install(base);

        // 安装tinker
        Beta.installTinker();
    }


    @TargetApi(9)
    protected void setStrictMode() {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
    }
}

enableProxyApplication = false

public class BuglyTinkerApplication extends TinkerApplication {

    /**
     * 注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中
     * 参数解析
     * 参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKER_ENABLE_ALL
     * 参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike
     * 参数3:loaderClassName Tinker的加载器,使用默认即可
     * 参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false
     */

    //当bugly.tinker-support.gradle中的enableProxyApplication 为 false时
    public BuglyTinkerApplication() {

        super(ShareConstants.TINKER_ENABLE_ALL, "com.example.buglytinker.BuglyTinkeApplicationLike",
                "com.tencent.tinker.loader.TinkerLoader", false);
    }

BuglyTinkeApplicationLike需要自己建,该类要继承DefaultApplicationLike(此类即便上面映射调用了,但是显示时还是灰色的)

 

到这里集成和代码就写的差不多了,其余的BugActivity就得由你自己去想要让其如何报错。

第四步:

打包也是很容易出错的,小编搞了三天才彻底玩明白。

APK签名这部分很重要,不然即便生成了包,也是不行的。注意build.gradle中一定要显示你签名相对应的东西,不然生成了.jks文件,但是build.gradle没也是不行。

以上步骤弄完后打基础包有2种方法:

1.在Terminal中直接输入gradlew assembleRelease 

2.在AS右边Gradle中 :app - Tasks - build - assemble

运行后在app - build 中会生成 bakApk文件夹,(我这里才用的第二种方式打包所以,会把debug的也生成了,注意:应为我这里没有混淆,所以没用mapping.txt文件,若用混淆自然会生成相对应的mapping.txt文件。若是用第一种打包就没有debug

到这里会发现生成的文件名跟tinker-support.gradle中(下面划红线名字一样,应为补丁包是根据这些为基础生成的)

其中这里的app-release.apk,是可以上架到各各平台上面去的,相当于我们Build APK是一样的

补丁包生成:

在生成前一定要先配置 baseApkDir 的值,指定用的是那个基础包。

生产方式也有两种:

1.在Terminal中直接输入gradlew tinkerPatchRelease 

2.在AS右边Gradle中 :app - Tasks - tinker-support - buildTinkerPatchRelease

生成完成后outputs中会多来个patch,补丁包就在这里面,其中patch_signed_7zip.apk就是补丁包

双击补丁包你可以查看YAPATCH.MF打的补丁包是否是你指定的基础包From看看是否跟baseApkDir一样

同时在bakApk这里也会生成一个跟To一样的包文件夹。

 

第五步:

就是上传到Bugly中去,这时候有一个地方要注意,目标版本是自动识别的。如果上传后提示没有改版本时,是因为你那个报错的基础包安装后至少要跑一次,不然Bugly异常上报接收不到该版本的错误。

然后重启就可以。(不过到这里你们以为就完成了,其实坑才刚开始。我就是在这里跌倒了2天的。如果你们是用电脑虚拟运行的话上面的提示都有了,但是还是会报错。这喵的,我想哭啊。小编有了Mumu,AS自带的模拟器,都不行。后来我拿到真机上面一试,开发现可以了。所以小编总结这东西得到真机上面搞才可以。“若用大牛知道原因告知小弟一下”。这时一定很多人心里一定很不算吧。后来我又发现了另外一个东西叫做“全量更新”。划重点,这是每年高考都要考的。因为工作上用的热更新几乎是指这个)

 

补坑(全量更新):

versionCode和versionName这里一定要比之前的版本高,然后跟第四步一样打基础包的方式一样二选一

将再次生成的app-release.apk上传到全量更新上,弹框的更新说明一定要写

创建策略后,回到主界面也要去手动点击启动。启动往后并不会立刻生效,需等待几分钟然后App就能收到了

这样就搞定了在虚拟机和真机都可以更新了。(问什么这里不写代码呢,因为在上面的Application中就已经写好了全量升级状态回调

 

再讲一个知识点吧,04是一开始得基础包,58是打补丁包后再生成得,20是后来全量更新的。后面2个的baseApkDir指定的都是第一个,如果你再Bugly中即上传的了补丁包,又上传了全量更新。而你安装的是04的基础包。这时后如何你热更新了补丁包你的APP baseApkDir就变成0925-14-22-58,而你的全量更新就没效了,因为指定的baseApkDir不同了,反正同理。(实验后总结的)

 

GitHub: https://github.com/950824/BuglyTinkers

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值