androidalipay trade sdk.jar jar 怎么热更新

Bugly热更新SDK你需要知道的一些事 - 简书
Bugly热更新SDK你需要知道的一些事
Bugly出热更新SDK了?
没错,Bugly也出热更新SDK啦,号,我们Bugly也上线了Android版的热更新SDK,大家都知道这一年来热更新被无数次提起,各大厂自主研发的热更新方案层出不穷,下面就列举一些大家比较熟悉的一些热更新方案:
微信开源:大众点评:阿里巴巴:阿里巴巴:美团:
各个方案的优劣性笔者就不在这里做过多讨论了,总的一句话没有最好的,只有最适合自己的。
我们Bugly也是出于高可用性的考虑,Tinker支持动态下发代码、So库以及资源,所以我们最终选择了Tinker方案作为我们SDK的一项能力。
这里有一点需要说明的,Android版的热更新SDK是包含在升级SDK里面的,所以如果你想使用我们提供的热更新能力需要下载对应版本的,目前我们在1.2.0版本才开始支持热更新:
&font color="red"&注意:升级SDK自1.2.0起将不再支持以jar包形式集成,我们建议您使用Android studio并且以gradle方式集成。&/font&
为什么集成我们Bugly热更新SDK?
热更新能力是Bugly为解决开发者紧急修复线上Bug,而无需重新发版让用户无感知就能把问题修复的一项能力。Bugly目前采用的开源方案,开发者只需要集成我们提供的SDK就可以实现自动下载补丁包、合成、并且应用补丁的功能,我们也提供了热更新管理后台让开发者对每个版本的补丁进行管理。
集成我们SDK的好处是显而易见的:
无需关注Tinker是如何合成补丁的
无需自己搭建补丁管理后台
无需考虑后台下发补丁策略的任何事情
无需考虑补丁下载合成的时机,处理后台下发的策略
我们提供了更加方便集成Tinker的方式
我们提供应用升级一站式解决方案
Uploading 2_453273.png . . .]
如何集成Bugly热更新SDK?
看文档、看文档、看文档。重要的事情说三遍。
相信接入过Tinker的同学会发现使用Tinker还是有一定门槛的,小白用户第一次使用可能会懵圈,我们Bugly也希望能让第一次接入的同学能顺利使用上热更新,所以建议大家严格按照我们文档的流程来接入,如果遇到任何使用SDK的问题可以及时跟我们反馈(交流群号:),但如果是Tinker插件的使用问题也是建议您认真查看。
简单概要说一下整个接入流程:
配置插件依赖(这里包含tinker插件和tinker-support插件的依赖)
apply插件(这里可以只配置apply plugin: 'com.tencent.bugly.tinker-support')
集成远程SDK仓库
重新自定义Application、ApplicationLike
AndroidManifest配置
打基准包安装并上报联网(注:填写唯一的tinkerId)
对基准包的bug修复(可以是Java代码变更,资源的变更)
修改基准包路径、填写补丁包tinkerId、mapping文件路径、resId文件路径
执行tinkerPatchRelease打Release版本补丁包
选择app/build/outputs/patch目录下的补丁包并上传(注:不要选择tinkerPatch目录下的补丁包,不然上传会有问题)
编辑下发补丁规则,点击立即下发
重启基准包,请求补丁策略(SDK会自动下载补丁并合成)
再次重启基准包,检验补丁应用结果
以上是应用补丁的流程,有同学可能会问,如果我想撤回怎么办?这里先解释下我们补丁的几种状态:
生效中、下发停止
下发中:表示你上传一个补丁后,点击立即下发之后的状态,表示后台正在下发补丁策略,补丁包对应的基线版本是可以收到对应的策略的。
生效中、下发停止:表示你已经下发过这个补丁,但因为你上传了新补丁,这个补丁下发会被停止,要注意一个目标版本只运行下发一个补丁。
撤回中:表示你不再下发这个补丁,这个操作是不可逆的,点击撤回,基线版本将不会再收到这个补丁策略。
以上就是Bugly热更新SDK的集成方式一些说明啦,如果还有疑问直接找Bugly-kirito咨询。
一些大家比较关注的问题
Q:Bugly热更新会收费么?
A:大家可以放心,我们热更新服务目前是完全免费的。
Q:之前使用Tinker,怎么切换过来使用Bugly?
A: 你只需在dependencies中配置一句代码:
compile "com.tencent.bugly:crashreport_upgrade:1.2.0"
注释掉以前的配置:
// 可选,用于生成application类
//provided('com.tencent.tinker:tinker-android-anno:1.7.5')
// tinker的核心库
// compile('com.tencent.tinker:tinker-android-lib:1.7.5')
插件配置不需要更改,只需要加上我们Bugly额外的tinker-support插件即可:
// tinker gradle插件
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.5')
// tinkersupport插件
classpath "com.tencent.bugly:tinker-support:1.0.1"
这里建议您不要随便更改插件版本,避免因为插件的更新导致您无法正常生成我们需要的补丁包。
Q:如果我配置了升级策略,又配置了补丁策略,会是怎样的效果?
A:升级策略优先级会高于补丁策略,后台会优先下发升级策略。毕竟你都要升级了,热更新只是帮助你修复bug而已。
Q:我只想使用热更新,不想使用升级?
A:热更新是包含在升级SDK里面的,你可以不配置任何升级策略,只需按照热更新文档集成即可。
Q:是否支持加固模式?
A:tinker是支持加固模式的,但需要你回退到Qzone方案,将usePreGeneratedPatchDex设置为true。
但要注意Tinker官方的提示:
是否提前生成dex,而非合成的方式。这套方案即回退成Qzone的方案,对于需要使用加固或者多flavor打包(建议使用其他方式生成渠道包)的用户可使用。但是这套方案需要插桩,会造成Dalvik下性能损耗以及Art补丁包可能过大的问题,务必谨慎使用。另外一方面,这种方案在Android N之后可能会产生问题,建议过滤N之后的用户。
Q:是否支持打多Flavor的patch包A:支持的。你需要配置productFlavor(示例):
productFlavors {
applicationId 'com.tencent.bugly.hotfix.xiaomi'
applicationId 'com.tencent.bugly.hotfix.yyb'
打flavor包,只需要配置构建flavor的目录,其他字段不需要填写(执行tinkerPatchAllFalvorRelease就可以得到所有flavor的包):
tinker task.png
关于Bugly热更新SDK你需要知道的一些事情,笔者已经讲完啦,如果你在使用过程中遇到任何问题可以及时跟我们反馈,我们会持续跟进优化SDK和完善接入流程,后续我们会分享更多我们Bugly关于热更新的一些技术和原理上的理解,希望本篇文章能够让使用Bugly热更新SDK的同学和想了解我们热更新的同学的有一些解惑。Android微信Tinker热更新详细使用
作者:Gimi丶
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android微信Tinker热更新的详细使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
先看一下效果图
Tinker已知问题
由于原理与系统限制,Tinker有以下已知问题:
Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件;
由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
在Android N上,补丁对应用启动时间有轻微的影响;
不支持部分三星android-21机型,加载补丁时会主动抛出”TinkerRuntimeException:checkDexInstall failed”;
由于各个厂商的加固实现并不一致,在1.7.6以及之后的版本,tinker不再支持加固的动态更新;
对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。
1.首先在项目的build中,集成tinker插件 ,如下所示(目前最新版是1.7.6)
先看结构图,只有几个类而已:
项目中的build集成
buildscript {
repositories {
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.6')
// NOTE: Do not place your applicati they belong
// in the individual module build.gradle files
allprojects {
repositories {
task clean(type: Delete) {
delete rootProject.buildDir
1.再将app的build中的关联属性添加进去,这些属性都是经过测试过的,都有注释显示,如果自己需要其他属性,可以自己去github上查看并集成,文章末尾会送上地址,ps:官方的集成特别麻烦,有时候一整天都有可能搞不定,根据自己的需求和情况来添加,末尾会送上demo
apply plugin: 'com.android.application'
def javaVersion = JavaVersion.VERSION_1_7
compileSdkVersion 23
buildToolsVersion "23.0.2"
compileOptions {
sourceCompatibility javaVersion
targetCompatibility javaVersion
//recommend
dexOptions {
jumboMode = true
defaultConfig {
applicationId "com.tinker.demo.tinkerdemo"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildConfigField "String", "MESSAGE", "\"I am the base apk\""
buildConfigField "String", "TINKER_ID", "\"${getTinkerIdValue()}\""
buildConfigField "String", "PLATFORM", "\"all\""
signingConfigs {
storeFile file("./keystore/release.keystore")
storePassword "testres"
keyAlias "testres"
keyPassword "testres"
} catch (ex) {
throw new InvalidUserDataException(ex.toString())
storeFile file("./keystore/debug.keystore")
buildTypes {
minifyEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
minifyEnabled false
signingConfig signingConfigs.debug
sourceSets {
jniLibs.srcDirs = ['libs']
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
compile "com.android.support:appcompat-v7:23.1.1"
testCompile 'junit:junit:4.12'
compile("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}") { changing = true }
provided("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}") { changing = true }
compile "com.android.support:multidex:1.0.1"
def gitSha() {
// String gitRev = 'git rev-parse --short HEAD'.execute(null, project.rootDir).text.trim()
String gitRev = "1008611"
if (gitRev == null) {
throw new GradleException("can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'")
return gitRev
} catch (Exception e) {
throw new GradleException("can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'")
def bakPath = file("${buildDir}/bakApk/")
//for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
tinkerEnabled = true
//for normal build
//old apk file to build patch apk
tinkerOldApkPath = "${bakPath}/app-debug--29.apk"
//proguard mapping file to build patch apk
tinkerApplyMappingPath = "${bakPath}/app-debug--47-mapping.txt"
//resource R.txt to build patch apk, must input if there is resource changed
tinkerApplyResourcePath = "${bakPath}/app-debug--29-R.txt"
//only use for build all flavor, if not, just ignore this field
tinkerBuildFlavorDirectory = "${bakPath}/app--47"
def getOldApkPath() {
return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath
def getApplyMappingPath() {
return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath
def getApplyResourceMappingPath() {
return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath
def getTinkerIdValue() {
return hasProperty("TINKER_ID") ? TINKER_ID : gitSha()
def buildWithTinker() {
return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled
def getTinkerBuildFlavorDirectory() {
return ext.tinkerBuildFlavorDirectory
if (buildWithTinker()) {
apply plugin: 'com.tencent.tinker.patch'
tinkerPatch {
* 默认为null
* 将旧的apk和新的apk建立关联
* 从build / bakApk添加apk
oldApk = getOldApkPath()
* 可选,默认'false'
*有些情况下我们可能会收到一些警告
*如果ignoreWarning为true,我们只是断言补丁过程
* case 1:minSdkVersion低于14,但是你使用dexMode与raw。
* case 2:在AndroidManifest.xml中新添加Android组件,
* case 3:装载器类在dex.loader {}不保留在主要的dex,
* 它必须让tinker不工作。
* case 4:在dex.loader {}中的loader类改变,
* 加载器类是加载补丁dex。改变它们是没有用的。
* 它不会崩溃,但这些更改不会影响。你可以忽略它
* case 5:resources.arsc已经改变,但是我们不使用applyResourceMapping来构建
ignoreWarning = false
*可选,默认为“true”
* 是否签名补丁文件
* 如果没有,你必须自己做。否则在补丁加载过程中无法检查成功
* 我们将使用sign配置与您的构建类型
useSign = true
可选,默认为“true”
是否使用tinker构建
tinkerEnable = buildWithTinker()
* 警告,applyMapping会影响正常的android build!
buildConfig {
*可选,默认为'null'
* 如果我们使用tinkerPatch构建补丁apk,你最好应用旧的
* apk映射文件如果minifyEnabled是启用!
* 警告:你必须小心,它会影响正常的组装构建!
applyMapping = getApplyMappingPath()
*可选,默认为'null'
* 很高兴保持资源ID从R.txt文件,以减少java更改
applyResourceMapping = getApplyResourceMappingPath()
*必需,默认'null'
* 因为我们不想检查基地apk与md5在运行时(它是慢)
* tinkerId用于在试图应用补丁时标识唯一的基本apk。
* 我们可以使用git rev,svn rev或者简单的versionCode。
* 我们将在您的清单中自动生成tinkerId
tinkerId = getTinkerIdValue()
*如果keepDexApply为true,则表示dex指向旧apk的类。
* 打开这可以减少dex diff文件大小。
keepDexApply = false
*可选,默认'jar'
* 只能是'raw'或'jar'。对于原始,我们将保持其原始格式
* 对于jar,我们将使用zip格式重新包装dexes。
* 如果你想支持下面14,你必须使用jar
* 或者你想保存rom或检查更快,你也可以使用原始模式
dexMode = "jar"
*必需,默认'[]'
* apk中的dexes应该处理tinkerPatch
* 它支持*或?模式。
pattern = ["classes*.dex",
"assets/secondary-dex-?.jar"]
*必需,默认'[]'
* 警告,这是非常非常重要的,加载类不能随补丁改变。
* 因此,它们将从补丁程序中删除。
* 你必须把下面的类放到主要的dex。
* 简单地说,你应该添加自己的应用程序{@code tinker.sample.android.SampleApplication}
* 自己的tinkerLoader,和你使用的类
loader = [
//use sample, let BaseBuildInfo unchangeable with tinker
"tinker.sample.android.app.BaseBuildInfo"
可选,默认'[]'
apk中的图书馆应该处理tinkerPatch
它支持*或?模式。
对于资源库,我们只是在补丁目录中恢复它们
你可以得到他们在TinkerLoadResult与Tinker
pattern = ["lib/armeabi/*.so"]
*可选,默认'[]'
* apk中的什么资源应该处理tinkerPatch
* 它支持*或?模式。
* 你必须包括你在这里的所有资源,
* 否则,他们不会重新包装在新的apk资源。
pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
*可选,默认'[]'
*资源文件排除模式,忽略添加,删除或修改资源更改
* *它支持*或?模式。
* *警告,我们只能使用文件没有relative与resources.arsc
ignoreChange = ["assets/sample_meta.txt"]
*默认100kb
* *对于修改资源,如果它大于'largeModSize'
* *我们想使用bsdiff算法来减少补丁文件的大小
largeModSize = 100
packageConfig {
*可选,默认'TINKER_ID,TINKER_ID_VALUE','NEW_TINKER_ID,NEW_TINKER_ID_VALUE'
* 包元文件gen。路径是修补程序文件中的assets / package_meta.txt
* 你可以在您自己的PackageCheck方法中使用securityCheck.getPackageProperties()
* 或TinkerLoadResult.getPackageConfigByName
* 我们将从旧的apk清单为您自动获取TINKER_ID,
* 其他配置文件(如下面的patchMessage)不是必需的
configField("patchMessage", "tinker is sample to use")
*只是一个例子,你可以使用如sdkVersion,品牌,渠道...
* 你可以在SamplePatchListener中解析它。
* 然后你可以使用补丁条件!
configField("platform", "all")
* 补丁版本通过packageConfig
configField("patchVersion", "1.0")
//或者您可以添加外部的配置文件,或从旧apk获取元值
//project.tinkerPatch.packageConfig.configField("test1", project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test"))
//project.tinkerPatch.packageConfig.configField("test2", "sample")
* 如果你不使用zipArtifact或者path,我们只是使用7za来试试
sevenZip {
* 可选,默认'7za'
* 7zip工件路径,它将使用正确的7za与您的平台
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
* 可选,默认'7za'
* 你可以自己指定7za路径,它将覆盖zipArtifact值
// path = "/usr/local/bin/7za"
List&String& flavors = new ArrayList&&();
project.android.productFlavors.each {flavor -&
flavors.add(flavor.name)
boolean hasFlavors = flavors.size() & 0
* bak apk and mapping
android.applicationVariants.all { variant -&
* task type, you want to bak
def taskName = variant.name
def date = new Date().format("MMdd-HH-mm-ss")
tasks.all {
if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
it.doLast {
def fileNamePrefix = "${project.name}-${variant.baseName}"
def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}"
def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath
from variant.outputs.outputFile
into destPath
rename { String fileName -&
fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")
from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"
into destPath
rename { String fileName -&
fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")
from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"
into destPath
rename { String fileName -&
fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")
project.afterEvaluate {
//sample use for build all flavor for one time
if (hasFlavors) {
task(tinkerPatchAllFlavorRelease) {
group = 'tinker'
def originOldPath = getTinkerBuildFlavorDirectory()
for (String flavor : flavors) {
def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release")
dependsOn tinkerTask
def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest")
preAssembleTask.doFirst {
String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15)
project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk"
project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt"
project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt"
task(tinkerPatchAllFlavorDebug) {
group = 'tinker'
def originOldPath = getTinkerBuildFlavorDirectory()
for (String flavor : flavors) {
def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug")
dependsOn tinkerTask
def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest")
preAssembleTask.doFirst {
String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13)
project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk"
project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt"
project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt"
3.在清单文件中集成application和服务 ,name的application必须是.AMSKY,如果你添加不进去,或者是红色的话,请先build一下,如果你已经有了自己的application,后面我会说怎么来集成,Service中做的操作是在你加载成功热更新插件后,会提示你更新成功,并且这里做了锁屏操作就会加载热更新插件,继续往下看。
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="com.tinker.demo.tinkerdemo"&
&uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&
&uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/&
&application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".AMSKY"
android:theme="@style/AppTheme"&
android:name=".service.SampleResultService"
android:exported="false"/&
&activity android:name=".MainActivity"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&/application&
&/manifest&
4.到这里就已经基本集成的差不多了,剩下的就是代码里面的集成,首先是application,这里主要说如果是自已已经存在的application的时候改怎么操作 ,这个applicaiton可以说就是自己的一个application,只不过写法,要这样去写,可以在onCreate中做自己的一些操作,只不过清单文件中,要写AMSKY
@SuppressWarnings("unused")
@DefaultLifeCycle(application = "com.tinker.demo.tinkerdemo.AMSKY",
flags = ShareConstants.TINKER_ENABLE_ALL,
loadVerifyFlag = false)
public class SampleApplicationLike extends DefaultApplicationLike {
private static final String TAG = "Tinker.SampleApplicationLike";
public SampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent,Resources[] resources, ClassLoader[] classLoader, AssetManager[] assetManager) {
super(application,tinkerFlags,tinkerLoadVerifyFlag,applicationStartElapsedTime,applicationStartMillisTime, tinkerResultIntent, resources, classLoader, assetManager);
* install multiDex before install tinker
* so we don't need to put the tinker lib classes in the main dex
* @param base
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
//MultiDex必须在Tinker初始化之前
MultiDex.install(base);
//这里就是初始化Tinker
TinkerInstaller.install(this,new DefaultLoadReporter(getApplication()),new DefaultPatchReporter(getApplication()),
new DefaultPatchListener(getApplication()),SampleResultService.class,new UpgradePatch());
Tinker tinker = Tinker.with(getApplication());
//这个只是一个Toast提示
Toast.makeText(
getApplication(),"没鸟用,就是Toast提示而已", Toast.LENGTH_SHORT).show();
public void onCreate() {
super.onCreate();
//这里可以做自己的操作
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
getApplication().registerActivityLifecycleCallbacks(callback);
5.这里就是在MainActivity中来加载热更新文件,在点击加载的时候,就直接锁屏加载(不要删除service),当然退出app,下次进来也是可以加载的吗,这里加载补丁插件的话,路径可以自己设置,我是放在根目录的debug文件夹当中的,并且我的补丁插件名字叫patch,可以自行更改。
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
* 加载热补丁插件
* @param v
public void loadPatch(View v) {
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), "/sdcard/debug/patch.apk");
* 杀死应用加载补丁
* @param v
public void killApp(View v) {
ShareTinkerInternals.killAllOtherProcess(getApplicationContext());
android.os.Process.killProcess(android.os.Process.myPid());
protected void onResume() {
super.onResume();
Utils.setBackground(false);
protected void onPause() {
super.onPause();
Utils.setBackground(true);
6.Service文件
public class SampleResultService extends DefaultTinkerResultService {
private static final String TAG = "Tinker.SampleResultService";
public void onPatchResult(final PatchResult result) {
if (result == null) {
TinkerLog.e(TAG, "SampleResultService received null result!!!!");
TinkerLog.i(TAG, "SampleResultService receive result: %s", result.toString());
//first, we want to kill the recover process
TinkerServiceInternals.killTinkerPatchServiceProcess(getApplicationContext());
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
if (result.isSuccess) {
Toast.makeText(getApplicationContext(), "patch success, please restart process", Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "patch fail, please check reason", Toast.LENGTH_LONG).show();
// is success and newPatch, it is nice to delete the raw file, and restart at once
// for old patch, you can't delete the patch file
if (result.isSuccess) {
File rawFile = new File(result.rawPatchFilePath);
if (rawFile.exists()) {
TinkerLog.i(TAG, "save delete raw patch file");
SharePatchFileUtil.safeDeleteFile(rawFile);
//not like TinkerResultService, I want to restart just when I am at background!
//if you have not install tinker this moment, you can use TinkerApplicationHelper api
if (checkIfNeedKill(result)) {
if (Utils.isBackground()) {
TinkerLog.i(TAG, "it is in background, just restart process");
restartProcess();
//we can wait process at background, such as onAppBackground
//or we can restart when the screen off
TinkerLog.i(TAG, "tinker wait screen to restart process");
new ScreenState(getApplicationContext(), new ScreenState.IOnScreenOff() {
public void onScreenOff() {
restartProcess();
TinkerLog.i(TAG, "I have already install the newly patch version!");
* you can restart your process through service or broadcast
private void restartProcess() {
TinkerLog.i(TAG, "app is background now, i can kill quietly");
//you can send service or broadcast intent to restart your process
android.os.Process.killProcess(android.os.Process.myPid());
static class ScreenState {
interface IOnScreenOff {
void onScreenOff();
ScreenState(Context context, final IOnScreenOff onScreenOffInterface) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(new BroadcastReceiver() {
public void onReceive(Context context, Intent in) {
String action = in == null ? "" : in.getAction();
TinkerLog.i(TAG, "ScreenReceiver action [%s] ", action);
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
context.unregisterReceiver(this);
if (onScreenOffInterface != null) {
onScreenOffInterface.onScreenOff();
}, filter);
7.Utils文件
public class Utils {
* the error code define by myself
* should after {@code ShareConstants.ERROR_PATCH_INSERVICE
public static final int ERROR_PATCH_GOOGLEPLAY_CHANNEL = -5;
public static final int ERROR_PATCH_ROM_SPACE
public static final int ERROR_PATCH_MEMORY_LIMIT
public static final int ERROR_PATCH_ALREADY_APPLY
public static final int ERROR_PATCH_CRASH_LIMIT
public static final int ERROR_PATCH_RETRY_COUNT_LIMIT = -10;
public static final int ERROR_PATCH_CONDITION_NOT_SATISFIED = -11;
public static final String PLATFORM = "platform";
public static final int MIN_MEMORY_HEAP_SIZE = 45;
private static boolean background =
public static boolean isGooglePlay() {
public static boolean isBackground() {
public static void setBackground(boolean back) {
background =
public static int checkForPatchRecover(long roomSize, int maxMemory) {
if (Utils.isGooglePlay()) {
return Utils.ERROR_PATCH_GOOGLEPLAY_CHANNEL;
if (maxMemory & MIN_MEMORY_HEAP_SIZE) {
return Utils.ERROR_PATCH_MEMORY_LIMIT;
//or you can mention user to clean their rom space!
if (!checkRomSpaceEnough(roomSize)) {
return Utils.ERROR_PATCH_ROM_SPACE;
return ShareConstants.ERROR_PATCH_OK;
public static boolean isXposedExists(Throwable thr) {
StackTraceElement[] stackTraces = thr.getStackTrace();
for (StackTraceElement stackTrace : stackTraces) {
final String clazzName = stackTrace.getClassName();
if (clazzName != null && clazzName.contains("de.robv.android.xposed.XposedBridge")) {
@Deprecated
public static boolean checkRomSpaceEnough(long limitSize) {
long availableSize = 0;
File data = Environment.getDataDirectory();
StatFs sf = new StatFs(data.getPath());
availableSize = (long) sf.getAvailableBlocks() * (long) sf.getBlockSize();
allSize = (long) sf.getBlockCount() * (long) sf.getBlockSize();
} catch (Exception e) {
allSize = 0;
if (allSize != 0 && availableSize & limitSize) {
public static String getExceptionCauseString(final Throwable ex) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(bos);
// print directly
Throwable t =
while (t.getCause() != null) {
t = t.getCause();
t.printStackTrace(ps);
return toVisualString(bos.toString());
} finally {
bos.close();
} catch (IOException e) {
e.printStackTrace();
private static String toVisualString(String src) {
boolean cutFlg =
if (null == src) {
char[] chr = src.toCharArray();
if (null == chr) {
int i = 0;
for (; i & chr. i++) {
if (chr[i] & 127) {
chr[i] = 0;
if (cutFlg) {
return new String(chr, 0, i);
到这里就已经集成完毕,下面来说下使用的方法
这是有bug的版本,我们测试就使用assembleDebug来测试 ,注意没点击assembleDebug之前,build文件夹里面是没有bakApk文件夹的
2.点击assembleDebug之后会出现bakApk这个文件夹,里面就有apk文件,如果失败,记得clean一下,然后build一下
3.接下来在build文件夹里面,更改ext中的属性,将bakApk中生成的apk文件和R文件复制到ext这里,如果你打的release包有mapping的话同样复制到这里,我们这里是debug测试,所以没有mapping文件
4.下面就修改我们需要更新,或者更改的bug,我这里是添加一张图片,并且更改标题显示
这是有bug的版本,我还没添加图片,更改标题
这里我添加了一张aa的图片,并且更改了标题
5.接下来我们运行tinker下面的tinkerPatchDebug,来生成补丁包,这个补丁包在outputs下面
点击完成后,就会生成tinkerPatch文件夹
将tinkerPatch文件夹下面的patch_signed_7zip.apk文件,粘贴出来,改成你的MainActivity中加载的文件名字,我这里叫patch,然后点击加载没加载之前
加载之后,锁频,解锁 ,补丁已经加载出来了,并且文件夹中的补丁已经不在了,因为它和老apk合并了
签名文件的话 在build的signingConfigs中设置,以及左侧的kestore文件夹中设置 ,如下图
项目github地址:
Tinker原项目地址:
Tinker使用指南:
Tinker一键集成(这个简单,但是不能从自己服务器上下载补丁,不需配置Tinker自己的后台,有部分局限性,自行选择):
Tinker一键集成后台:
更多精彩内容请点击《》,《》欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 mta sdk 1.6.2.jar 的文章

 

随机推荐