注:当然一开始要参考Tinker的详细说明,链接如下:
https://github.com/Tencent/tinker/wiki
下面就是我自己一步一步操作,并完成接入Tinker,而且入坑并出坑的过程。
一:android studio自己创建个工程
二:工程的build.gradle中添加以下代码:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
//tinker依赖
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.11')
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
三:在app/build.gradle中添加如下:(整个文件代码如下:根据自己工程情况适当修改名称)
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.oneandroid.activity"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
signingConfigs {
release {
keyAlias 'oneAndroid'
keyPassword '123456'
storeFile file('jks/sign.jks')
storePassword '123456'
}
}
buildTypes {
debug {
signingConfig signingConfigs.release
}
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
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:25.3.0'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
compile 'com.android.support:design:25.3.0'
testCompile 'junit:junit:4.12'
//可选,用于生成application类
provided('com.tencent.tinker:tinker-android-anno:1.7.11')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.7.11')
compile "com.android.support:multidex:1.0.1"
}
apply plugin: 'com.tencent.tinker.patch'
tinkerPatch {
//有问题的apk的地址
oldApk = "/Users/zhaoguang/Documents/kanzhun/as_workspace/oldApk/app-debug.apk"
ignoreWarning = false
useSign = true
buildConfig{
tinkerId = "1.0"
}
packageConfig{
//写这个为了修复一个bug,详见github issue #22
configField("TINKER_ID", "tinker_id_1.0")
}
dex{
dexMode = "jar"
pattern = ["classes*.dex", "assets/secondary-dex-?.jar"]
loader = ["com.tencent.tinker.loader.*", "com.oneandroid.activity.Application"]
}
lib{
pattern = ["lib/armeabi/*.so","lib/arm64-v8a/*.so","lib/armeabi-v7a/*.so","lib/mips/*.so","lib/mips64/*.so","lib/x86/*.so","lib/x86_64/*.so"]
}
res{
pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
largeModSize = 100
}
sevenZip{
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
}
}
说明:关于上面app/build.gradle:
1)首先创建sign.jks(不懂如何创建,参看:http://blog.csdn.net/yy1300326388/article/details/48344411)
2)在1)基础上,在app/build.gradle中增加如下代码:(代码中的别名,密码,存储位置必须与创建sign.jks时所填写保持一致)
signingConfigs {
release {
keyAlias 'oneAndroid'
keyPassword '123456'
storeFile file('jks/sign.jks')
storePassword '123456'
}
}
buildTypes {
debug {
signingConfig signingConfigs.release
}
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
4)在app/build.gradle中,添加Tinker依赖和多Dex方式,如下:
//可选,用于生成application类
provided('com.tencent.tinker:tinker-android-anno:1.7.11')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.7.11')
compile "com.android.support:multidex:1.0.1"
5)在app/build.gradle中,增加tinkerPatch 任务代码,并且增加引用该插件:代码如下:
apply plugin: 'com.tencent.tinker.patch'
tinkerPatch {
//有问题的apk的地址
oldApk = "/Users/zhaoguang/Documents/kanzhun/as_workspace/oldApk/app-debug.apk"
ignoreWarning = false
useSign = true
buildConfig{
tinkerId = "1.0"
}
packageConfig{
//写这个为了修复一个bug,详见github issue #22
configField("TINKER_ID", "tinker_id_1.0")
}
dex{
dexMode = "jar"
pattern = ["classes*.dex", "assets/secondary-dex-?.jar"]
loader = ["com.tencent.tinker.loader.*", "com.oneandroid.activity.Application"]
}
lib{
pattern = ["lib/armeabi/*.so","lib/arm64-v8a/*.so","lib/armeabi-v7a/*.so","lib/mips/*.so","lib/mips64/*.so","lib/x86/*.so","lib/x86_64/*.so"]
}
res{
pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
largeModSize = 100
}
sevenZip{
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
}
}
其中:
5.1) oldApk为你电脑存放有问题的apk路径。
注意开始调试接入Tinker时,最好打debug包,这样Tinker有问题会有日志输出:在LogCat窗口该日志的Tag就是你的"包名:patch"
5.2) 很多网上的帖子都写成:
configField("TINKER_ID", "1.0")
而我按此测试发现Logcat中Tinker报错:说patch的tinkerId与oldApk包中
tinkerId不一致,所以我改成一致的才通过测试如下代码中的:
//写这个为了修复一个bug,详见github issue #22
configField("TINKER_ID", "tinker_id_1.0")
5.3)注意下面代码中下面这行:要改为你自己的包名
loader = ["com.tencent.tinker.loader.*", "com.oneandroid.activity.Application"]
四:编写MyApplication,代码如下:
package com.oneandroid.activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import com.tencent.tinker.anno.DefaultLifeCycle;
import com.tencent.tinker.lib.tinker.TinkerInstaller;
import com.tencent.tinker.loader.app.DefaultApplicationLike;
import com.tencent.tinker.loader.shareutil.ShareConstants;
/**
* Created by zhaoguang on 17/6/5.
*/
@DefaultLifeCycle(
application = "com.oneandroid.activity.Application",
flags = ShareConstants.TINKER_ENABLE_ALL
)
public class MyApplication extends DefaultApplicationLike {
public MyApplication(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
TinkerInstaller.install(this);
}
}
并且注意要在AndroidManifest.xml中配置如下:注意application标签的android:name="com.oneandroid.activity.Application",而不是MyApplication,这是与DefaultLifeCycle中设置的application值相同,另外在AndroidManifest.xml中要至少增加读写SD卡的权限
五:编写有问题的MainActivity.java,具体如下:
package com.oneandroid.activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.tencent.tinker.lib.tinker.TinkerInstaller;
public class MainActivity extends AppCompatActivity {
private TextView mText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText=(TextView)findViewById(R.id.txt_tip);
//mText.setText("这是没有bug版本");
/* 补丁的路径,从服务器下载到手机 */
String patchPath = Environment.getExternalStorageDirectory().getAbsolutePath()+ "/666/patch_signed_7zip.apk";
TinkerInstaller.onReceiveUpgradePatch(this.getApplication(), patchPath);
Log.d("FFFFFF","====patchPath="+patchPath);
}
}
其中注释掉那行代码时,为错误代码,打开注释后为正确代码(通过这种方式模拟你的代码错误和正确的两种情况)
变量:patchPath的值为从你公司服务器下载到Android手机存放补丁的路径,其中patch_signed_7zip.apk为TInker生产的补丁的默认名称,这里我存放补丁在我Android手机内部存储目录下的666文件内
TinkerInstaller.onReceiveUpgradePatch(this.getApplication(), patchPath);
这行就是Tinker安装Android设置的patchPath目录中的补丁的代码。
自此以上接入Tinker结束,下面是测试热修复。
六:MainActivity.java保持那一行代码注释掉,然后点击运行Android studio中Gradle中的assembleDebug,如下图:
在app/build/outputs/apk/目录中生产app-debug.apk(有问题的apk),把它放置到上文5.1)中设置的你的电脑路径下,并且通过adb install -r安装到你的Android手机内,并运行,这时为错误的程序
七:将MainActivity.java中那行注释打开(模拟修复后的代码),打开终端:设置好gradle的环境变量(不会请自行百度),运行:gradle tinkerPatchDebug , 看到Build Success之后,会在你工程中app/build/outputs/tinkerPatch目录下看到生产的补丁文件:patch_signed_7zip.apk,如下图:然后把atch_signed_7zip.apk放置到你在MainActivity.java中设置的变量patchPath对应的目录下,本文为Android手机内置存储目录下新建的666文件内,kill 掉刚才错误的apk进程,重新打开该apk。会发现注释那行代码打开生效了,自此接入Tinker成功!!!