3dwoo大學簡體電腦書店
Android插件化開發指南
( 簡體 字)
作者:包建強 著類別:1. -> 程式設計 -> 手機程式 -> Android
出版社:機械工業出版社Android插件化開發指南 3dWoo書號: 49628
詢問書籍請說出此書號!
有庫存
NT售價: 395
出版日:8/1/2018
頁數:320
光碟數:0
站長推薦:
印刷:黑白印刷語系: ( 簡體 字 )
ISBN:9787111603368 加入購物車加到我的最愛 (請先登入會員)
(簡體書上所述之下載連結耗時費功, 恕不適用在台灣, 若讀者需要請自行嘗試, 恕不保證, 繁體書的下載亦請直接連絡出版社)
序一
序二
序三
前言
第一部分 預備知識
第1章 插件化技術的昨天、今天與明天2
1.1 插件化技術是什么2
1.2 為什么需要插件化3
1.3 插件化技術的歷史3
1.4 插件化技術的用途到底是什么8
1.5 更好的替代品:React Native8
1.6 只有中國這么玩嗎9
1.7 四大組件都需要插件化技術嗎10
1.8 雙開和虛擬機10
1.9 從原生頁面到HTML 5的過渡11
1.10 本章小結12
第2章 Android底層知識13
2.1 概述13
2.2 Binder原理14
2.3 AIDL原理16
2.4 AMS20
2.5 Activity工作原理21
2.5.1 App是怎么啟動的21
2.5.2 啟動App并非那么簡單21
2.6 App內部的頁面跳轉32
2.7 Context家族史34
2.8 Service工作原理36
2.8.1 在新進程啟動Service36
2.8.2 啟動同一進程的Service39
2.8.3 在同一進程綁定Service39
2.9 BroadcastReceiver工作原理41
2.9.1 注冊過程43
2.9.2 發送廣播的流程44
2.9.3 廣播的種類45
2.10 ContentProvider工作原理46
2.10.1 ContentProvider的本質49
2.10.2 匿名共享內存(ASM)49
2.10.3 ContentProvider與AMS的通信流程50
2.11 PMS及App安裝過程52
2.11.1 PMS簡介52
2.11.2 App的安裝流程52
2.11.3 PackageParser53
2.11.4 ActivityThread與PackageManager54
2.12 ClassLoader家族史55
2.13 雙親委托57
2.14 MultiDex57
2.15 實現一個音樂播放器App59
2.15.1 基于兩個Receiver的音樂播放器59
2.15.2 基于一個Receiver的音樂播放器63
2.16 本章小結68
第3章 反射70
3.1 基本反射技術70
3.1.1 根據一個字符串得到一個類70
3.1.2 獲取類的成員71
3.1.3 對泛型類的反射75
3.2 jOOR77
3.2.1 根據一個字符串得到一個類78
3.2.2 獲取類的成員78
3.2.3 對泛型類的反射79
3.3 對基本反射語法的封裝80
3.3.1 反射出一個構造函數81
3.3.2 調用實例方法81
3.3.3 調用靜態方法82
3.3.4 獲取并設置一個字段的值82
3.3.5 對泛型類的處理83
3.4 對反射的進一步封裝84
3.5 本章小結88
第4章 代理模式89
4.1 概述89
4.1.1 遠程代理(AIDL)90
4.1.2 保護代理(權限控制)92
4.1.3 虛代理(圖片占位)92
4.1.4 協作開發(Mock Class)92
4.1.5 給生活加點料(記日志)93
4.2 靜態代理和動態代理94
4.3 對AMN的Hook95
4.4 對PMS的Hook97
4.5 本章小結98
第5章 對startActivity方法進行Hook99
5.1 startActivity方法的兩種形式99
5.2 對Activity的startActivity方法進行Hook100
5.2.1 方案1:重寫Activity的startActivityForResult方法102
5.2.2 方案2:對Activity的mInstrumentation字段進行Hook102
5.2.3 方案3:對AMN的getDefault方法進行Hook104
5.2.4 方案4:對H類的mCallback字段進行Hook107
5.2.5 方案5:再次對Instrumentation字段進行Hook109
5.3 對Context的startActivity方法進行Hook111
5.3.1 方案6:對ActivityThread的mInstrumentation字段進行Hook111
5.3.2 對AMN的getDafault方法進行Hook是一勞永逸的113
5.4 啟動沒有在AndroidManifest中聲明的Activity113
5.4.1 “欺騙AMS”的策略分析114
5.4.2 Hook的上半場115
5.4.3 Hook的下半場:對H類的mCallback字段進行Hook118
5.4.4 Hook的下半場:對ActivityThread的mInstrumentation字段進行Hook119
5.4.5 “欺騙AMS”的弊端121
5.5 本章小結121
第二部分 解決方案
第6章 插件化技術基礎知識124
6.1 加載外部的dex124
6.2 面向接口編程126
6.3 插件的瘦身129
6.4 對插件進行代碼調試131
6.5 Application的插件化解決方案133
6.6 本章小結134
第7章 資源初探135
7.1 資源加載機制135
7.1.1 資源分類135
7.1.2 剪不斷理還亂:Resources和AssetManager136
7.2 資源的插件化解決方案137
7.3 換膚141
7.4 殊途同歸:另一種換膚方式149
7.5 本章小結149
第8章 最簡單的插件化解決方案150
8.1 在AndroidManifest中聲明插件中的組件150
8.2 宿主App加載插件中的類151
8.3 啟動插件Service152
8.4 加載插件中的資源152
8.5 本章小結154
第9章 Activity的插件化解決方案155
9.1 啟動沒有在AndroidManifest中聲明的插件Activity155
9.2 基于動態替換的Activity插件化解決方案159
9.2.1 Android啟動Activity的原理分析159
9.2.2 故意命中緩存160
9.2.3 加載插件中類的方案1:為每個插件創建一個ClassLoader164
9.2.4 為了圓一個謊言而編造更多的謊言164
9.3 加載插件中類的方案2:合并多個dex166
9.4 為Activity解決資源問題169
9.5 對LaunchMode的支持169
9.6 加載插件中類的方案3:修改App原生的ClassLoader172
9.7 本章小結174
第10章 Service的插件化解決方案175
10.1 Android界的荀彧和荀攸:Service和Activity175
10.2 預先占位176
10.3 startService的解決方案178
10.4 bindService的解決方案183
10.5 本章小結185
第11章 BroadcastReceiver的插件化解決方案186
11.1 Receiver概述186
11.2 動態廣播的插件化解決方案187
11.3 靜態廣播的插件化解決方案187
11.4 靜態廣播的插件化終極解決方案189
11.5 本章小結193
第12章 ContentProvider的插件化解決方案194
12.1 ContentProvider基本概念194
12.2 一個簡單的ContentProvider例子195
12.3 ContentProvider插件化197
12.4 執行這段Hook代碼的時機199
12.5 ContentProvider的轉發機制200
12.6 本章小結201
第13章 基于靜態代理的插件化解決方案:that框架202
13.1 靜態代理的思想202
13.2 一個最簡單的靜態代理的例子203
13.2.1 從宿主Activity跳轉到插件Activity203
13.2.2 ProxyActivity與插件Activity的通信204
13.2.3 插件Activity的邏輯206
13.3 插件內部的頁面跳轉206
13.4 從“肉體”上消滅that關鍵字207
13.5 插件向外跳轉209
13.6 面向接口編程在靜態代理中的應用211
13.7 對LaunchMode的支持216
13.8 本章小結221
第14章 that框架對Service和BroadcastReceiver的支持222
14.1 靜態代理的思想在Service的應用222
14.2 對BindService的支持227
14.3 Service的預先占位思想229
14.4 Service插件化的終極解決方案:動靜結合231
14.4.1 解析插件中的Service231
14.4.2 通過反射創建一個Service對象232
14.4.3 ProxyService與ServiceManager234
14.4.4 bindService的插件化解決方案240
14.5 靜態代理的思想在BroadcastReceiver的應用245
14.6 本章小結248
第15章 再談資源249
15.1 Android App的打包流程249
15.2 修改AAPT251
15.2.1 修改并生成新的aapt命令251
15.2.2 在插件化項目中使用新的aapt命令254
15.3 public.xml固定資源id值256
15.4 插件使用宿主的資源258
15.5 本章小結259
第16章 基于Fragment的插件化框架261
16.1 AndroidDynamicLoader概述261
16.2 最簡單的Fragment插件化例子262
16.3 插件內部的Fragment跳轉263
16.4 從插件的Fragment跳轉到插件外部的Fragment264
16.5 本章小結266
第三部分 相關技術
第17章 降級268
17.1 從Activity到HTML 5269
17.2 從HTML 5到Activity273
17.3 對返回鍵的支持278
17.4 本章小結278
第18章 插件的混淆279
18.1 插件的基本混淆279
18.2 方案1:不混淆公共庫MyPluginLibrary280
18.3 方案2:混淆公共庫MyPluginLibrary282
18.3.1 配置multidex283
18.3.2 配置proguard285
18.3.3 移除Plugin1.apk中的冗余dex286
18.4 本章小結287
第19章 增量更新288
19.1 如何使用增量更新288
19.2 制作插件的增量包289
19.3 App下載增量包并解壓到本地289
19.4 App合并增量包290
19.5 本章小結291
第20章 so的插件化解決方案292
20.1 編寫一個最簡單的so292
20.2 使用so296
20.3 so的加載原理298
20.4 基于System.load的插件化解決方案301
20.5 基于System.loadLibrary的插件化解決方案304
20.6 本章小結305
第21章 對App的打包流程進行Hook306
21.1 自定義Gradle插件306
21.1.1 創建Gradle自定義插件項目306
21.1.2 Extension又是什么308
21.1.3 修改打包流程309
21.2 修改resources.arsc311
21.2.1 Android是怎么查找資源的311
21.2.2 aapt都干了什么312
21.2.3 gradle-small的工作原理313
21.2.4 怎么使用gradle-small313
21.2.5 gradle-small中的Plugin家族313
21.2.6 gradle-small中的Editor家族317
21.3 本章小結318
第22章 插件化技術總結319
22.1 插件的工程化319
22.2 插件中類的加載319
22.3 哪些地方可以Hook320
22.4 Activity插件化的解決方案320
22.5 資源的解決方案321
22.6 Fragment是哪門哪派322
22.7 Service、ContentProvider、BroadcastReceiver插件化的通用解決方案322
22.8 特定于Service的插件化解決方案322
22.9 特定于BroadcastReceiver的插件化解決方案323
22.10 特定于ContentProvider的插件化解決方案323
22.11 本章小結323
附錄
附錄A 常用工具326
附錄B 本書代碼索引328
本書詳細介紹了插件化技術的原理、各種方案,及其在Android App中的使用方法。本書在介紹插件化技術的同時,還詳細介紹了Android 系統的底層知識,有助于App開發人員深入理解Android系統,從而寫出更健壯的代碼。

全書分為三大部分,共22章。第一部分“預備知識”包括第1~5章,是進行Android插件化編程的準備知識,先介紹Android插件化技術的歷史和現狀,系統介紹了Android的底層知識以及反射、代理等技術。第二部分“解決方案”包括第6~16章,詳細介紹并分析了插件化編程的各種解決方案,以及一些插件化框架的實現原理,如DL、Zeus等。第三部分“相關技術”包括第17~21章,介紹插件化編程的周邊技術,包括降級、混淆、增量更新等,并對紛繁復雜的插件化技術進行了總結。
這是一本什么書
如果只把本書當作純粹介紹Android插件化技術的書那就錯了。本書在研究Android插件化之余,還詳細介紹了Android系統的底層知識,包括Binder和AIDL的原理、四大組件的原理、App的安裝和啟動流程、Context和ClassLoader的家族史。沒有羅列大量的Android系統中的源碼,而是以一張張UML圖把這些知識串起來。
本書詳細介紹了Android中的資源機制,包括aapt命令的原理、resource文件的組成以及public.xml的使用方式,順帶還提及了如何自定義一個Gradle插件化。
此外,本書還介紹了so的加載原理,尤其是動態加載so的技術,可以幫助App進行瘦身;探討了HTML5降級技術,可以實現任何一個原生頁面和HTML5頁面的互換;介紹了反射技術,以及jOOR這個有趣的開源框架;介紹了Android中的動態代理技術Proxy.newProxyInstance方法。
如果讀者能堅持把這本書從頭到尾讀完,那么不僅掌握了插件化技術,而且也把上述所有這些知識點全都系統地學習了一遍。也許Android插件化會隨著Google的限制而有所變化甚至消亡,但我在本書中介紹的其他知識,仍然是大有用武之處的。
如何面對Android P的限制
寫作這本書的時候,Google推出了Android P preview的操作系統,會限制對@hide api的反射調用。目前會通過log發出警告,用戶代碼仍然能夠獲取到正確的Method或Field,在后續版本中獲取到的Method或Field極有可能為空。
但是道高一尺,魔高一丈。Google對這次限制,很快就被技術極客們繞過去了,有兩種解決方法:
1)把通過反射調用的系統內部類改為直接調用。具體操作辦法是,在Android項目中新建一個庫,把要反射的類的方法和字段復制一份到這個庫中,App對這個庫的引用關系設置為provided。那么我們就可以在App中直接調用這個類和方法,同時,在編譯的時候,又不會把這些類包含到apk中。
其實早在2015年,hoxkx就在他的插件化框架中實現了這種技術。但是這種解決方案,僅限于Android系統中標記為public的方法和字段,對于protected和private就無能為力了。比如AssetsManager的addAssetPath方法,ActivityThread的currentActivityThread方法。
2)類的每個方法和字段都有一個標記,表明它是不是hide類型的。我們只要在jni層,把這個標記改為不是hide的,就可以繞過檢查了。
然而,魔高一丈,道高一丈二。Google在Android P的正式版中勢必會推出更嚴厲的限制方案,到時候,又會有新的解決方案面世,讓我們拭目以待。
其實,開發者是無意和Google進行技術對抗的,這是毫無意義的。泛濫成災的修改導致了App大量的崩潰,Google實在看不下去了,所以才搞出這套限制方案;另一方面,插件化技術是剛需,尤其在中國的互聯網行業,App崩潰會直接影響使用,很可能導致經濟損失,所以開發者才會不惜一切代價走插件化這條路。
再回到限制方案來,Google也不是清一色不要開發者使用系統底層的標記為hide的API,而是推出了一組黑灰名單,如下所示:
名  單 影  響
light-greylist 淺灰名單 僅打印警告日志,Google盡可能在未來版本提供 public API
dark-greylist 深灰名單 第三方App不能訪問,開發者可以申請把這份清單中的某些API加入到淺灰名單
blacklist 黑名單 第三方App不能訪問
所以,另一種應對策略是,在插件化中使用淺灰名單中的API,比如說ActivityThread的currentActivityThread方法。
Google的這組清單還在持續調整中,據我所知,給各大手機廠商的清單與其在社區中發布的清單略有出入。在Android P的正式版本中,這份清單會最終確定下來。所以現在中國的各個插件化框架的開發人員,都在等Android P的正式版本發布后再制定相應的策略。留給中國隊的時間不多了。
這本書的來龍去脈
這是一本醞釀了3年的書。
早在2015年Android插件化技術百家爭鳴時,我就看好這個技術,想寫一本書介紹這個技術,但當時的積累還不夠。那年,我在一場技術大會上發表了《Android插件化從入門到放棄》演講,四十五分鐘介紹了插件化技術的皮毛。后來這個演講內容被整理成文章發布到網上,流傳很廣。
2017年1月,有企業要我去講2天Android插件化技術。為此,我花了一個月時間,準備了四十多個例子。這是我第一次系統地積累了素材。
2017年6月,我在騰訊課堂做Android線上培訓,為了宣傳推廣我的課程,我寫了一系列文章《寫給Android App開發人員看的Android底層知識》,共8篇,沒列太多代碼,完全以UML圖的方式向讀者普及Binder、AIDL、四大組件、AMS、PMS的知識。本書的第2章就是在這8篇文章的基礎之上進行擴充的。
2018年1月,我父親住院一周。我當時在醫院每天晚上值班。老爺子半夜打呼嚕,吵得我睡不著,事后我才知道,我睡著了打呼嚕聲音比他還大。半夜睡不著時就開始了本書的寫作,每晚堅持寫到凌晨兩三點。直到父親出院,這本書寫了將近五分之一。
碰巧的是,這一年5月底我結婚,促使我想在5月初完成這本書的一稿,為此,我宅在家里整整寫了3個月。僅以此書作為新婚禮物獻給我親愛的老婆,感謝你的理解,這本書才得以面世。
這兩年我在忙什么
2016年5月寫完《App研發錄》后不久,我就從一線互聯網公司出來,開始了長達兩年的App技術培訓工作。一改之前十幾年在辦公室悶頭研究技術的工作方式,開始在全中國飛來飛去,給各大國企、傳統公司、手機商的Android和iOS團隊進行培訓。這兩年去過了近百家公司,有了很多與過去十幾年不一樣的感受。
App開發人員的分布也呈金字塔型,在金字塔尖的自然是那些一線互聯網的開發人員,他們掌握Android和iOS最先進的技術,比如組件化、插件化等技術,但這些人畢竟是少數。而位于金字塔底端的開發人員則是大多數,他們大都位于創業公司或者傳統行業,相應的App側重于業務的實現,對App的高端技術,用得不多,需要不斷補充新知識。另外,我在騰訊課堂講了幾個月App開發課程的過程中,認識了很多學員,有幾千粉絲,同樣面臨需要不斷學習新知識。
寫作這本書的目的,是向廣大Android開發人員普及插件化技術。
這本書里講些什么
戰戰兢兢寫下這本書,有十幾萬字,仍不能覆蓋Android插件化的所有技術。因為插件化技術千頭萬緒,流派眾多,我想從最基本的原理講起,配合大量的例子,希望能幫助完全不懂Android插件化技術的小白,升級為一個精通這類技術的高手。
面對業內各種成熟的插件化框架,我只選取了具有代表意義的DroidPlugin、DL、Small和Zeus進行介紹,這幾個框架基本覆蓋了插件化編程的所有思想,而且非常簡單,像Zeus只有11個類,就支撐起掌閱App的插件化。而對于后期推出的VirtualApk、Atlas、Replugin等,在本書中并沒有介紹,主要是因為這些框架都是大塊頭,代碼量很多,我沒有精力再去研究和學習了。但這些企業級插件化框架所用的技術,本書都有涉及。
本書的結構及內容
全書分為三大部分,共22章。第1部分“預備知識”包括第1~5章,是進行Android插件化編程的準備知識。第2部分“解決方案”包括第6~16章,詳細介紹并分析了插件化編程的各種解決方案。第3部分“相關技術”包括第17~21章,介紹插件化編程的周邊技術,并對紛繁復雜的插件化技術進行了總結。
第1章介紹的是Android插件化的歷史,可以當作小說來讀,茶余飯后,地鐵站中就可以讀完。
第2章介紹Android底層知識,涉及那些與Android插件化相關的知識,比如Binder和AIDL,Android App的安裝流程和啟動流程,ActivityThread,LoadedApk,Android四大組件的運行原理。這一章篇幅較多,需要仔細研讀。其中,講到一個音樂播放器的例子,幫助大家更加深刻地認識Android的四大組件。
第3章講反射,詳細介紹了構造函數、方法、字段、泛型的反射語法。這章介紹了Java領域很火的一個開源庫jOOR,可惜,它對Android的支持并不是很好,所以這章還介紹了我們自己封裝的RefInvoke類,這個類將貫穿本書,基本上所有源碼例子都會使用到它。
第4章講代理模式。這個模式在Android中最著名的實現就是Proxy.newProxyInstance方法。基于此,我們Hook了AMS和PMS中的一些方法。
第5章是第4章的延續,仍然是基于Proxy.newProxyInstance方法,Hook了Activity的啟動流程,從而可以啟動一個沒有在AndroidManifest中聲明的Activity,這是插件化的核心技術之一。
第6章介紹了如何加載插件App,以及如何對插件化項目的宿主App和插件App同時進行調試。說到插件化編程,離不開面向接口編程的思想,這章也花了很多筆墨介紹這個思想,以及具體的代碼實現。
第7章介紹了資源的加載機制,包括AssetManager和Resources,并給出了資源的插件化解決方案,從而為Activity的插件化鋪平了道路。另外還介紹了換膚技術的插件化實現。
第8章介紹了最簡單的插件化解決方案,通過在宿主App的AndroidManifest中事先聲明插件中的四大組件。為了能讓宿主App隨意加載插件的類,這章介紹了合并dex的技術方案。
第9章到第12章介紹了Android四大組件的插件化解決方案。四大組件的生命周期各不相同,所以它們各自的插件化解決方案也都不同。
第13章、第14章介紹了Android插件化的靜態代理的解決方案。這是一種“牽線木偶”的思想,我們不用Hook太多Android系統底層的代碼。
第15章再次講到資源,這次要解決的是宿主和多個插件的資源id值沖突的問題。這一章介紹了多種解決方案,包括思路分析、代碼示例。
第16章介紹一種古老的插件化解決方案,通過動態替換Fragment的方式。
第17章介紹了App的降級解決方案。一旦插件化方案不可用,那么我們仍然可以使用H5,來替換任何一個App原生頁面。
第18章介紹了插件的混淆技術。有時候宿主App和插件App都會引用MyPluginLibrary這個類庫,這個公用類庫是否要混淆,相應有兩種不同的混淆方案。
第19章介紹了增量更新技術。這是插件化必備的技術,從而保證插件的升級,不需要從服務器下載太大的包。
第20章介紹了so的插件化解決方案。這章詳細介紹了so的加載原理,以及從服務器動態加載so的方案,基于此,有兩種so的插件化解決方案。
第21章介紹了gradle-small這個自定義Gradle插件。這章是對第15章的補充,是另一種解決插件資源id沖突的方案。
第22章作為整本書的結尾,系統總結了Android插件化的各種解決方案。如果讀者能堅持讀到這最后一章,可以幫助讀者鞏固這些知識。
關于本書名詞解釋
本書有很多專業術語,剛接觸Android插件化的讀者可能不容易理解。有一些專業術語還有別稱或者簡稱,我在這里羅列出最常見的一些術語:
HostApp,本書中有時也寫作“宿主App”。用于承載各種插件App,是最終發版的App。我們從Android市場上下載的都是HostApp。
Plugin,本書中有時也寫作“插件”、“插件App”。
Receiver,是BroadcastReceiver的簡稱,Android四大組件之一。
AndroidManifest,也就是AndroidManifest.xml。
Hook,就是使用反射修改Android系統底層的方法和字段。
AMS,是ActivityManagerService的簡稱,在App運行時和四大組件進行通信。
PMS,是PackageManagerService的簡稱,用于App的安裝和解析。
關于本書的源碼
本書精心挑選了70多個例子,都可以直接下載使用,正文中都列出了代碼名稱,在相應網站可以找到。附錄B還列出了所有源碼對應的章節。
致謝
幾乎所有的書都千篇一律地感謝很多人,卻不寫為什么要感謝他們。我在這里一定要把感謝的理由說清楚。
首先,感謝我那古靈精怪的老婆郭曼云。謝謝她在我人生迷惘的時候及時出現,陪我玩王者榮耀,帶我騎小黃車去散心,看電影時一起八卦劇情然后被坐在旁邊的觀眾出聲制止。她每天要我做不一樣的飯菜給她吃,把我鍛煉成廚房小能手,我現在已經習慣于每天傍晚五點半就放下手中所有的活兒,愉快地投入買菜做飯的工作。
感謝張勇、任玉剛、羅迪、黃劍、林光亮、鄧凡平、王堯波、田維術等Android領域的朋友們,我在寫作這本書的時候,經常會遇到各種疑惑,每次問到他們,他們都會不厭其煩地給我詳細解答。
在這里,尤其感謝田維術,他的技術博客(weishu.me)“介紹插件化的一系列文章”對我的影響很大,可惜沒寫完,只講了Binder原理和四大組件的插件化方案。本書的部分章節參考了他的博客文章,對他提供的一些代碼例子進行了二次加工。經過他本人同意后,收入這本書中。代碼中的很多類上都標注了作者是weishu,以表達對他的感謝。
感謝任正浩、霹靂嬌娃、趙越、Dinosaur等這群狐朋狗友的陪伴,我從互聯網公司出來轉型做App技術培訓的過程中,整理了半年PPT教程后才開始陸陸續續接到單子,在這半年時間里,我就跟這幫學弟學妹廝混在一起,爬山、撕名牌、唱K、密室逃脫、狼人殺,還有一陣時間沉迷于你畫我猜。那是我最愜意的一段時光。
感謝我爸我媽以及咱爸咱媽,你們的女兒我一定照顧好。雖然北京與天津距離那么近,很抱歉還是不能常回家看看,我永遠是那么忙,忙著去追求事業的成功,距離財務自由還很遠,但是我一直在努力。
最后,感謝曹洪偉等21位社區朋友的辛勤勞動,把這本書翻譯為英文,限于篇幅,這里就不一一致謝了。接下來,這本書的英文版本會在國外網站社區逐篇發布,乃至出版成書,讓全世界的Android開發人員看到中國工程師們的智慧結晶。

包建強
2018年6月于北京
pagetop