使用Tinker与极光推送实现Android热更新

本文详细介绍如何使用Tinker实现Android应用的热更新功能,包括Tinker平台与Android Studio的配置步骤、JPush推送补丁包的实现方法及完整的热更新流程。

一、Tinker平台的配置

Tinker的注册不做赘述,打开Tinker PlatformApp管理界面,新增自己的App。输入App名称新增成功之后会进入到App详情界面,这个界面左侧的appKey在下面的配置中会用到。

二、Tinker在AndroidStudio上的配置与初始化

1.配置gradle文件:

1)打开build.gradle,添加版本库与依赖包:

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.7"
    }
}

dependencies {
    。。。
    provided 'com.tinkerpatch.tinker:tinker-android-anno:1.7.11'
    compile 'com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.7'
    compile 'com.android.support:multidex:1.0.1'
}

2)在build.gradle所在目录下新建tinkerpatch.gradle,添加如下内容:

apply plugin: 'tinkerpatch-support'

def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "app-1.0.2-0721-09-46-04" // 这个值是生成patch的对比包
def variantName = "release"

tinkerpatchSupport {
    tinkerEnable = true
    reflectApplication = false
    autoBackupApkPath = "${bakPath}"
    appKey = "your appkey"
    /** 注意:appVersion是当前app的版本号,若发布新的全量包, appVersion一定要更新 **/
    appVersion = "1.0.2"

    def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
    def name = "${project.name}-${variantName}"
    baseApkFile = "${pathPrefix}/${name}.apk"
    baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
    baseResourceRFile = "${pathPrefix}/${name}-R.txt"
}

android {
    defaultConfig {
        buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
    }
    signingConfigs { // 签名文件的配置
        release {
            try {
                storeFile file("your store file")
                storePassword "your store password"
                keyAlias "your key alias"
                keyPassword "your key password"
            } catch (ex) {
                throw new InvalidUserDataException(ex.toString())
            }
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
/** 以下配置不用做修改 **/
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"
    }
    buildConfig {
        keepDexApply = false
    }
}

3)在build.gradle中通过apply from: 'tinkerpatch.gradle'引入tinkerpatch.gradle

2.Tinker在Android工程里的初始化

1)新建ApplicationLike文件,并在这个文件中对Tinker进行初始化配置

@SuppressWarnings("unused")
public class MyApplicationLike extends DefaultApplicationLike {
    private static final String TAG = "sglei-tinker";

    public MyApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
                             long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        MultiDex.install(base);
    }

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

    private void initTinker() {
        if (BuildConfig.TINKER_ENABLE) {
            TinkerPatch.init(this)
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true)
                    .setFetchPatchIntervalByHours(3)
                    .setPatchResultCallback(new ResultCallBack() {
                        @Override
                        public void onPatchResult(PatchResult patchResult) {
                            Log.i(TAG, "补丁安装结果:" + patchResult.toString());
                        }
                    });
            Log.d(TAG, "current patch version is " + TinkerPatch.with().getPatchVersion());
            TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
        }
    }
}

2)新建自己的Application文件,这个Application继承自com.tencent.tinker.loader.app.TinkerApplication,而不是android.app.Application

public class MyApplication extends TinkerApplication {

    public MyApplication() {
      super(ShareConstants.TINKER_ENABLE_ALL, "com.fablesmart.pagc.MyApplicationLike");//这里修改为上面自己的ApplicationLike路径
    }
}

此时,Tinker的配置已经全部完成,TinkerPatch.with().fetchPatchUpdateAndPollWithInterval()会通过初始化中setFetchPatchIntervalByHours(3)设置的3小时轮询一次的频率向TinkerPlatform请求patch,如果有新的patch,便会下载与更新。若更新成功,在下一次启动App时,更新的patch会生效。

考虑到用户使用期间,我们下发了patch,如果用户使用的时间小于上面设置的interval,便很有可能执行不到请求patch的操作。为了保证patch的及时性,也就是保证用户不需要重启两次app才能完成更新,下发补丁的时候,我们使用极光推送自定义消息来通知app请求patch。

三、JPush的配置

极光推送的在AndroidStudio上的配置详见极光推送SDK集成指南
关于Tinker,我们所做的修改是新建一个接收器。代码如下:

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        String content = bundle.getString(JPushInterface.EXTRA_MESSAGE);
        Log.d("sglei-tinker", "jpush content = " + content);
    // JPush推送的消息如果包含tinker字符,便向TinkerPlatform请求patch并更新。
        if (content.contains("tinker")) {
            TinkerPatch.with().fetchPatchUpdate(true);
        }
    }
}

MyRecevier在AndroidManifest的配置如下:

<receiver
    android:name=".MyReceiver"
    android:exported="false"
    android:enabled="true">
    <intent-filter>
        <action android:name="cn.jpush.android.intent.REGISTRATION" />
        <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" />
        <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" />
        <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" />
        <action android:name="cn.jpush.android.intent.CONNECTION" />
        <category android:name="your application id" />
    </intent-filter>
</receiver>

三、Tinker与JPush实现热更新的完整操作流程。

1.生成release版本的oldApk

生成apk的方法有两种:a)打开AndroidStudio的Terminal控制台,输入命令“gradlew assembleRelease”;b)打开AndroidStudio右侧的Gradle侧边栏,双击root目录下的Tasks/build/assembleRelease。
根据tinkerpatch.gradle的配置,会在app/build/bakApk目录下生成一个当前日期的app文件夹,文件夹包括release版本的apk。这个apk可以看做包含bug的签名包,也就是我们的oldApk。

2.生成Tinker补丁包

我们修复上述apk的bug,这里的修复可以修改java文件、assets与res下的资源文件等。代码与资源文件修改完成后,需要将tinkerpatch.gradle中的baseInfo改成oldApk所在的文件夹
生成patch的方法也是两种:a)打开Terminal控制台,执行“gradlew tinkerPatchRelease”;B)双击root目录下的Tasks/tinker/tinkerPatchRelease。
根据tinkerpatch.gradle的配置,会在app/build/bakApk目录下生成release版本的已修复bug的新apk,并在app/build/outputs/tinkerPatch/release文件夹下生成补丁包patch_signed.apk

3.上传Tinker补丁包并发布

1)打开TinkerPlatform的App详情页,若oldApk的版本号还未添加到该App中,点击“添加app版本”,输入版本号(这里的版本后必须和oldApk的版本号保持一致,否则oldApk读取不到我们上传到该版本的patch)。
2)点击刚刚添加的版本号,点击“选择文件”,将刚刚生成的patch_signed.apk上传,点击“提交”,该patch即上传成功。

4.JPush发送一条包含”tinker”字符的自定义消息

打开JPush控制台,创建一条自定义消息,并将发送内容填为“tinker”。发送该自定义消息。

5.重启App,patch生效

App会上面发送的自定义消息,并执行TinkerPatch.with().fetchPatchUpdate(true)
若补丁包安装成功,下次启动App的时候,oldApk所含的bug已经修复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值