تینکر ابزار رسمی WeChat و توسعه داده شده توسط کمپانی چینی Tencent است که قابلیت توزیع پویای کد را در اختیار برنامهنویسان اندروید قرار میدهد. با استفاده از این ابزار میتوان بدون نیاز به نصب مجدد، برنامه اندرویدی را بهروزرسانی کرد و مشکلات برنامه را رفع کرد و قابلیتهای مختلفی به آن افزود یا حذف کرد.
جز تینکر ابزارهای متنوعی برای hot patch وجود دارد. مانند Ali’s AndFix، American League’s Robust و QZone’s Super Patch که مقایسه این ابزارها در زیر آمده است:
به شکل خلاصه:
به علت محدودیتهای سیستمی اندروید، ابزار تینکر در موارد زیر ناکارآمد است:
برای استفاده از تینکر، در تنظیمات گردل پروژه وابستگی آن را اضافه میکنیم:
buildscript { dependencies { classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1') } }
همچنین در تنظیمات گردل برنامه نیز باید تنظیمات زیر اعمال شود:
dependencies { provided('com.tencent.tinker:tinker-android-anno:1.9.1') //tinker core library compile('com.tencent.tinker:tinker-android-lib:1.9.1') } ... ... apply plugin: 'com.tencent.tinker.patch'
ابزار تینکر با استفاده از فایل apk برنامهی گذشته و مقایسهی آن با فایل apk برنامهی جدید، یک پچ شامل تغییرات تولید کرده و با استفاده از آن برنامهی قدیمی نصب شده روی دستگاه کاربر را به روز میکند.
تنظیمات عمومی تینکر:
تنظیمات مرتبط با مراحل کامپایل و بیلد:
تنظیمات مرتبط با dex:
تنظیمات مرتبط با منابع:
در نهایت پس از کامپایل و تولید فایلهای پچ موارد زیر در پوشهی خروجی که به طور پیشفرض مسیر build/outputs/tinkerPatch است قرار میگیرند:
همچنین بدون نیاز به ابزار gradle و با دستورات خط فرمان نیز میتوان با داشتن فایلهای apk جدید و قدیم فایل پچ نهایی را تولید کرد. برای اینکار از ابزار tinker-patch-cli.jar توسعه داده شده توسط خود توسعهدهندگان تینکر میتوان به شکل زیر استفاده کرد:
java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output_path
تنظیمات موجود در tinker_config.xml همان تنظیمات گردل توضیح داده شده در بالا هستند که مثالی از آن در این لینک موجود است با این تفاوت که در این حالت باید tinker_id داخل فایل manifest به شکل زیر قرار بگیرد:
<meta-data android:name="TINKER_ID" android:value="tinker_id_b168b32"/>
مثال عملیاتی از تینکر
در این لینک نمونهای از یک برنامه نوشته شده با تینکر وجود دارد که در ادامه آن را توضیح میدهیم.
برای تولید برنامه همراه با ابزار تینکر لازم است کلاس SampleApplicationLike که از کلاس DefaultApplicationLike به ارث میبرد، در برنامه وجود داشته باشد که در آن تنظیمات گوناگونی شامل تنظیمات application و context و... قرار میگیرد. مرجع این فایل در این لینک قابل مشاهده است. همچنین اگر کلاسی در برنامه داشته باشیم که از کلاس Application ارثبری میکند باید تمام موارد پیادهسازی شده در آن را به کلاس SampleApplicationLike اشاره شده در بالا منتقل کنیم و این کلاس را به شکل زیر تبدیل کنیم:
public class SampleApplication extends TinkerApplication { public SampleApplication() { super( ShareConstants.TINKER_ENABLE_ALL, // This is passed as a string so the shell application does not // have a binary dependency on your ApplicationLifeCycle class. "tinker.sample.android.app.SampleApplicationLike"); } }
سایر تنظیمات مرتبط با تینکر داخل تنظیمات گردل قرار میگیرند که در نمونهی اشاره شده قابل مشاهده است.
در کلاس MainActivity و در تعریف تابع مرتبط با کلیک روی دکمهی Do Crash، به قسمتی از آرایه که وجود ندارد دسترسی اتفاق میافتد که در نتیجه برنامه با خطا روبرو شده و بسته میشود:
ArrayList<String> strings = new ArrayList<>(); Strings.get(0);
برای اعمال پچ، قسمت خطادار حذف شده و یک اعلان مبنی بر رفع خطا نمایش داده میشود و رنگ دکمه به رنگ سبز درمیآید:
Toast.makeText(MainActivity.this, “Bug Fixed”, Toast.LENGTH_SHORT).show(); bugTest.setBackgroundColor(getResources().getColor(android.R.color.halo_green_light));
حال به این میپردازیم که پچ چگونه تولید میشود و چگونه برنامهی کاربر با استفاده از آن به روز میشود.
برای ساخت پچ جدید، ابتدا تنظیمات گردل را مطابق توضیحات تنظیمات آن اعمال میکنیم و مسیر فایل apk قدیمی را در تنظیم oldApk قرار میدهیم. صرفا با استفاده از ابزارهای موجود در گردل ذیل قسمت تینکر، فایل پچ جدید را ایجاد میکنیم.
برای این که برنامه بتواند به پچ جدید دسترسی داشته باشد، نیاز تا از طریقی از وجود پچ جدید آگاه شود. برای اینکار، هر بار که برنامه شروع به کار میکند با فراخوانی تابع fetchConfig وجود پچ جدید از یک API Endpoint استعلام میشود و با کسب اجازه از کاربر این فایل جدید دانلود شده و با فراخوانی ابزار تینکر پچ جدید نصب میگردد:
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), file.getAbsolutePath());
به عنوان API Endpoint از ابزار رایگان Beeceptor استفاده نمودیم و نمونه پاسخ این API به شکل زیر است:
{ "patch_available": true, "patch_id": "p_1157", "patch_url": "https://bayanbox.ir/download/1689140552403622929/patch-signed-7zip.apk" }
در صورت true بودن مقدار patch_available و همچنین جلوتر بودن patch_id از نسخهی فعلی، فایل پچ دانلود شده و اعمال میشود. با اعمال پچ، برنامه ریستارت شده و برنامهی جدید که شامل پچ جدید است شروع به کار میکند.
تهیه شده برای درس برنامهنویسی موبایل ارائه شده در نیمسال دوم تحصیلی ۰۰-۹۹ دانشگاه صنعتی شریف