集成tinker热更新

前段时间尝试了一下增量更新,以及hotfix,今天写了一个demo集成腾讯bugly的tinker热更新https://bugly.qq.com/v2/index
step1、添加依赖:
1. 工程中的dependencies依赖:

// tinker gradle插件
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.7.5')
// tinkersupport插件
        classpath "com.tencent.bugly:tinker-support:latest.release"
  1. app中的dependencies依赖:
// 多dex配置
        compile "com.android.support:multidex:1.0.1"
        //其中latest.release指代最新版本号,也可以指定明确的版本
        compile 'com.tencent.bugly:crashreport_upgrade:latest.release'

step2、gradle脚本编辑:

apply plugin: 'com.tencent.bugly.tinker-support'
def bakPath = file("${buildDir}/bakApk/")

ext {
    // for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
    tinkerEnabled = true

    // for normal build
    // old apk file to build patch apk
    tinkerOldApkPath = "${bakPath}/app-release.apk"
    // proguard mapping file to build patch apk
    tinkerApplyMappingPath = "${bakPath}/mapping.txt"
    // resource R.txt to build patch apk, must input if there is resource changed
    tinkerApplyResourcePath = "${bakPath}/R.txt"
    // only use for build all flavor, if not, just ignore this field
    tinkerBuildFlavorDirectory = "${bakPath}/app-1124-23-03-52"
}

def getOldApkPath() {
    return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath
}

def getApplyMappingPath() {
    return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath
}

def getApplyResourceMappingPath() {
    return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath
}

def getTinkerIdValue() {
    return hasProperty("TINKER_ID") ? TINKER_ID : gitSha()
}

def buildWithTinker() {
    return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled
}

def getTinkerBuildFlavorDirectory() {
    return ext.tinkerBuildFlavorDirectory
}

// 注意:必须要配置tinker-support
tinkerSupport {
    enable = true
}

// 全局信息相关配置项
tinkerPatch {
    oldApk = getOldApkPath()  //打补丁包时必选, 基准包路径

    ignoreWarning = false // 可选,默认false
    useSign = true // 可选,默认true, 验证基准apk和patch签名是否一致

    // 编译相关配置项
    buildConfig {
        applyMapping = getApplyMappingPath() //  可选,设置mapping文件,建议保持旧apk的proguard混淆方式
        applyResourceMapping = getApplyResourceMappingPath()      // 可选,设置R.txt文件,通过旧apk文件保持ResId的分配
        tinkerId = "1.0"  // 必选,当前版本的唯一标识,可以是git版本号、versionName
    }

    // dex相关配置项
    dex {
        dexMode = "jar" // 可选,默认为jar
        usePreGeneratedPatchDex = false // 可选,默认为false
        pattern = ["classes*.dex",
                   "assets/secondary-dex-?.jar"]
        loader = ["com.tencent.tinker.loader.*",  // 必选
                  "com.lin.tinkerdemo.SampleApplication",
        ]
    }

    // lib相关的配置项
    lib {
        pattern = ["lib/armeabi/*.so"]
    }

    // res相关的配置项
    res {
        pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
        ignoreChange = ["assets/sample_meta.txt"]
        largeModSize = 100
    }

    // 用于生成补丁包中的'package_meta.txt'文件
    packageConfig {
        configField("patchMessage", "tinker is sample to use")
        configField("platform", "all")
        configField("patchVersion", "1.0")
    }

    // 7zip路径配置项,执行前提是useSign为true
    sevenZip {
        zipArtifact = "com.tencent.mm:SevenZip:1.1.10" // optional
    }
}

step3、签名与混淆

  1. 签名
 signingConfigs {
        debug {}

        release {
            storeFile file("lin.jks")
            storePassword "123456"
            keyAlias "lin"
            keyPassword "123456"
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//指定签名
            signingConfig signingConfigs.release
        }
    }
  1. 混淆
#---------------------------------基本指令区----------------------------------
  -optimizationpasses 5
  -dontskipnonpubliclibraryclassmembers
  -printmapping proguardMapping.txt
  -optimizations !code/simplification/cast,!field/*,!class/merging/*
  -keepattributes *Annotation*,InnerClasses
  -keepattributes Signature
  -keepattributes SourceFile,LineNumberTable
  #----------------------------------------------------------------------------

  #---------------------------------默认保留区---------------------------------
  #继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
  -keep public class * extends android.app.Activity
  -keep public class * extends android.app.Application
  -keep public class * extends android.support.multidex.MultiDexApplication
  -keep public class * extends android.app.Service
  -keep public class * extends android.content.BroadcastReceiver
  -keep public class * extends android.content.ContentProvider
  -keep public class * extends android.app.backup.BackupAgentHelper
  -keep public class * extends android.preference.Preference
  -keep public class * extends android.view.View
  -keep public class com.android.vending.licensing.ILicensingService
  -keep class android.support.** {*;}

  -keep public class * extends android.view.View{
      *** get*();
      void set*(***);
      public <init>(android.content.Context);
      public <init>(android.content.Context, android.util.AttributeSet);
      public <init>(android.content.Context, android.util.AttributeSet, int);
  }
  -keepclasseswithmembers class * {
      public <init>(android.content.Context, android.util.AttributeSet);
      public <init>(android.content.Context, android.util.AttributeSet, int);
  }
  #这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆
  -keepclassmembers class * extends android.app.Activity {
     public void *(android.view.View);
  }

  -keepclassmembers class * implements java.io.Serializable {
      static final long serialVersionUID;
      private static final java.io.ObjectStreamField[] serialPersistentFields;
      private void writeObject(java.io.ObjectOutputStream);
      private void readObject(java.io.ObjectInputStream);
      java.lang.Object writeReplace();
      java.lang.Object readResolve();
  }
  -keep class **.R$* {
   *;
  }

  -keepclassmembers class * {
      void *(*Event);
  }

  -keepclassmembers enum * {
      public static **[] values();
      public static ** valueOf(java.lang.String);
  }
  -keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
  }
  #// natvie 方法不混淆
  -keepclasseswithmembernames class * {
      native <methods>;
  }

  #保持 Parcelable 不被混淆
  -keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
  }

  #----------------------------------------------------------------------------
# support-v7
-dontwarn android.support.v7.**
-keep class android.support.v7.internal.** { *; }
-keep interface android.support.v7.internal.** { *; }
-keep class android.support.v7.** { *; }
#腾讯budly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}

step4、清单文件配置

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:name=".SampleApplication"
        android:icon="@mipmap/as"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!--如果你也想使用升级功能,你必须要进行2、3项的配置,-->
        <!--而如果你只想使用热更新能力,你只需要配置权限即可-->
        <activity
            android:name="com.tencent.bugly.beta.ui.BetaActivity"
            android:theme="@android:style/Theme.Translucent" />
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>

provider_paths文件:在res目录下新建一个xml文件夹,新建一个xml文件:
这里写图片描述

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
    <external-path name="beta_external_path" path="Download/"/>
    <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
    <external-path name="beta_external_files_path" path="Android/data/"/>
</paths>

step5、代码编辑
新建一个SampleApplication继承tinker的TinkerApplication

/**
 * 注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中
 * 参数解析
 * 参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKER_ENABLE_ALL
 * 参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike
 * 参数3:loaderClassName Tinker的加载器,使用默认即可
 * 参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false
 */

public class SampleApplication extends TinkerApplication {
    public SampleApplication() {
        super(ShareConstants.TINKER_ENABLE_ALL, "com.lin.tinkerdemo.SampleApplicationLike",
                "com.tencent.tinker.loader.TinkerLoader", false);
    }

新建一个SampleApplicationLike类继承tinker的DefaultApplicationLike:

package com.lin.tinkerdemo;

import android.annotation.TargetApi;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Build;
import android.support.multidex.MultiDex;

import com.tencent.bugly.Bugly;
import com.tencent.bugly.beta.Beta;
import com.tencent.tinker.loader.app.DefaultApplicationLike;

/**
 * Created by Administrator on 2016/12/11.
 */

public class SampleApplicationLike extends DefaultApplicationLike{
    public static final String TAG = "Tinker.SampleApplicationLike";

    public SampleApplicationLike(Application application, int tinkerFlags,
                                 boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,
                                 long applicationStartMillisTime, Intent tinkerResultIntent, Resources[] resources,
                                 ClassLoader[] classLoader, AssetManager[] assetManager) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime,
                applicationStartMillisTime, tinkerResultIntent, resources, classLoader,
                assetManager);
    }


    @Override
    public void onCreate() {
        super.onCreate();
        /**
         * 参数解析:

         参数1:上下文对象

         参数2:注册时申请的APPID

         参数3:是否开启debug模式,true表示打开debug模式,false表示关闭调试模式
         */
        // 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId
        Bugly.init(getApplication(), "19a472c4c3", true);
    }


    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        // you must install multiDex whatever tinker is installed!
        MultiDex.install(base);

        // 安装tinker
        // TinkerManager.installTinker(this); 替换成下面Bugly提供的方法
        Beta.installTinker(this);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {
        getApplication().registerActivityLifecycleCallbacks(callbacks);
    }

}

step6、打包基准包
在terminal中输入gradlew assembleRelease
然后在build目录下新建bakApk文件夹app/build/bakApk
将生成的app-release.apk mapping.txt R.txt 拷贝到该文件夹
R.txt文件在app/build/intermediates/symbols/release/R.txt目录下
这里写图片描述

step7、发布基准包
在腾讯bugly新建产品 并上传安装包
这里写图片描述

step8、编译生成补丁包

在ternimal输入gradlew tinkerPatchRelease
这里写图片描述
其中patch_signed_7zip.apk就是我们要的补丁包
step9、发布补丁包
这里写图片描述

okay 继承tinker热更新就完成了
github:https://github.com/shenglintang/tinkerDemo
scdn:http://download.youkuaiyun.com/my

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值