本片文章的目的是用简单的方式集成tinker到自己的项目中,完成tinker的核心功能,即更新补丁,修复bug。
微信的Tinker之前了解的同学可能已经有所耳闻,微信官方的热补丁修复框架,极大的方便了开发者热修复自己线上App的出现的bug和漏洞。听着都这么令人激动!在之前,如果想在自己的项目中热修复自己App,困难程度是不小的,还是有不少的技术门槛。
Tinker GitHub: https://github.com/Tencent/tinker
幸运的是微信的Tinker终于开源了,几天功夫star数就超过3000,可见在开发者中的影响力有多大,也说明这是一个刚需。
但是Tinker开源后有不少同学反映不知道该怎么使用,即便是官方已经给出了中文wiki以及集成步骤和方案,但是仍有不少同学无法集成到自己的项目中甚至官方sample都无法运行。
我自己也试了一下,发现在讲Tinker集成到自己项目的过程中,确实还是有不少坑需要注意的,不小心就会出现错误。
很多人遇到的第一个错误就是提示 tinkerId is not set
,这个是由于要获取git的提交版本号,设置到Tinker,如果不是通过git clone方式下载的就可能出现这个错误,其实可以简单粗暴的方式解决,那就是在app/build.gradle中更改以下代码:
tinkerId = getTinkerIdValue()
更改为
tinkerId = "TinkerSample"//或者其他你想要的id
下面介绍一下如何一步步的把Tinker集成到自己的项目中,其中遇到的问题该如何解决,现在就开始吧。
buildscript {
dependencies {
classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.6.2')
}
}
//可选,用于生成application类
compile('com.tencent.tinker:tinker-android-anno:1.6.2')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.6.2')
compile('com.android.support:multidex:1.0.1')
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
怎样实现自己的Application类呢,主要还是参考Tinker推荐的方式,通过注解生成Application类。
@DefaultLifeCycle(
application = "com.github.tinkersample.SampleApplication", //这里将com.github.tinkersample.SampleApplicationLike更改为你自己的包名即可
flags = ShareConstants.TINKER_ENABLE_ALL) //tinkerFlags above
public class SampleApplicationLike extends DefaultApplicationLike
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
getApplication().registerActivityLifecycleCallbacks(callback);
}
MultiDex.install(context);
TinkerInstaller.install(this);
至此,自定义Application,也就是将Application中的实现移动到SampleApplicationLike中已经完成。
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private EditText etUserName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(TAG,"onCreate");
// Log.e(TAG,"i am on patch log");
// etUserName = (EditText) findViewById(R.id.et_username);
findViewById(R.id.btn_show_name).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = etUserName.getText().toString();
Toast.makeText(getApplicationContext(),"输入的名字为:" + name,Toast.LENGTH_SHORT).show();
}
});
findViewById(R.id.btn_load_patch).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String patchPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tinkersample/patch_signed_7zip.apk";
File file = new File(patchPath);
if (file.exists()) {
Log.v(TAG,"补丁文件存在");
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), patchPath);
} else {
Log.v(TAG,"补丁文件不存在");
}
}
});
}
}
可以看出来,由于并没有在onCreate中对EditText进行初始化复制,所以在点击显示名字的按钮的时候,必然会触发 NullPointException
,而且日志 //Log.e(TAG,"i am on patch log");
还是处于注释状态,并不会打印。
整体UI如下:
此时运行app,并点击显示名字按钮会crash,我们一会就通过Tinker去修复它。
tinkerPatchDebug
命令,成功后即可在app/build/outputs/tinkerPatch/debug/中找到生成好的补丁文件“patch_signed_7zip.apk”,将该文件复制到sdk,并记住在sd卡中路径。此时有一些同学在这个地方会遇到问题,不知道该怎么调用tinkerPatchDebug
,其实就是在Android Studio中的Teriminnal中执行,需要注意的是调用该命令前需要加上 ./gradlew
前缀,完整的命令是:
./gradlew tinkerPatchDebug
执行该命令后你可能会遇到错误:
A problem occurred evaluating project ':app'.
> java.lang.UnsupportedClassVersionError: com/android/build/gradle/AppPlugin : Unsupported major.minor version 52.0
解决办法是你需要将工程根目录build.gradle中的
classpath 'com.android.tools.build:gradle:2.2.0'
更改成
classpath 'com.android.tools.build:gradle:2.1.0'
然后如果此时你使用compileSdkVersion=24的话,有可能还会遇到这个错误:
* What went wrong:
Execution failed for task ':app:compileDebugJavaWithJavac'.
> compileSdkVersion 'android-24' requires JDK 1.8 or later to compile.
解决办法是在app\build.gradle中将
compileSdkVersion=24
更改为
compileSdkVersion=23
buildToolsVersion "23.0.3"//buildToolsVersion更改为23.0.3
同时在dependencies中将:
compile 'com.android.support:appcompat-v7:24.2.1'
更改为
compile 'com.android.support:appcompat-v7:23.4.1'
//对照自己的版本,总之就是改为sdk 23版本的
如果Android Studio出现如下提示,请无视之。
说明:我在之前测试的时候发现如果不在mainfest.xml中设置
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14"/>
的话,在点击加载补丁,执行操作的时候控制台日志会提示“Permission denied”或者控制台输出的 isSuccess=false 的错误,即便你已经在app\builde.gradle中设置过minSdkVersion和targetSdkVersion,依然会发生,不过今天确没有发现这个问题。如果有发生,请将这行配置添加上即可。
再次运行app,可以发现之前打开的注释代码已经被差异化修复到app中,并且打开的日志已经输出到控制台,EditText也已经初始化了,点击显示名字的按钮也不会crash了,因为已经被修复了。
ok,到这里,简单的将Tinker集成到自己的项目中已经完成,不过这只是简单原始粗暴的集成,很多回调监听并没有处理,应用并不知道加载是成功还是失败等等,下次再说这些监听的问题。这一块其实官方Sample中已经有介绍,可以参考官方Sample。
代码地址: TinkerSample