تحديث Android الساخن Tinker + تغليف متعدد القنوات + عرض توضيحي مفصل لعملية التعزيز
في الآونة الأخيرة، تمت صيانة ستة مشاريع وإطلاقها في وقت واحد في غضون شهرين، وكان العديد منها عبارة عن مشكلات بسيطة، ولكن الأمر استغرق الكثير من الموارد البشرية والمادية للحصول على إصدارات محدثة فقط عبر الإنترنت، لذلك أمضيت يومًا في دمج Tinker، مكتبة التحديثات الساخنة مفتوحة المصدر الخاصة بـ WeChat ، ووضعه قيد الاستخدام، ويعتبر العرض التعليمي مفتوح المصدر للمبرمجين الجدد في التحديثات الساخنة.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.8"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
قم بإضافة تبعيات التبعيات إلى المهد في التطبيق. ملاحظة: هذين المهدين ليسا نفس المهد. إن هيكل البناء أعلاه مخصص للمشروع بأكمله، وقاعدة البناء التالية موجودة داخل التطبيق.
dependencies {
// 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
provided("com.tinkerpatch.tinker:tinker-android-anno:1.8.0")
compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.8")
}
لاحظ أنه إذا كنت تستخدم التعليقات التوضيحية لإنشاء التطبيق تلقائيًا، فستحتاج إلى تقديم مكتبة Tinker-android-anno الخاصة بـ Tinker بشكل منفصل. بالإضافة إلى ذلك، لا نحتاج إلى تقديم مكتبات العبث الأخرى بشكل منفصل.
من أجل البساطة والراحة، قمنا بوضع جميع التكوينات ذات الصلة بـ TinkerPatch في tinkerpatch.gradle، ونحتاج إلى تقديمها:
التقديم من: "tinkerpatch.gradle"
حسنًا، بعد ذلك سنقوم بإنشاء tinkerpatch.gradle في دليل التطبيق، كما هو موضح في الصورة:
افتح tinkerpatch.gradle، ثم ضع جميع التكوينات ذات الصلة بـ TinkerPatch في tinkerpatch.gradle.
apply plugin: 'tinkerpatch-support'
/**
* TODO: 请按自己的需求修改为适应自己工程的参数
*/
//基包路径
def bakPath = file("${buildDir}/bakApk/")
//基包文件夹名(打补丁包的时候,需要修改)
def baseInfo = "app-1.0.1-0221-11-01-38"
//版本名称
def variantName = "release"
/**
* 对于插件各参数的详细解析请参考
*
*/
tinkerpatchSupport {
//可以在debug的时候关闭 tinkerPatch
tinkerEnable = true
//是否使用一键接入功能 默认为false 是否反射 Application 实现一键接入;
// 一般来说,接入 Tinker 我们需要改造我们的 Application, 若这里为 true, 即我们无需对应用做任何改造即可接入。
reflectApplication = true
//将每次编译产生的 apk/mapping.txt/R.txt 归档存储的位置
autoBackupApkPath = "${bakPath}"
appKey = "582e640cae57f603"// 注意!!! 需要修改成你的appkey
/** 注意: 若发布新的全量包, appVersion一定要更新 **/
appVersion = "1.0.1"
protectedApp=true//使用加固
def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
def name = "${project.name}-${variantName}"
/**
* 基准包的文件路径, 对应 tinker 插件中的 oldApk 参数;编译补丁包时,
* 必需指定基准版本的 apk,默认值为空,则表示不是进行补丁包的编译
*/
baseApkFile = "${pathPrefix}/${name}.apk"
/**
* 基准包的 Proguard mapping.txt 文件路径, 对应 tinker 插件 applyMapping 参数;在编译新的 apk 时候,
* 我们希望通过保持基准 apk 的 proguard 混淆方式,
* 从而减少补丁包的大小。这是强烈推荐的,编译补丁包时,我们推荐输入基准 apk 生成的 mapping.txt 文件。
*/
baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
/**
* 基准包的资源 R.txt 文件路径, 对应 tinker 插件 applyResourceMapping 参数;在编译新的apk时候,
* 我们希望通基准 apk 的 R.txt 文件来保持 Resource Id 的分配,这样不仅可以减少补丁包的大小,
* 同时也避免由于 Resource Id 改变导致 remote view 异常
*/
baseResourceRFile = "${pathPrefix}/${name}-R.txt"
/**
* 若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample
* 注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)
**/
}
/**
* 用于用户在代码中判断tinkerPatch是否被使能
*/
android {
defaultConfig {
buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
}
}
/**
* 一般来说,我们无需对下面的参数做任何的修改
* 对于各参数的详细介绍请参考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
ignoreWarning = false
useSign = true //是否需要签名,打正式包如果这里是true,则要配置签名,否则会编译不过去
dex {
dexMode = "jar"
pattern = ["classes*.dex"]
loader = []
}
lib {
pattern = ["lib/*/*.so"]
}
res {
pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
ignoreChange = []
largeModSize = 100
}
packageConfig {
}
sevenZip {
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
// path = "/usr/local/bin/7za"
}
buildConfig {
keepDexApply = false
}
}
الشيء الآخر الذي يحتاج إلى الاهتمام هنا هو مفتاح التطبيق. بعد تسجيل الدخول إلى الموقع الرسمي لـ tinker وإضافة إصدار التطبيق، سيتم إنشاء مفتاح التطبيق، وسنحتاج إلى ملء مفتاح التطبيق الخاص بنا في التكوين أعلاه وإرفاق صورة:
package com.barnettwong.tinkerdemo;
import android.app.Application;
import com.tencent.tinker.loader.app.ApplicationLike;
import com.tinkerpatch.sdk.TinkerPatch;
import com.tinkerpatch.sdk.loader.TinkerPatchApplicationLike;
/**
* Created by wang on 2019-2-20.
* reflectApplication = true 时
*/
public class tinkerApplication extends Application {
private ApplicationLike tinkerApplicationLike;
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.TINKER_ENABLE) {
// 我们可以从这里获得Tinker加载过程的信息
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
// 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
TinkerPatch.init(tinkerApplicationLike)
.reflectPatchLibrary()
.setPatchRollbackOnScreenOff(true)
.setPatchRestartOnSrceenOff(true);
// 每隔3个小时去访问后台时候有更新,通过handler实现轮训的效果
new FetchPatchHandler().fetchPatchWithInterval(3);
}
}
}
وأخيرًا، قم بإضافة فئة FetchPatchHandler:
package com.barnettwong.tinkerdemo;
import android.os.Handler;
import android.os.Message;
import com.tinkerpatch.sdk.TinkerPatch;
/**
* Created by wang on 2019-2-20.
*/
public class FetchPatchHandler extends Handler {
public static final long HOUR_INTERVAL = 3600 * 1000;
private long checkInterval;
/**
* 通过handler, 达到按照时间间隔轮训的效果
*/
public void fetchPatchWithInterval(int hour) {
//设置TinkerPatch的时间间隔
TinkerPatch.with().setFetchPatchIntervalByHours(hour);
checkInterval = hour * HOUR_INTERVAL;
//立刻尝试去访问,检查是否有更新
sendEmptyMessage(0);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这里使用false即可
TinkerPatch.with().fetchPatchUpdate(false);
//每隔一段时间都去访问后台, 增加10分钟的buffer时间
sendEmptyMessageDelayed(0, checkInterval + 10 * 60 * 1000);
}
}
أخيرًا، أضف أذونات الشبكة وSD المقابلة إلى AndroidManifest.xml، وأضف android:name=".tinkerApplication" إلى التطبيق، وأرفق الكود:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:name=".tinkerApplication"
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>
</application>
لن يتم تفصيل عملية التغليف وإصدار التصحيح المحددة هنا. إذا كانت لديك أي أسئلة، فيرجى الاتصال بـ [email protected]
حقوق الطبع والنشر 2019، وانجفينج19930909
مرخص بموجب ترخيص Apache، الإصدار 2.0 ("الترخيص")؛ ولا يجوز لك استخدام هذا الملف إلا وفقًا للترخيص. يمكنك الحصول على نسخة من الترخيص على http://www.apache.org/licenses/LICENSE -2.0 ما لم يكن ذلك مطلوبًا بموجب القانون المعمول به أو تم الاتفاق عليه كتابيًا، يتم توزيع البرامج الموزعة بموجب الترخيص على أساس "كما هي"، دون ضمانات أو شروط من أي نوع، سواء كانت صريحة أو ضمنية لغة محددة تحكم الأذونات والقيود بموجب الترخيص.