Anroid_微信热修复Tinker

Tinker简单集成

一:导入依赖

 //可选,用于生成application类
    provided('com.tencent.tinker:tinker-android-anno:1.9.2')
    //tinker的核心库
    compile('com.tencent.tinker:tinker-android-lib:1.9.2')
    //分包
    compile 'com.android.support:multidex:1.0.1'
二:在AndroidManifast中配置:

 <application>
    	<meta-data android:name="TINKER_ID" android:value="tinker_id_b168b32"/>
    </application>

三:创建类TinkerManager 

public class TinkerManager {

    //是否安装
    private static boolean isInstalled = false;
    private static ApplicationLike app;

    /**
     * 安装
     */
    public static void installTinbker(ApplicationLike applicationLike){
        app=applicationLike;
        //判断是否安装
        if(isInstalled){
            return;
        }
        TinkerInstaller.install(applicationLike);
        isInstalled=true;
    }

    /**
     * 添加补丁包
     * @param path
     */
    public static void addPatch(String path){
        if(isInstalled){
            TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path);
        }
    }

    /**
     * 从ApplicationLike中拿到上下文
     */
    public static Context getApplicationContext(){
        return app.getApplication().getApplicationContext();
    }

}
四:创建Application继承DefaultApplicationLike
public class CustomApplication extends DefaultApplicationLike{

    public CustomApplication(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.installTinbker(this);

    }
}
五:给CustomApplication 类添加注解(第四步的类上添加此注解)
@DefaultLifeCycle(
        application = ".MyTinkerApplication",             //application name to generate 应用程序名称生成
        flags = ShareConstants.TINKER_ENABLE_ALL)         //tinkerFlags above tinkerFlags上面
添加上之后编译一下,AndroidStudio3.0之后会报错
Error:Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now.  The following dependencies on the compile classpath are found to contain annotation processor.  Please add them to the annotationProcessor configuration.
    - tinker-android-anno-1.9.2.jar (com.tencent.tinker:tinker-android-anno:1.9.2)
  Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior.  Note that this option is deprecated and will be removed in the future.
  See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

解决方法  在app的build中  defaultConfig中   添加     
javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }

解决之后再次编译,会生成一个.MyTinkerApplication不用管在哪里,清单文件中注册一下就可以
六:主页面代码操作一波

  添加新功能或者修复bug主要是通过一个补丁包,在此点击事件添加一个补丁包,补丁包放在自定义文件夹下 

   在此自定义文件夹为( /storage/emulated/0/tpatch/)

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_tinker;
    private String path="";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取id
        btn_tinker = (Button)findViewById(R.id.btn_tinker);
        //监听
        btn_tinker.setOnClickListener(this);
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            //File.separator 代表一个 /
            path=Environment.getExternalStorageDirectory().getAbsolutePath().concat(File.separator).concat("tpatch/");
            File file = new File(path);
            if(!file.exists()){
                file.mkdir();
            }
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            //点击添加新功能  或者修复bug
            case R.id.btn_tinker:
                TinkerManager.addPatch(path.concat("out.apk"));
                break;
        }
    }
}
上面完成之后,就差生成一个补丁包放入我们的手机或模拟器自定义的文件夹下了

开始生成补丁包使用gradle接入


一:Gradle配置

1:在Project下build.gradle中配置
dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.2')
 }

2:在model的build.gradle 添加 apply tinker插件
apply plugin: 'com.tencent.tinker.patch'


3:在model的build.gradle最下面配置

def bakPath = file("${buildDir}/bakApk/")

ext{
    tinkerOldApkPath = "${bakPath}/"
    tinkerEnabled = true;
    //不开启混淆
    //tinkerApplyMappingPath = "${bakPath}/"
    tinkerApplyResourcePath = "${bakPath}/"
    //多渠道打包
    //tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47"
}

def getOldApkPath() {
    return ext.tinkerOldApkPath
}
//是否使用Tinker
def buildWithTinker() {
    return ext.tinkerEnabled
}

def getApplyMappingPath() {
    return ext.tinkerApplyMappingPath
}

def getApplyResourceMappingPath() {
    return ext.tinkerApplyResourcePath
}

def getTinkerIdValue() {
    return "tinker_id_b168b32"
}
//多渠道打包
/*def getTinkerBuildFlavorDirectory() {
    return ext.tinkerBuildFlavorDirectory
}*/

tinkerPatch{
    tinkerEnable = buildWithTinker()
    oldApk = getOldApkPath()
    ignoreWarning = false
    useSign = true

    buildConfig{
        //不开启混淆不用他
        //applyMapping = getApplyMappingPath()
        applyResourceMapping = getApplyResourceMappingPath()
        tinkerId = getTinkerIdValue()
        keepDexApply = false                //分包 暂时不用 太小
        isProtectedApp = false              //加固  暂时不加
    }

    dex{
        dexMode = "jar"
        pattern = ["classes*.dex",
                "assets/secondary-dex-?.jar"]
        //全路径Application
        loader = ["com.geekghost.gp.tinker.MyTinkerApplication"]
    }

    lib{
        pattern = ["lib/*/*.so"]
    }

    res{
        pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
        ignoreChange = ["assets/sample_meta.txt"]
        largeModSize = 100
    }

    packageConfig{
        configField ("version_name","1")
        configField ("change_log","添加了一些新功能")
    }

}

4:此脚本在最下面复制 比较固定 用于生产老的apk文件

List<String> 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配置完成之后 

签名生成一个apk包  把apk包安装,现在安装的是没有修复bug的或者是没有新功能的apk包

三:安装完成后 

 找到app下 build文件夹下面的 bakApk文件夹  这个文件夹里如果有东西先删除一下,要不然太乱了   
    如果没有此文件夹就忽略删除这一步

  1 首先打开右侧的Project下的Gradle,找到Tasks\build\assembleRelease
   双击assembleRelease就会编译一个apk包与r.txt文档  
   生成在app build bakApk下面


  2 或者在项目的outputs\apk下也可以在Terminal(命令行)输入 gradle assembleRelease    代替双击操作


   选一即可  现在app build bakApk下面有两个文件  一个apk r.txt


  把bakApk的老的apk的名字copy下来把   tinkerOldApkPath = "${bakPath}/" 填好
  把bakApk的老的R文件的名字copy下来把tinkerApplyResourcePath = "${bakPath}/" 填好

  如下:

  ext{
     tinkerOldApkPath = "${bakPath}/tinker-release-0118-11-10-48.apk"
    tinkerApplyResourcePath = "${bakPath}/tinker-release-0118-11-10-48-R.txt" 
  }

四:现在就可以写一些新功能或者修复bug的代码了


添加了一些新功能或者修复完bug之后需要 配置一个正式的签名文件 (可以快捷生成)

  1:自己手写
  android {
     signingConfigs {
        release {
            keyAlias 'key0'
            keyPassword '123456'
            storeFile file('C:/Users/ZangH/Desktop/Tinker/tk.jks')
            storePassword '123456'
        }
    }
  }

  2:快捷键生成
  右键项目选择 open module settings   ;  快捷键是 ctrl+shift+alt+s
  选择此app 里的signing 点击+号  信息填上
  name  =  随便
  key Alias = 你的Alias  Alias一般默认为key0
  key Password  = 123456  or  你的密码
  Store File = 签名.jks文件
  Store Password = 123456  or 你的密码

  信息填完再选择  Build Types
  debug  release选择release
  signing config 选择默认 
  一波操作就完成了,点击ok


  随便选一种方式即可

五:生成有新功能的apk包与补丁文件

 点击打开右侧的Project下的Gradle,找到Tasks\tinker\tinkerPatchRelease
  双击tinkerPatchRelease就会编译一个新的apk包与r.txt文档   
  在app build bakApk下面
  
  
  现在app build bakApk下面有4个文件  2个旧的2个新的
  

  到了现在就可以结尾了,只需要把补丁文件放到手机或模拟器中就行了,那么补丁文件在哪里


  在app\build\outputs\apk\tinkerPatch\release里   
  (patch_signed.apk)就是我们的补丁文件
  接下来只需把补丁包放入我们定义的修改路径就好了

  放入后,运行程序,点击按钮添加补丁文件,程序立马闪退你就成功了,再次运行就行了

  
  那么补丁文件是什么时候生成的?   双击tinkerPatchRelease编译时生成的

六:如果再需要更新呢?  就不用那么麻烦了  因为只需要配置一次就可以了

  以后每次更新只需要把下面的两个路径改成上一次最新的路径就行了     路径app build bakApk下面找
  ext{
     tinkerOldApkPath = "${bakPath}/tinker-release-0118-11-10-48.apk"
    tinkerApplyResourcePath = "${bakPath}/tinker-release-0118-11-10-48-R.txt" 
  }

  新代码写完之后,再次操作一下第五步就行了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值