日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

2020 Android 大厂面试-插件化、模块化、组件化,android开发环境的搭建视频

發(fā)布時間:2023/12/20 Android 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2020 Android 大厂面试-插件化、模块化、组件化,android开发环境的搭建视频 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

if (Constants.COMBINE_RESOURCES) {

//插件和主工程資源合并時需要hook住主工程的資源

Resources resources = ResourcesManager.createResources(context, apk.getAbsolutePath());

ResourcesManager.hookResources(context, resources);

return resources;

} else {

//插件資源獨立,該resource只能訪問插件自己的資源

Resources hostResources = context.getResources();

AssetManager assetManager = createAssetManager(context, apk);

return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());

}

//第二步:hook主工程的Resource

//對于合并式的資源訪問方式,需要替換主工程的Resource,下面是具體替換的代碼。

public static void hookResources(Context base, Resources resource

《Android學習筆記總結(jié)+最新移動架構(gòu)視頻+大廠安卓面試真題+項目實戰(zhàn)源碼講義》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整內(nèi)容開源分享

s) {

try {

ReflectUtil.setField(base.getClass(), base, “mResources”, resources);

Object loadedApk = ReflectUtil.getPackageInfo(base);

ReflectUtil.setField(loadedApk.getClass(), loadedApk, “mResources”, resources);

Object activityThread = ReflectUtil.getActivityThread(base);

Object resManager = ReflectUtil.getField(activityThread.getClass(), activityThread, “mResourcesManager”);

if (Build.VERSION.SDK_INT < 24) {

Map<Object, WeakReference> map = (Map<Object, WeakReference>) ReflectUtil.getField(resManager.getClass(), resManager, “mActiveResources”);

Object key = map.keySet().iterator().next();

map.put(key, new WeakReference<>(resources));

} else {

// still hook Android N Resources, even though it’s unnecessary, then nobody will be strange.

Map map = (Map) ReflectUtil.getFieldNoException(resManager.getClass(), resManager, “mResourceImpls”);

Object key = map.keySet().iterator().next();

Object resourcesImpl = ReflectUtil.getFieldNoException(Resources.class, resources, “mResourcesImpl”);

map.put(key, new WeakReference<>(resourcesImpl));

}

} catch (Exception e) {

e.printStackTrace();

}

替換了主工程context中LoadedApk的mResource對象

將新的Resource添加到主工程ActivityThread的mResourceManager中,并且根據(jù)Android版本做了不同處理

//第三步:關(guān)聯(lián)resource和Activity

Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);

activity.setIntent(intent);

//設置Activity的mResources屬性,Activity中訪問資源時都通過mResources

ReflectUtil.setField(ContextThemeWrapper.class, activity, “mResources”, plugin.getResources());

資源沖突

資源id是由8位16進制數(shù)表示,表示為0xPPTTNNNN, 由三部分組成:PackageId+TypeId+EntryId

修改aapt源碼,編譯期修改PP段。

修改resources.arsc文件,該文件列出了資源id到具體資源路徑的映射。

blog.csdn.net/jiangwei091…

// Main.cpp

result = handleCommand(&bundle);

case kCommandPackage: return doPackage(bundle);

// Command.cpp

int doPackage(Bundle* bundle) {

if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {

err = buildResources(bundle, assets, builder);

if (err != 0) {

goto bail;

}

}

}

Resource.cpp

buildResources

ResourceTable.cpp

switch(mPackageType) {

case App:

case AppFeature:

packageId = 0x7f;

break;

case System:

packageId = 0x01;

break;

case SharedLibrary:

packageId = 0x00;

break;

}

首先找到入口類:Main.cpp:main函數(shù),解析參數(shù),然后調(diào)用handleCommand函數(shù)處理參數(shù)對應的邏輯,我們看到了有一個函數(shù)doPackage。

然后就搜索到了Command.cpp:在他內(nèi)部的doPackage函數(shù)中進行編譯工具的一個函數(shù):buildResources函數(shù),在全局搜索,發(fā)現(xiàn)了Resource.cpp:發(fā)現(xiàn)這里就是處理編譯工作,構(gòu)建ResourceTable的邏輯,在ResourceTable.cpp中,也是獲取PackageId的地方,下面我們就來看看如何修改呢?

其實最好的方法是,能夠修改aapt源碼,添加一個參數(shù),把我們想要編譯的PackageId作為輸入值,傳進來最好了,那就是Bundle類型,他是從Main.cpp中的main函數(shù)傳遞到了最后的buildResources函數(shù)中,那么我們就可以把這個參數(shù)用Bundle進行攜帶。

juejin.im/entry/5c008… www.jianshu.com/p/8d691b6bf…

————————————————————————————————————————————————

cloud.tencent.com/developer/a…

在整個過程中,需要修改到R文件、resources.arsc和二進制的xml文件

四大組件支持

ProxyActivity代理

代理方式的關(guān)鍵總結(jié)起來有下面兩點:

ProxyActivity中需要重寫getResouces,getAssets,getClassLoader方法返回插件的相應對象。生命周期函數(shù)以及和用戶交互相關(guān)函數(shù),如onResume,onStop,onBackPressedon,KeyUponWindow,FocusChanged等需要轉(zhuǎn)發(fā)給插件。

PluginActivity中所有調(diào)用context的相關(guān)的方法,如setContentView,getLayoutInflater,getSystemService等都需要調(diào)用ProxyActivity的相應方法。

該方式有幾個明顯缺點:

插件中的Activity必須繼承PluginActivity,開發(fā)侵入性強。

如果想支持Activity的singleTask,singleInstance等launchMode時,需要自己管理Activity棧,實現(xiàn)起來很繁瑣。

插件中需要小心處理Context,容易出錯。

如果想把之前的模塊改造成插件需要很多額外的工作。

復制代碼

預埋StubActivity,hook系統(tǒng)啟動Activity的過程

VirtualAPK通過替換了系統(tǒng)的Instrumentation,hook了Activity的啟動和創(chuàng)建,省去了手動管理插件Activity生命周期的繁瑣,讓插件Activity像正常的Activity一樣被系統(tǒng)管理,并且插件Activity在開發(fā)時和常規(guī)一樣,即能獨立運行又能作為插件被主工程調(diào)用。

其他插件框架在處理Activity時思想大都差不多,無非是這兩種方式之一或者兩者的結(jié)合。在hook時,不同的框架可能會選擇不同的hook點。如360的RePlugin框架選擇hook了系統(tǒng)的ClassLoader,即構(gòu)造Activity2的ClassLoader,在判斷出待啟動的Activity是插件中的時,會調(diào)用插件的ClassLoader構(gòu)造相應對象。另外RePlugin為了系統(tǒng)穩(wěn)定性,選擇了盡量少的hook,因此它并沒有選擇hook系統(tǒng)的startActivity方法來替換intent,而是通過重寫Activity的startActivity,因此其插件Activity是需要繼承一個類似PluginActivity的基類的。不過RePlugin提供了一個Gradle插件將插件中的Activity的基類換成了PluginActivity,用戶在開發(fā)插件Activity時也是沒有感知的。

www.jianshu.com/p/ac96420fc…

Service插件化總結(jié)

初始化時通過ActivityManagerProxy Hook住了IActivityManager。

服務啟動時通過ActivityManagerProxy攔截,判斷是否為遠程服務,如果為遠程服務,啟動RemoteService,如果為同進程服務則啟動LocalService。

如果為LocalService,則通過DexClassLoader加載目標Service,然后反射調(diào)用attach方法綁定Context,然后執(zhí)行Service的onCreate、onStartCommand方法

如果為RemoteService,則先加載插件的遠程Service,后續(xù)跟LocalService一致。

3.模塊化實現(xiàn)(好處,原因)


www.cnblogs.com/Jackie-zhan…

1、模塊間解耦,復用。

(原因:對業(yè)務進行模塊化拆分后,為了使各業(yè)務模塊間解耦,因此各個都是獨立的模塊,它們之間是沒有依賴關(guān)系。

每個模塊負責的功能不同,業(yè)務邏輯不同,模塊間業(yè)務解耦。模塊功能比較單一,可在多個項目中使用。)

2、可單獨編譯某個模塊,提升開發(fā)效率。

(原因:每個模塊實際上也是一個完整的項目,可以進行單獨編譯,調(diào)試)

3、可以多團隊并行開發(fā),測試。

原因:每個團隊負責不同的模塊,提升開發(fā),測試效率。

組件化與模塊化

組件化是指以重用化為目的,將一個系統(tǒng)拆分為一個個單獨的組件

避免重復造輪子,節(jié)省開發(fā)維護成本;

降低項目復雜性,提升開發(fā)效率;

多個團隊公用同一個組件,在一定層度上確保了技術(shù)方案的統(tǒng)一性。

模塊化業(yè)務分層:由下到上

基礎(chǔ)組件層:

底層使用的庫和封裝的一些工具庫(libs),比如okhttp,rxjava,rxandroid,glide等

業(yè)務組件層:

與業(yè)務相關(guān),封裝第三方sdk,比如封裝后的支付,即時通行等

業(yè)務模塊層:

按照業(yè)務劃分模塊,比如說IM模塊,資訊模塊等

Library Module開發(fā)問題

在把代碼抽取到各個單獨的Library Module中,會遇到各種問題。

最常見的就是R文件問題,Android開發(fā)中,各個資源文件都是放在res目錄中,在編譯過程中,會生成R.java文件。

R文件中包含有各個資源文件對應的id,這個id是靜態(tài)常量,但是在Library Module中,這個id不是靜態(tài)常量,那么在開發(fā)時候就要避開這樣的問題。

舉個常見的例子,同一個方法處理多個view的點擊事件,有時候會使用switch(view.getId())這樣的方式,

然后用case R.id.btnLogin這樣進行判斷,這時候就會出現(xiàn)問題,因為id不是經(jīng)常常量,那么這種方式就用不了。

4.熱修復、插件化


www.jianshu.com/p/704cac3eb…

宿主: 就是當前運行的APP

插件: 相對于插件化技術(shù)來說,就是要加載運行的apk類文件

補丁: 相對于熱修復技術(shù)來說,就是要加載運行的.patch,.dex,*.apk等一系列包含dex修復內(nèi)容的文件。

QQ 空間超級補丁方案

Tinker

HotFix

當然就熱修復的實現(xiàn),各個大廠還有各自的實現(xiàn),比如餓了嗎的Amigo,美團的Robust,實現(xiàn)及優(yōu)缺點各有差異,但總的來說就是兩大類

ClassLoader 加載方案

Native層替換方案

或者是參考Android Studio Instant Run 的思路實現(xiàn)代碼整體的增量更新。但這樣勢必會帶來性能的影響。

Sophix

www.jianshu.com/p/4d30ce3e5…

底層替換方案

原理:在已經(jīng)加載的類中直接替換掉原有方法,是在原有類的結(jié)構(gòu)基礎(chǔ)上進行修改的。在hook方法入口ArtMethod時,通過構(gòu)造一個新的ArtMethod實現(xiàn)替換方法入口的跳轉(zhuǎn)。

應用:能即時生效,Andfix采用此方案。

缺點:底層替換穩(wěn)定性不好,適用范圍存在限制,通過改造代碼繞過限制既不優(yōu)雅也不方便,并且還沒提供資源及so的修復。

類加載方案

原理:讓app重新啟動后讓ClassLoader去加載新的類。如果不重啟,原來的類還在虛擬機中無法重復加載。

優(yōu)點:修復范圍廣,限制少。

應用:騰訊系包括QQ空間,手QFix,Tinker采用此方案。

QQ空間會侵入打包流程。

QFix需要獲取底層虛擬機的函數(shù),不穩(wěn)定。

Tinker是完整的全量dex加載。

Tinker與Sophix方案不同之處

Tinker采用dex merge生成全量DEX方案。反編譯為smali,然后新apk跟基線apk進行差異對比,最后得到補丁包。

Dalvik下Sophix和Tinker相同,在Art下,Sophix不需要做dex merge,因為Art下本質(zhì)上虛擬機已經(jīng)支持多dex的加載,要做的僅僅是把補丁dex作為主dex(classes.dex)加載而已:

將補丁dex命名為classes.dex,原apk中的dex依次命名為classes(2, 3, 4…).dex就好了,然后一起打包為一個壓縮文件。然后DexFile.loadDex得到DexFile對象,最后把該DexFile對象整個替換舊的dexElements數(shù)組就好了。

資源修復方案

基本參考InstantRun的實現(xiàn):構(gòu)造一個包含所有新資源的新的AssetManager。并在所有之前引用到原來的AssetManager通過反射替換掉。

Sophix不修改AssetManager的引用,構(gòu)造的補丁包中只包含有新增或有修改變動的資源,在原AssetManager中addAssetPath這個包就可以了。資源包不需要在運行時合成完整包。

so庫修復方案

本質(zhì)是對native方法的修復和替換。類似類修復反射注入方式,將補丁so庫的路徑插入到nativeLibraryDirectories數(shù)據(jù)最前面。

Method Hook

www.jianshu.com/p/7dcb32f8a… pqpo.me/2017/07/07/…

5.項目組件化的理解


juejin.im/post/5b5f17…

總結(jié)

組件化相較于單一工程,在組件模式下可以提高編譯速度,方便單元測試,提高開發(fā)效率。

開發(fā)人員分工更加明確,基本上做到互不干擾。

業(yè)務組件的架構(gòu)也可以自由選擇,不影響同伴之間的協(xié)作。

降低維護成本,代碼結(jié)構(gòu)更加清晰。

6.描述清點擊 Android Studio 的 build 按鈕后發(fā)生了什么


blog.csdn.net/u011026779/… blog.csdn.net/github_3713…

apply plugin : ‘com.android.application’

apply plugin : ‘com.android.library’

編譯五階段

1.準備依賴包 Preparation of dependecies

2.合并資源并處理清單 Merging resources and proccesssing Manifest

3.編譯 Compiling

4.后期處理 Postprocessing

5.包裝和出版 Packaging and publishing

簡單構(gòu)建流程:

1. Android編譯器(5.0之前是Dalvik,之后是ART)將項目的源代碼(包括一些第三方庫、jar包和aar包)轉(zhuǎn)換成DEX文件,將其他資源轉(zhuǎn)換成已編譯資源。

2. APK打包器將DEX文件和已編譯資源在使用秘鑰簽署后打包。

3. 在生成最終 APK 之前,打包器會使用zipalign 等工具對應用進行優(yōu)化,減少其在設備上運行時的內(nèi)存占用。

構(gòu)建流程結(jié)束后獲得測試或發(fā)布用的apk。

復制代碼

圖中的矩形表示用到或者生成的文件,橢圓表示工具。

1. 通過aapt打包res資源文件,生成R.java、resources.arsc和res文件

2. 處理.aidl文件,生成對應的Java接口文件

3. 通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件

4. 通過dex命令,將.class文件和第三方庫中的.class文件處理生成classes.dex

5. 通過apkbuilder工具,將aapt生成的resources.arsc和res文件、assets文件和classes.dex一起打包生成apk

6. 通過Jarsigner工具,對上面的apk進行debug或release簽名

7. 通過zipalign工具,將簽名后的apk進行對齊處理。

這樣就得到了一個可以安裝運行的Android程序。

復制代碼

7.徹底搞懂Gradle、Gradle Wrapper與Android Plugin for Gradle的區(qū)別和聯(lián)系


zhuanlan.zhihu.com/p/32714369 blog.csdn.net/LVXIANGAN/a…

Offline work時可能出現(xiàn)"No cached version of com.android.tools.build:gradle:xxx available for offline mode"問題

Gradle: gradle-wrapper.properties中的distributionUrl=https/😕/services.gradle.org/distributions/gradle-2.10-all.zip

Gradle插件:build.gradle中依賴的classpath ‘com.android.tools.build:gradle:2.1.2’

Gradle:

一個構(gòu)建系統(tǒng),構(gòu)建項目的工具,用來編譯Android app,能夠簡化你的編譯、打包、測試過程。

Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語言來聲明項目設置,而不是傳統(tǒng)的XML。當前其支持的語言限于Java、Groovy和Scala

Gradle插件:

我們在AS中用到的Gradle被叫做Android Plugin for Gradle,它本質(zhì)就是一個AS的插件,它一邊調(diào)用 Gradle本身的代碼和批處理工具來構(gòu)建項目,一邊調(diào)用Android SDK的編譯、打包功能。

Gradle插件跟 Android SDK BuildTool有關(guān)聯(lián),因為它還承接著AS里的編譯相關(guān)的功能,在項目的 local.properties 文件里寫明 Android SDK 路徑、在build.gradle 里寫明 buildToolsVersion 的原因。

| 插件版本 | Gradle 版本 |

| — | — |

| 1.0.0 - 1.1.3 | 2.2.1 - 2.3 |

| 1.2.0 - 1.3.1 | 2.2.1 - 2.9 |

| 1.5.0 | 2.2.1 - 2.13 |

| 2.0.0 - 2.1.2 | 2.10 - 2.13 |

| 2.1.3 - 2.2.3 | 2.14.1+ |

| 2.3.0+ | 3.3+ |

| 3.0.0+ | 4.1+ |
| 3.1.0+ | 4.4+ |
| 3.2.0 - 3.2.1 | 4.6+ |

總結(jié)

以上是生活随笔為你收集整理的2020 Android 大厂面试-插件化、模块化、组件化,android开发环境的搭建视频的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。