腾讯bugly热更新开发

bugly 支持异常上报,应用升级与热更新;异常上报与应用升级使用较为简单,也没有什么难点。

下面看一下热更新,官网的文档说的虽然非常明白,但是罗里吧嗦,看的让人头大。

下面给出一个特别简单的集成与使用方式。

打开下面 bugly 给出的 GitHub 示例,下面是链接:

https://github.com/BuglyDevTeam/Bugly-Android-Demo

下载完毕,会看到有两个 demo ,如下图所示:

可以看到里面有两个:官网推荐 BuglyHotfixDemo;一键接入 BuglyHotfixEasyDemo ;

我们直接打开第二个,也就是 BuglyHotfixEasyDemo ,这个 demo 是热更新一键接入示例,后续也不再更新这个;    

热更新sdk版本至1.3.6, tinker-support版本至1.1.5,对应tinker版本 1.9.9;

虽然不再更新这个,但是作为普通的用户,目前使用这个是完全够用的。

如果你想使用第一个 demo ,也建议先看第二个,因为这个非常简单,看完这个再看第一个会感觉并不复杂。

在接入热更新之前,我们要去申请 appid 过程很简单,打开官网登录 qq 账号申请即可,就不说了,下面是官网地址:

https://bugly.qq.com/

下面就看一下如何接入,我并不是按照官网来的,因为官网过于复杂;如果第一次使用建议新建一个 demo ,作为测试使用;

首先在项目的 build.gradle 中添加下面代码:


        classpath 'com.tencent.bugly:tinker-support:1.1.5'

如下图:

在 app 下的 build.gradle 中添加:


// 依赖插件脚本,添加在最上面
apply from: 'tinker-support.gradle'

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

如下图所示:

新建 tinker-support.gradle 与 app 的 build.gradle 同级,代码如下:

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

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

/**
 * 此处填写每次构建生成的基准包目录
 */
def baseApkDir = "app-1119-14-54-04"

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

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

    // 自动生成tinkerId, 你无须关注tinkerId,默认为false
    autoGenerateTinkerId = true

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

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

    //测试
    baseApk =  "${bakPath}/${baseApkDir}/app-debug.apk"
    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"
    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"

    //正式
//    baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
//    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
//    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"

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

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

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

    // 是否采用反射Application的方式集成,无须改造Application
    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"
    }
}

如下图,作为参考:

在 tinkerSupport { } 里面有很多参数,请不要修改,还有需要看一下里面每个参数的意义;

这里说明几个比较重要的参数:

    // 自动生成tinkerId, 你无须关注tinkerId,默认为false
    autoGenerateTinkerId = true

参数 autoGenerateTinkerId = ture 自动生成 tinkerId,无需手动填写,方便了很多,也是和官网推荐 BuglyHotfixDemo 的一个区别;

添加这个参数也无需指定 tinkerId = "1.0.3-ccc" 这个参数;

正式和测试切换:

    //测试
    baseApk =  "${bakPath}/${baseApkDir}/app-debug.apk"
    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"
    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"

    //正式
//    baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
//    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
//    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"

测试使用 debug ,正式使用 release;

参数 buildAllFlavorsDir,配置多渠道打包请打开,不需要请注释,最下面要配置多渠道打包,所有我就打开了;

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

参数 isProtectedApp = true;测试千万不要开启,会引发不必要的 bug ,当应用需要加固时再开启;

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

参数 enableProxyApplication = true,无需改造 Application;

    // 是否采用反射Application的方式集成,无须改造Application
    enableProxyApplication = true

新建 MyApplication 加入下面代码:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        setStrictMode();
        // 设置是否开启热更新能力,默认为true
        Beta.enableHotfix = true;
        // 设置是否自动下载补丁
        Beta.canAutoDownloadPatch = true;
        // 设置是否提示用户重启
        Beta.canNotifyUserRestart = false;
        // 设置是否自动合成补丁
        Beta.canAutoPatch = true;

        /**
         * 补丁回调接口,可以监听补丁接收、下载、合成的回调
         */
        Beta.betaPatchListener = new BetaPatchListener() {
            @Override
            public void onPatchReceived(String patchFileUrl) {
                //补丁包下载地址为patchFileUrl
            }

            @Override
            public void onDownloadReceived(long savedLength, long totalLength) {
                //热修复回调成功
            }

            @Override
            public void onDownloadSuccess(String patchFilePath) {
                //热修复下载成功
            }

            @Override
            public void onDownloadFailure(String msg) {
                //热修复下载失败
            }

            @Override
            public void onApplySuccess(String msg) {
                //补丁包应用成功
            }

            @Override
            public void onApplyFailure(String msg) {
                //补丁包应用失败
            }

            @Override
            public void onPatchRollback() {
                //补丁回滚
            }
        };

        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, "4bf2a8d8eb", true);
        long end = System.currentTimeMillis();
        Log.e("init time--->", end - start + "ms");
}

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // 热更新必须添加
        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());
    }
}

别忘记在 AndroidManifest.xml 中使用:

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

需要注意的是,下面的代码中要换成你申请的 appId:

        // 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId,调试时将第三个参数设置为true
        Bugly.init(this, "4bf2a8d8eb", true);

AndroidManifest.xml 文件中添加下面代码:

        <!-- Bugly升级SDK配置开始  -->
        <activity
                android:name="com.tencent.bugly.beta.ui.BetaActivity"
                android:theme="@android:style/Theme.Translucent"/>

        <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.tencent.bugly.hotfix.easy.fileProvider"
                android:exported="false"
                android:grantUriPermissions="true">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
        </provider>

        <!-- Bugly升级SDK配置结束-->

参考下图:

加入权限:

    <!--Bugly升级SDK权限配置开始-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
    <!-- <uses-permission android:name="android.permission.GET_TASKS" /> -->

    <!--Bugly升级SDK权限配置结束-->

在 xml 中的 provider_paths 加入代码,没有请创建:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- /storage/emulated/0/Download/com.bugly.upgrade.demo/.beta/apk-->
    <external-path name="beta_external_path" path="Download/"/>
    <!--/storage/emulated/0/Android/data/com.bugly.upgrade.demo/files/apk/-->
    <external-path name="beta_external_files_path" path="Android/data/"/>
</paths>

参考下图:

MainActivity 中加入代码:

public class MainActivity extends AppCompatActivity {
    private Button button; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "这是存在bug的", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

里面只有一个 button ;

最后加入混淆:

# Bugly混淆规则
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }

参考下图:

多渠道打包配置,暂时配置三个:

    productFlavors {
        huawei {

//            applicationId "com.tencent.bugly.hotfix.huawei"
            manifestPlaceholders = [CHANNEL_VALUE: "huawei"]
        }
        qihu360 {
//            applicationId "com.tencent.bugly.hotfix.qihu360"
            manifestPlaceholders = [CHANNEL_VALUE: "qihu360"]
        }
        oppo {
//            applicationId "com.tencent.bugly.hotfix.oppo"
            manifestPlaceholders = [CHANNEL_VALUE: "oppo"]
        }
    }

作为参考我给出我的 build.gradle 所有代码:

apply plugin: 'com.android.application'

// 依赖插件脚本
apply from: 'tinker-support.gradle'

android {
    compileSdkVersion 26
    buildToolsVersion '26.0.2'
    defaultConfig {
        applicationId "com.tencent.bugly.hotfix.easy"
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 3
        versionName "1.0"
        flavorDimensions "versionCode"

        // 开启multidex
        multiDexEnabled true
    }


    // 签名配置
    signingConfigs {
        release {
            try {
                storeFile file("./keystore/release.keystore")
                storePassword "testres"
                keyAlias "testres"
                keyPassword "testres"
            } catch (ex) {
                throw new InvalidUserDataException(ex.toString())
            }
        }

        debug {
            storeFile file("./keystore/debug.keystore")
        }
    }

    buildTypes {
        release {
            minifyEnabled true
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            debuggable true
            minifyEnabled false
            // signingConfig signingConfigs.debug
        }
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    repositories {
        flatDir {
            dirs 'libs'
        }
    }

    // productFlavors 示例
    //flavorDimensions "tier"


    productFlavors {
        huawei {

//            applicationId "com.tencent.bugly.hotfix.huawei"
            manifestPlaceholders = [CHANNEL_VALUE: "huawei"]
        }
        qihu360 {
//            applicationId "com.tencent.bugly.hotfix.qihu360"
            manifestPlaceholders = [CHANNEL_VALUE: "qihu360"]
        }
        oppo {
//            applicationId "com.tencent.bugly.hotfix.oppo"
            manifestPlaceholders = [CHANNEL_VALUE: "oppo"]
        }
    }

    lintOptions {
        checkReleaseBuilds false
        abortOnError false
    }
}


dependencies {

    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:26.1.0'

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

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

}

上面的签名配置是我从 BuglyHotfixEasyDemo 中直接复制过来的;

所有配置完毕,下面就测试打包,点击右侧 Gradle ==> app ==> Tasks ==> build ==>assembleDebug ,如下图:

打包完毕,在左侧 app ==> bakApk 可以看到躺着三个包,这就是基准包,如下图:

需要注意的是:一般在正式的情况下,需要将 bakApk 文件夹里面的内容保存到本地,方便以后打补丁包使用,如果不存在了,直接复制到 bakApk 文件夹下面就可以了。

记住上面的 app-1126-16-12-58,也就是 bakApk ==> app-1126-16-12-58 ,这个是随机生成的,下面会使用到这个;

打开 tinker-support.gradle,找到 baseApkDir 参数,将里面的内容替换为 app-1126-16-12-58 ;如下图:

需要注意的是:你生成的是什么就写什么,这个是每打一次基准包,需要填写一次,打补丁包不需要改变;

一定要保证该目录下面有对应的包,这也就是上面为什么让你把基准包保存到本地的原因,以防丢失;

为了方便测试,将 MainActivity 中的提示改为下面:

Toast.makeText(MainActivity.this, "修复了bug,以便测试", Toast.LENGTH_SHORT).show();

点击右侧 Gradle ==> app ==> Tasks ==> tinker-support ==>buildAllFlavorsTinkerPatchDebug ,如下图:

等待过后,补丁包就打完了,在左侧 app ==> outputs ==> patch 中可以看到三个补丁包,如下图:

上面以 7-zip 结尾就是我们的补丁包了,也就是 patch_signed_7zip.apk  ,也就是把这个包放到 bugly 官网就可以了;

下面就可以测试了,测试的时候需要注意:一定先将基本包安装到手机上,保证有网络的情况下打开 app ,让热更新代码走完补丁包才可以上传到 bugly 官网,否则上传不上去;

下面将基本包放到手机上面运行,因为打了三个包,就拿华为的包测试;

安装完毕,点击按钮可以发现,提示:这是存在bug的;与基本包一致,emmm;

打开 bugly 官网,将补丁包上传到官网,点击应用升级==>热更新==>发布新补丁,如下图所示:

不要上传错了,我们测试的是华为的基本包,所以补丁包也应该上传华为下面的 patch_signed_7zip.apk ;

上传如果提示,改包不合法,那么刷新页面再试一下,或者重新打开基本包的 app ;因为我也遇到过,是 bugly 后台的问题;

上传完毕,会自动识别版本,选择全量更新,写上备注,然后点击立即下发就可以了,如下图:

稍等片刻,就可以出现了,如下图:

我上面有两个,因为我已经测试过一次了,如果你们第一次测试,应该是一个。

热更新官网说是重启 app 就可以修复了,经过我测试,大概需要5分钟的时间,补丁才会生效,所以不必着急;

经过几分钟的重启 app ,点击按钮测试,发现提示语变成了:修复了bug,以便测试;

说明补丁包应用成功了,打开 bugly 官网,刷新页面,可以看到已经下发了一个了,如下图所示:

可以看到激活的数量为0,但我们已经应用成功了,因为有延迟,所以再过大概10分钟就可以看到激活量为1了,所以不用着急;

看完这个简单集成方式以后,再看 BuglyHotfixDemo 或者官网文档就会感觉简单多了。

如果你有什么问题,可以看下面我写的 demo ,或者留言;

https://github.com/wuqingsen/BuglyDemo

到这里就结束了。

记录一个bug,测试上没问题,但是我在正式上面先发成功,但是激活数量一直为0,如下图所示:

解决方法,在项目的 bulid.gradle 中的配置改为:

classpath "com.tencent.bugly:tinker-support:latest.release"

就好了,我之前用的是:

//        classpath 'com.tencent.bugly:tinker-support:1.1.5' //之前配置
        classpath "com.tencent.bugly:tinker-support:latest.release" //修改后

做一下记录。

发布了322 篇原创文章 · 获赞 450 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/wuqingsen1/article/details/103256807