Tinker的使用

Tinker的继承和使用

Tinker-API概览:https://github.com/Tencent/tinker/wiki/Tinker-API概览
Tinker-自定义扩展:https://github.com/Tencent/tinker/wiki/Tinker-自定义扩展
Tinker案例:
https://github.com/Tencent/tinker/blob/master/tinker-sample-android/app/src/main/java/tinker/sample

添加依赖

 //可选,用于生成application类 provided不参与打包
    provided('com.tencent.tinker:tinker-android-anno:1.9.1')
    //tinker的核心库
    compile('com.tencent.tinker:tinker-android-lib:1.9.1')
     //支持多分包
    compile "com.android.support:multidex:1.0.1"

TinkerManager

public class TinkerManager {
    private static boolean isInstall = false;
    private static ApplicationLike mAppLike;

    /**
     * 完成Tinker的初始化
     */
    public static void installTinker(ApplicationLike applicationLike) {
        mAppLike = applicationLike;
        if (isInstall) {
            return;
        }
        TinkerInstaller.install(applicationLike);//完成tinker的初始化
        isInstall = true;
    }

    /**
     * 发起补丁修复请求
     */
    public static void loadPatch(String path) {
        if (Tinker.isTinkerInstalled()) {
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), path);
        }
    }

    //获取上下文
    private static Context getApplicationContext() {
        if (mAppLike != null) {
            return mAppLike.getApplication().getApplicationContext();
        }
        return null;
    }
}

CustomTinkerLike用于生成Application

@DefaultLifeCycle(application = ".MyTinkerApplication",
        flags = ShareConstants.TINKER_ENABLE_ALL,
        loadVerifyFlag = false)
public class CustomTinkerLike extends ApplicationLike {
    public CustomTinkerLike(Application application
            , int tinkerFlags
            , boolean tinkerLoadVerifyFlag
            , long applicationStartElapsedTime
            , long applicationStartMillisTime
            , Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag
                , applicationStartElapsedTime, applicationStartMillisTime
                , tinkerResultIntent);
    }

    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        //支持多分包
        MultiDex.install(base);
        TinkerManager.installTinker(this);
    }
}

grade参数配置

整个项目中添加依赖:

       //Tinker
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')

参数配置:官网接入指南:
https://github.com/Tencent/tinker/wiki/Tinker-接入指南
有相关说明,可以直接拷贝官网提供的指南https://github.com/Tencent/tinker/blob/master/tinker-sample-android/app/build.gradle

apply plugin: 'com.android.application'
def javaVersion = JavaVersion.VERSION_1_7
def bakPath = file("${buildDir}/bakApk/")
android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"

    defaultConfig {
        applicationId "com.peakmain.tinker"
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    compileOptions {
        sourceCompatibility javaVersion
        targetCompatibility javaVersion
    }
    signingConfigs {
        signingConfigs {
            try {
                keyAlias 'Tinker'
                keyPassword '123456'
                storeFile file('E:/Android/FestEc/tinker/src/keystore/release.jks')
                storePassword '123456'
            } catch (ex) {
                throw new InvalidUserDataException(ex.toString())
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            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.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    //可选,用于生成application类 provided不参与打包
    provided("com.tencent.tinker:tinker-android-anno:${TINKER_VERSION}"){changing=true}
    //tinker的核心库
    compile("com.tencent.tinker:tinker-android-lib:${TINKER_VERSION}"){changing=true}
    //支持多分包
    compile "com.android.support:multidex:1.0.1"
}

ext {
    tinkerEnabled = true
    tinkerOldApkPath = "${bakPath}/"
    tinkerID = "1.0"
    tinkerApplyMappingPath = "${bakPath}/"
    tinkerApplyResourcePath = "${bakPath}/"
}

def buildWithTinker() {
    return ext.tinkerEnabled;
}

def getOldApkPath() {
    return ext.tinkerOldApkPath
}

def getApplyMappingPath() {
    return ext.tinkerApplyMappingPath
}

def getApplyResourceMappingPath() {
    return ext.tinkerApplyResourcePath
}

def getTinkerIdValue() {
    return ext.tinkerID
}

if (buildWithTinker()) {
    //启用tinker
    apply plugin: 'com.tencent.tinker.patch'

    tinkerPatch {
        oldApk = getOldApkPath()//指定old  apk的路径
        ignoreWarning = false//是否忽略警告,false表示不忽略tinker的警告,有警告则中止文件的生成
        useSign = true//强制使用签名
        tinkerEnable = buildWithTinker()//指定是否启用tinker
        buildConfig {
            applyMapping = getApplyMappingPath()//指定old apk打包时所使用的混淆文件
            applyResourceMapping = getApplyResourceMappingPath()//指定old apk的资源文件
            tinkerId = getTinkerIdValue()//指定Tinker的id
            keepDexApply = false
        }
        dex {
            dexMode = "jar"
            //指定dex文件目录
            pattern = ["classes*.dex",
                       "assets/secondary-dex-?.jar"]
            loader = [
                    "com.peakmain.tinker.MyTinkerApplication"//指定加载patch文件时用到的类
            ]
        }
        lib {
            pattern = ["lib/*/*.so"]
        }
        res {
            pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
//指定tinker可以修改的资源路径
            ignoreChange = ["assets/sample_meta.txt"]//指定不受影响的资源路径
            largeModSize = 100//资源修改的默认大小
        }
        packageConfig {
            configField("patchMessage", "tinker is sample to use")
            configField("platform", "all")//平台
            configField("patchVersion", "1.0")//版本号
        }
    }
    List flavors = new ArrayList<>();
    project.android.productFlavors.each { flavor ->
        flavors.add(flavor.name)
    }
    boolean hasFlavors = flavors.size() > 0
    def date = new Date().format("MMdd-HH-mm-ss")

    /**
     * bak apk and mapping
     */
    android.applicationVariants.all { variant ->
        /**
         * task type, you want to bak
         */
        def taskName = variant.name

        tasks.all {
            if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {

                it.doLast {
                    copy {
                        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.first().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")
                        }
                    }
                }
            }
        }
    }
}

gradle.properties添加

TINKER_VERSION=1.9.1

修改整个项目的build

        //Tinker
        classpath ("com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}"){changing=true}

生成签名apk之后修改builder中ext


image.png

build之后选择tinkerPatchRelease


image.png

此时会生成tinkerPatch


image.png

有时候会报错:使用Tinker can't the get signConfig for this build,这个代表你没有添加签名配置,可是代码明明添加了,还是报错,解决办法

 buildTypes {
        release {
            minifyEnabled true
          //添加这一行
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

此时就已经完成生成patch文件

TinkerService进行后台下载

public class TinkerService extends Service {
    private static final String FILE_END = ".apk";//文件后缀名
    private static final int DOWNLOAD_PATCH = 0x01;
    private static final int UPDATE_PATCH = 0x02;

    private String mPatchFileDir;//patch要保存的文件夹
    private String mFilePatch;//patch文件保存的路径
    private BasePatch mBasePatchInfo;//服务器patch信息

    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_PATCH:
                    checkPatchInfo();
                    break;
                case DOWNLOAD_PATCH:
                    downloadPatch();
                    break;
            }
        }
    };

    private void downloadPatch() {
        mFilePatch=mPatchFileDir.concat(String.valueOf(System.currentTimeMillis()))
                .concat(FILE_END);
        RequestCenter.downloadFile(mBasePatchInfo.data.downloadUrl, mFilePatch, new DisposeDownloadListener() {
            @Override
            public void onProgress(int progrss) {

            }

            @Override
            public void onSuccess(Object responseObj) {
                TinkerManager.loadPatch(mFilePatch);
            }

            @Override
            public void onFailure(Object reasonObj) {
             stopSelf();
            }
        });
    }

    private void checkPatchInfo() {
        RequestCenter.requestPatchUpdateInfo(new DisposeDataListener() {
            @Override
            public void onSuccess(Object responseObj) {
                mBasePatchInfo = (BasePatch) responseObj;
                mHandler.sendEmptyMessage(DOWNLOAD_PATCH);
            }

            @Override
            public void onFailure(Object reasonObj) {
                stopSelf();
            }
        });

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //检查是否有patch更新
        mHandler.sendEmptyMessage(UPDATE_PATCH);
        return START_NOT_STICKY;//被系统回收将不再重启
    }

    private void init() {
        mPatchFileDir = getExternalCacheDir().getAbsolutePath() + "/tpatch";
        File patchFileDir = new File(mPatchFileDir);
        try {
            if (patchFileDir == null || !patchFileDir.exists()) {
                patchFileDir.mkdir();
            }
        } catch (Exception e) {
            e.printStackTrace();
            //无法正常创建,停止服务
            stopSelf();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

你可能感兴趣的:(Tinker的使用)