Tinker热修复接入详解(入坑并出坑篇)

注:当然一开始要参考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'
        }
    }

3)在 app/build.gradle中增加如下代码:(这样设置保证打debug和release包都是使用同一个签名)

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);
    }
}

注意:MyApplication继承自DefaultApplicationLike,而不是Application,还要在MyApplication开始处写注解:@DefaultLifeCycle

并且注意要在AndroidManifest.xml中配置如下:注意application标签的android:name="com.oneandroid.activity.Application",而不是MyApplication,这是与DefaultLifeCycle中设置的application值相同,另外在AndroidManifest.xml中要至少增加读写SD卡的权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.oneandroid.activity" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:name="com.oneandroid.activity.Application"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.oneandroid.activity.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


五:编写有问题的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成功!!!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值