一、将Tinke集成到自己的项目

来源:互联网 发布:阿里云域名ssl证书 编辑:程序博客网 时间:2024/05/20 10:13

本片文章的目的是用简单的方式集成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集成到自己的项目中,其中遇到的问题该如何解决,现在就开始吧。

一、新建工程,然后在工程根目录的build.gradle中添加
buildscript {    dependencies {        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.6.2')    }}
二、在app/build.gradle中的dependencies节点添加如下依赖
//可选,用于生成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')
三、在manifest.xml中添加对于sd卡的读写权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
四、复制官方sample工程app/build.gradle中的其他相关配置到自己的app/build.gradle中
五、使用Tinker的要求自定义Application类,这一块需要特殊说明一下,tinker为了达到修改应用自己的Application的目的,使用代码框架封装继承DefaultApplicationLike的方式来实现对Application的修改,主要为了减少反射的使用和提高兼容性,具体说明参考 Tinker Wiki。

怎样实现自己的Application类呢,主要还是参考Tinker推荐的方式,通过注解生成Application类。

5.1 写一个继承自DefaultApplicationLike 的子类,例如SampleApplicationLike。并实现默认构造方法。
5.2 在SampleApplicationLike中添加如下注解:
@DefaultLifeCycle(application = "com.github.tinkersample.SampleApplication",             //这里将com.github.tinkersample.SampleApplicationLike更改为你自己的包名即可flags = ShareConstants.TINKER_ENABLE_ALL)                                //tinkerFlags abovepublic class SampleApplicationLike extends DefaultApplicationLike 
5.3 在SampleApplicationLike中添加如下方法:
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)    public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {        getApplication().registerActivityLifecycleCallbacks(callback);    }
5.4 在SampleApplicationLike中重载onBaseContextAttached方法,并在该方法中增加以下代码调用初始化tinker
MultiDex.install(context);TinkerInstaller.install(this);

至此,自定义Application,也就是将Application中的实现移动到SampleApplicationLike中已经完成。

六、在自己的工程中增加两个按钮和一个EditText,其中一个按钮用来显示EditText中的内容,另一个按钮用来加载补丁,在加载补丁按钮点击事件中执行加载patch的操作,为后期修复代码bug做准备,代码为:
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/build/bakApk目录下会有生成好的apk文件一份以及对应的资源文件txt文件一份比如app-debug-1004-18-51-17.apk和app-debug-1004-18-51-17.apk-R.txt,此时app应该已经部署到手机或者模拟器上。

此时运行app,并点击显示名字按钮会crash,我们一会就通过Tinker去修复它。

八、然后将app-debug-1004-18-51-17.apk文件复制到下图对应的红色区域,app-debug-1004-18-51-17.apk-R.txt复制到下图对应的蓝色区域

这里写图片描述

九、修改代码,将刚才注释的两行代码输出打开,然后执行 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=23buildToolsVersion "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出现如下提示,请无视之。
这里写图片描述

十、此时点击我们刚才设置了点击事件加载补丁的按钮,此时如果加载补丁成功,应用会闪退,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

3 0
原创粉丝点击