AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

面試官:你對插件化有什么了解?

來源: 責編: 時間:2024-09-10 09:47:30 108觀看
導讀背景插件化的誕生是為了解決什么問題?我們不妨好好思考一下,作為客戶端開發,平時工作中是否為這樣的情況發愁:核心業務功能迭代的時候,千小心,萬小心,又是做AB,又是做灰度,最后線上還是出問題了,這個時候只能靠發版解決問題,奈何

背景

插件化的誕生是為了解決什么問題?Sbq28資訊網——每日最新資訊28at.com

我們不妨好好思考一下,作為客戶端開發,平時工作中是否為這樣的情況發愁:Sbq28資訊網——每日最新資訊28at.com

  • 核心業務功能迭代的時候,千小心,萬小心,又是做AB,又是做灰度,最后線上還是出問題了,這個時候只能靠發版解決問題,奈何客戶端的發版周期長,并且只有用戶升級以后才能解決問題
  • 有些業務上線以來,用的人不多,占用的包體積還不小,這些功能是否可以動態加載
  • 開發一個功能,必須提交到應用商店以后,用戶才能更新(涉及到監管)

所以說,插件化設計之初就是為了不安裝新Apk,從而完成應用的更新迭代。Sbq28資訊網——每日最新資訊28at.com

我之前所在的團隊也做了插件化,主要的原因還是包體積的訴求,原因有兩個:Sbq28資訊網——每日最新資訊28at.com

  • 廠商預裝的時候包體積的強制訴求:如果不做插件化,就需要每年預裝階段持續投入人力優化包體積,成本比較高
  • 對外投放的時候,小包有利于提高用戶的轉化

轉換率轉換率Sbq28資訊網——每日最新資訊28at.com

上圖是2018年谷歌IO披露的包體積與下載轉化率之間的關系,時至今日,即使我們的網絡狀況已經有了很好的提升,但是優化包體積仍然是我們的目標,比如說:Sbq28資訊網——每日最新資訊28at.com

  • 線下推廣的時候用戶的網絡是不穩定的
  • 對于線上廣告投放,用戶不可能一直在wifi下,小的包體積可以讓用戶更快的進入應用內,避免勸退用戶

所以我們可以看到,pdd這一方面做的很出色,僅有25m。Sbq28資訊網——每日最新資訊28at.com

一、插件化難點

講插件化之前,我們先科普一下其中的概念。Sbq28資訊網——每日最新資訊28at.com

對于一個完整功能的App,我們可以將其劃分成為很多模塊,每個模塊都可以將其劃分成為一個Apk。然后將基礎功能的Apk提交給應用市場上架,后續我們可以通過基礎的Apk,下載其他模塊的Apk,從而完成功能的擴展。Sbq28資訊網——每日最新資訊28at.com

基礎分包基礎分包Sbq28資訊網——每日最新資訊28at.com

在整個過程中,我們稱提交給應用市場的Apk為宿主,其他模塊的Apk稱之為插件。Sbq28資訊網——每日最新資訊28at.com

相信沒接觸過插件化的同學可能會有一些疑問,我們平時打包的時候不是都是一個完整的Apk,為什么可以加載一個單獨的Apk?好了,這就是插件化的第一個難點。Sbq28資訊網——每日最新資訊28at.com

二、加載插件Apk

作為一個Android開發,我們都知道Android里面的Davilk和Art虛擬機和Java虛擬機不是同一套,所以他們也有著不同的類加載結構。Sbq28資訊網——每日最新資訊28at.com

我們先回顧一下。Sbq28資訊網——每日最新資訊28at.com

1. Java類加載

Jvm中加載的文件是class文件,再由Jvm翻譯成特定平臺的機器碼。使用的類加載器如下:Sbq28資訊網——每日最新資訊28at.com

  • 啟動類加載器:由C++語言實現,負責加載Java中的核心類。
  • 擴展類加載器:負責加載Java擴展的核心類之外的類。
  • 應用程序類加載器:負責加載用戶類路徑上指定的類庫。

整個加載架構如下:Sbq28資訊網——每日最新資訊28at.com

Java類加載器結構Java類加載器結構Sbq28資訊網——每日最新資訊28at.com

雙親委派機制保證了收到類加載請求的時候,優先讓父類加載器去加載,父類加載器處理不了的時候,才會自己去加載,保證了類加載機制的穩定性。Sbq28資訊網——每日最新資訊28at.com

2. Android類加載

我們上面提過,由于CPU和功耗環境不一致,Android虛擬機和Jvm有著很大的不同,Android里面的虛擬機在4.4.4以后,就是ART虛擬機了。早期的時候,安裝的時候,會將dex文件直接編譯成.oat這樣的機器碼,不過這樣會有其他問題:Sbq28資訊網——每日最新資訊28at.com

  • 提高安裝和升級應用的時間

于是,在 Android 7.0 以后,第一次啟動的時候,使用 Jit,針對dex,邊解釋邊執行,然后在空閑的時候,將剩余的 dex 文件編譯成機器碼。Sbq28資訊網——每日最新資訊28at.com

所以,我們可以注意到,每次應用升級的一段時間內,我們的啟動時長會出現波動,過了幾天以后,又會達到穩定的狀態。因此,很多大廠,會針對這個過程優化,如:Sbq28資訊網——每日最新資訊28at.com

  • 如何更多的觸發 dex2aot 過程
  • 對啟動熱點代碼預先aot,比如谷歌的BaselineProfile方案,很多大廠也有自己的方案

我們再來看一下類加載機制,Android里面類加載的單位是dex,類加載器包括:Sbq28資訊網——每日最新資訊28at.com

  • BootClassLoader:用來解決Android系統啟動時的核心基礎類
  • PathClassLoader:Android中默認的類加載器,主要用來加載應用程序自身的類以及系統類庫之外的本地代碼
  • DexClassLoader:加載指定路徑下的Apk、Jar包的類
  • InMemoryDexClassLoader:Android 8.0 中可以用來加載內存中的Dex文件

整個結構是這樣的:Sbq28資訊網——每日最新資訊28at.com

Android類加載器Android類加載器Sbq28資訊網——每日最新資訊28at.com

如果是指定路徑下的Apk或者jar包,我們需要將 PathClassLoader 替換成 DexClassLoader。到這里,第一個問題的解決思路就很清晰了,我們可以通過 DexClassLoader 加載插件Apk。Sbq28資訊網——每日最新資訊28at.com

3. 方案實現

DexClassLoader的原理主要是通過DexPathList管理DexFile列表信息,從而加載到具體的類。Sbq28資訊網——每日最新資訊28at.com

DexClassLoaderDexClassLoaderSbq28資訊網——每日最新資訊28at.com


Sbq28資訊網——每日最新資訊28at.com

基于DexClassLoader,通常有兩種方案:Sbq28資訊網——每日最新資訊28at.com

  • 單個DexClassLoader方案
  • 多個DexClassLoader方案

單個DexClassLoader

單個DexClassLoader指的我們可能有多個插件Dex,多個插件Dex使用同一個DexClassLoader,如圖:Sbq28資訊網——每日最新資訊28at.com

單ClassLoader結構Sbq28資訊網——每日最新資訊28at.com

將所有的插件中的類都由統一的DexClassLoader加載。Sbq28資訊網——每日最新資訊28at.com

多個DexClassLoader

多個DexClassLoader指的是對于多個插件Dex,每一個Dex都會有自己的DexClassLoader,如圖:Sbq28資訊網——每日最新資訊28at.com

多ClassLoader結構多ClassLoader結構Sbq28資訊網——每日最新資訊28at.com

由各自DexClassLoader負責相關的插件的類加載。Sbq28資訊網——每日最新資訊28at.com

看一下各自的優缺點:Sbq28資訊網——每日最新資訊28at.com

分類Sbq28資訊網——每日最新資訊28at.com

優點Sbq28資訊網——每日最新資訊28at.com

缺點Sbq28資訊網——每日最新資訊28at.com

單DexClassLoaderSbq28資訊網——每日最新資訊28at.com

類之間不隔離,可以互相調用Sbq28資訊網——每日最新資訊28at.com

需要處理一些適配問題,比如不同插件加載了同一庫的不同版本,可能引發兼容性問題Sbq28資訊網——每日最新資訊28at.com

多DexClassLoaderSbq28資訊網——每日最新資訊28at.com

安全、穩定Sbq28資訊網——每日最新資訊28at.com

類之間隔離,需要處理互相調用的問題Sbq28資訊網——每日最新資訊28at.com

對于我們安卓系統來講,僅僅能夠加載插件中的類顯然是不夠的,還要能夠啟動插件中的的四大組件,并正確的執行四大組件的生命周期,為什么不能夠執行四大組件的生命周期呢?Sbq28資訊網——每日最新資訊28at.com

這是因為,只有在我們宿主包中Manifest文件中注冊的四大組件才能夠啟動,如果沒有注冊,就會拋出異常,提醒你在Manifest中注冊。這也是我們遇到的第二個問題。Sbq28資訊網——每日最新資訊28at.com

三、組件加載

Android 中四大組件包括Activity、Service、廣播和ContentProvider,我們主要介紹一下Activity。Sbq28資訊網——每日最新資訊28at.com

1. Activity解決方法

如果我們想讓對應的Activity啟動,一般有如下幾種方法:Sbq28資訊網——每日最新資訊28at.com

  1. 宿主包提前聲明組件
  2. 占位組件 + 手動調用組件
  3. 占位組件 + 欺騙系統

我們針對這幾種分別解釋一下。Sbq28資訊網——每日最新資訊28at.com

1.1 宿主包提前聲明組件

將所有的四大組件在宿主包中都提前聲明,這是最簡單粗暴的方式。Sbq28資訊網——每日最新資訊28at.com

但這種方式會丟失插件化的動態性,也就是說,如果想在插件包中,加入宿主包沒有注冊的Activity,這就會有問題。Sbq28資訊網——每日最新資訊28at.com

那這種方式的優點呢?解決包體積的問題的同時不用處理復雜的組件加載以及伴隨的生命周期的問題。Sbq28資訊網——每日最新資訊28at.com

1.2 占位組件 + 手動調用組件

那如果想要保存插件的動態化加載呢?也就是說我們想要在插件包中的 Manifest 文件中進行注冊。Sbq28資訊網——每日最新資訊28at.com

默認情況下,如果我們啟動一個沒有在插件 Manifest 中注冊的的 Activity,會發生 error,原因是啟動過程中的 Instrumentation 中的 checkStartActivityResult 方法:Sbq28資訊網——每日最新資訊28at.com

public class Instrumentation {    public static void checkStartActivityResult(int res, Object intent) {        if (!ActivityManager.isStartResultFatalError(res)) {            return;        }        switch (res) {            case ActivityManager.START_INTENT_NOT_RESOLVED:            case ActivityManager.START_CLASS_NOT_FOUND:                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)                    throw new ActivityNotFoundException(                            "Unable to find explicit activity class "                            + ((Intent)intent).getComponent().toShortString()                            + "; have you declared this activity in your AndroidManifest.xml?");                throw new ActivityNotFoundException(                        "No Activity found to handle " + intent);                ...        }    }}

所以我們傳入的Activity必須要在宿主包中注冊,這樣系統才能檢驗通過,那怎么才能實現動態化呢?Sbq28資訊網——每日最新資訊28at.com

答案是使用占位Activity,這其實就是使用的代理模式。每次需要啟動插件中的Activity的時候,先啟動一個占位Activity實例,然后在占位Activity實例里面持有目標Activity的實例對象,從而通過反射或者其他方法調用實例的生命周期。Sbq28資訊網——每日最新資訊28at.com

生命周期處理生命周期處理Sbq28資訊網——每日最新資訊28at.com

這種方法的問題主要如下:Sbq28資訊網——每日最新資訊28at.com

  1. 代碼的入侵性比較強,需要統一繼承PluginActvity。
  2. 對于Activity的啟動模式,處理比較繁瑣。
  3. 改造已有的模塊比較繁瑣。

1.3 欺騙系統

第三種方法我們稱之為欺騙系統,具體怎么個欺騙方法呢?Sbq28資訊網——每日最新資訊28at.com

先看一下具體Activity的啟動流程,默認大家對Activity的啟動流程比較了解了:Sbq28資訊網——每日最新資訊28at.com

Activity啟動流程Activity啟動流程Sbq28資訊網——每日最新資訊28at.com

我們在整個過程中,同樣也需要一個占位Activity。Sbq28資訊網——每日最新資訊28at.com

使用步驟如下:Sbq28資訊網——每日最新資訊28at.com

  1. 在途中的第一步,啟動PluginActivity跳轉的時候,通過Instrument處理的時候,會將PluginActivity的Intent改成占位Activity的Intent,并存入原始Activity的信息。
  2. 在圖片中的第十三步,等系統驗證完成回來創建占位Activity的實例對象,就替換成PluginActivity。

最終,系統以為自己調用的是占位Activity的對象,并且和實際上調用的是PluginActivity進行綁定。Sbq28資訊網——每日最新資訊28at.com

在最終使用之前,我們在插件中的Android資源文件并不能使用,比如說圖片、字符串、布局文件等,原因是插件的資源路徑并沒有被添加。Sbq28資訊網——每日最新資訊28at.com

四、資源加載

Apk安裝以后,我們都是通過 Resource 對象去訪問資源,簡單看一下 Resouce 的構造方法:Sbq28資訊網——每日最新資訊28at.com

@Deprecated  public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {      this(null);      mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());  }

可以看到,構造函數中有一個參數是 AssetManager,我們可以通過在 AssetManager 中,加入我們插件的資源地址,就可以訪問到插件中的資源。Sbq28資訊網——每日最新資訊28at.com

1 解決方法

現在可以訪問具體的資源了,和之前的類加載方式類似,也有兩種加載方式:Sbq28資訊網——每日最新資訊28at.com

  • 合并式:插件和宿主資源可以互相訪問,要處理資源沖突
  • 獨立式:無需處理資源沖突,宿主和插件的資源訪問比較難處理

首先,我們想一下為什么會有資源沖突問題?其實是因為宿主和插件包都是獨立編譯的,所以打包的時候生成的資源Id會存在相同的情況,這個時候,訪問的的時候就存在資源沖突。Sbq28資訊網——每日最新資訊28at.com

我們項目之前采用的 Qigsaw 方案,所以簡單介紹一下合并式的方案,資源id是8位16進制數表示:Sbq28資訊網——每日最新資訊28at.com

QigsawQigsawSbq28資訊網——每日最新資訊28at.com

如上圖:Sbq28資訊網——每日最新資訊28at.com

  • PP為Package Id,代表應用類型:如系統應用、第三方應用、dynamic feature等。
  • TT為資源類型:如drawabl、layout和string。
  • EEEE為Entry:代表資源順序

所以我們對不同的插件包,進行打包的時候,前面的PP字段,可以進行依次遞減,可以避免資源沖突的問題。常用的方案有:Sbq28資訊網——每日最新資訊28at.com

  1. 修改AAPT生成ResourceId,在編譯期間完成修改
  2. 修改resouce.arsc文件

Qigsaw使用的第一種方案。Sbq28資訊網——每日最新資訊28at.com

總結

本文是一篇入門插件化的文章,主要回答了插件化是什么,有什么難點,又是怎么解決的,其中沒有涉及到很多代碼,非常適合入門。Sbq28資訊網——每日最新資訊28at.com

Sbq28資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-112727-0.html面試官:你對插件化有什么了解?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 停止使用 `let` 或為什么它在 JavaScript/TypeScript 中是不必要的

下一篇: 聊一聊Spring事務失效的12種場景

標簽:
  • 熱門焦點
Top