Android進階面試題

1. Android系統(tǒng)啟動流程是什么?

==Android系統(tǒng)核心流程==:

  • ==啟動電源以及系統(tǒng)啟動==:當(dāng)電源按下時引導(dǎo)芯片從預(yù)定義的地方(固化在ROM)開始執(zhí)行,加載引導(dǎo)程序BootLoader到RAM,然后執(zhí)行。
  • ==引導(dǎo)程序BootLoader==:BootLoader是在Android系統(tǒng)開始運行前的一個小程序,主要用于把系統(tǒng)OS拉起來并運行。
  • ==Linux內(nèi)核啟動==:當(dāng)內(nèi)核啟動時,設(shè)置緩存、被保護存儲器、計劃列表、加載驅(qū)動。當(dāng)其完成系統(tǒng)設(shè)置時,會先在系統(tǒng)文件中尋找init.rc文件,并啟動init進程
  • ==init進程啟動==:初始化和啟動屬性服務(wù),并且啟動Zygote進程
  • ==Zygote進程啟動==:創(chuàng)建JVM并為其注冊JNI方法,創(chuàng)建服務(wù)器端Socket,啟動SystemServer進程
  • ==SystemServer進程啟動==:啟動Binder線程池和SystemServiceManager,并且啟動各種系統(tǒng)服務(wù)
  • ==Launcher啟動==:被SystemServer進程啟動的AMS會啟動Launcher,Launcher啟動后會將已安裝應(yīng)用的快捷圖標(biāo)顯示到系統(tǒng)桌面上。

進程啟動過程:init進程 -> Zygote進程 –> SystemServer進程 –> 各種系統(tǒng)服務(wù) –> 應(yīng)用進程。

2. 啟動一個程序,可以主界面點擊圖標(biāo)進入,也可以從一個程序中跳轉(zhuǎn)過去,二者有什么區(qū)別?

點擊圖標(biāo)是因為啟動程序(主界面也是一個app),發(fā)現(xiàn)了在這個程序中存在一個設(shè)置為入口的activity, 所以這個launcher會把icon提出來,放在主界面上。當(dāng)用戶點擊icon的時候,發(fā)出一個Intent:

Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);
mActivity.startActivity(intent); 

從另一個程序跳過去,系統(tǒng)會根據(jù)第三方程序向系統(tǒng)注冊的功能,為你的Intent選擇可以打開的程序或者頁面。

所以唯一的一點不同的是從icon的點擊啟動的intent的action是相對單一的,從程序中跳轉(zhuǎn)或者啟動可能樣式更多一些。本質(zhì)是相同的。

3. AMS家族重要術(shù)語解釋

  • ActivityManagerServices,簡稱AMS,服務(wù)端對象,負責(zé)系統(tǒng)中所有Activity的生命周期。

  • ==ActivityThread==,App的真正入口。當(dāng)開啟App之后,調(diào)用main()開始運行,開啟消息循環(huán)隊列,這就是傳說的UI線程或者叫主線程。與ActivityManagerService一起完成Activity的管理工作。

  • ApplicationThread,用來實現(xiàn)ActivityManagerServie與ActivityThread之間的交互。在ActivityManagerSevice需要管理相關(guān)Application中的Activity的生命周期時,通過ApplicationThread的代理對象與ActivityThread通信。

  • ApplicationThreadProxy,是ApplicationThread在服務(wù)器端的代理,負責(zé)和客戶端的ApplicationThread通信。AMS就是通過該代理與ActivityThread進行通信的。

  • Instrumentation,每一個應(yīng)用程序只有一個Instrumetation對象,每個Activity內(nèi)都有一個對該對象的引用,Instrumentation可以理解為應(yīng)用進程的管家,ActivityThread要創(chuàng)建或暫停某個Activity時,都需要通過Instrumentation來進行具體的操作。

  • ActivityStackActivity在AMS的棧管理,用來記錄經(jīng)啟動的Activity的先后關(guān)系,狀態(tài)信息等。通過ActivtyStack決定是否需要啟動新的進程。

  • ActivityRecord,ActivityStack的管理對象,每個Acivity在AMS對應(yīng)一個ActivityRecord,來記錄Activity狀態(tài)以及其他的管理信息。其實就是服務(wù)器端的Activity對象的映像。

  • TaskRecord,AMS抽象出來的一個“任務(wù)”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord。AMS用TaskRecord確保Activity啟動和退出的順序。如果你清楚Activity的4種launchMode,那么對這概念應(yīng)該不陌生。

4. ==App啟動流程==

點擊應(yīng)用圖標(biāo)后會去啟動應(yīng)用的Launcher Activity,如果Launcer Activity所在的進程沒有創(chuàng)建,還會創(chuàng)建新進程,整體的流程就是一個Activity的啟動流程。

image.png

整個流程涉及的主要角色有:

  • Instrumentation: 監(jiān)控應(yīng)用與系統(tǒng)相關(guān)的交互行為。
  • AMS:組件管理調(diào)度中心,什么都不干,但是什么都管。
  • ActivityStarter:Activity啟動的控制器,處理Intent與Flag對Activity啟動的影響,具體說來有:
    1、尋找符合啟動條件的Activity,如果有多個,讓用戶選擇;
    2、校驗啟動參數(shù)的合法性;
    3、 返回int參數(shù),代表Activity是否啟動成功。
  • ActivityStackSupervisior:這個類的作用從它的名字就可以看出來,它用來管理任務(wù)棧。
  • ActivityStack:用來管理任務(wù)棧里的Activity。
  • ActivityThread:最終干活的人,Activity、Service、BroadcastReceiver的啟動、切換、調(diào)度等各種操作都在這個類里完成。

注:這里單獨提一下ActivityStackSupervisior,這是高版本才有的類,它用來管理多個ActivityStack,早期的版本只有一個ActivityStack對應(yīng)著手機屏幕,后來高版本支持多屏以后,就有了多個ActivityStack,于是就引入了ActivityStackSupervisior用來管理多個ActivityStack。

==整個流程主要涉及四個進程==:

  • ==調(diào)用者進程==,如果是在桌面啟動應(yīng)用就是Launcher應(yīng)用進程。
  • ActivityManagerService等所在的==System Server進程==,該進程主要運行著系統(tǒng)服務(wù)組件。
  • ==Zygote進程==,該進程主要用來fork新進程。
  • ==新啟動的應(yīng)用進程==,該進程就是用來承載應(yīng)用運行的進程了,它也是應(yīng)用的主線程(新創(chuàng)建的進程就是主線程),處理組件生命周期、界面繪制等相關(guān)事情。

有了以上的理解,==整個流程可以概括如下==:

  • 1、點擊桌面應(yīng)用圖標(biāo),==Launcher進程將啟動Activity(MainActivity)的請求以Binder的方式發(fā)送給了AMS==。
  • 2、==AMS接收到啟動請求后,交付ActivityStarter處理Intent和Flag等信息==,然后再交給ActivityStackSupervisior/ActivityStack 處理Activity進棧相關(guān)流程。==同時以Socket方式請求Zygote進程fork新進程==。
  • 3、==Zygote接收到新進程創(chuàng)建請求后fork出新進程==。
  • 4、==在新進程里創(chuàng)建ActivityThread對象==,新創(chuàng)建的ActivityThread就是應(yīng)用的主線程,==在主線程里開啟Looper消息循環(huán),開始處理創(chuàng)建Activity==。
  • 5、==ActivityThread利用ClassLoader去加載Activity、創(chuàng)建Activity實例,并回調(diào)Activity的onCreate()方法==,這樣便完成了Activity的啟動。
image.png

5. ==理解Window和WindowManager==

  • 1.Window用于顯示View和接收各種事件,Window有三種型:應(yīng)用Window(每個Activity對應(yīng)一個Window)、子Widow(不能單獨存在,附屬于特定Window)、系統(tǒng)window(toast和狀態(tài)欄)

  • 2.Window分層級,應(yīng)用Window在1-99、子Window在1000-1999、系統(tǒng)Window在2000-2999. WindowManager提供了增改View的三個功能。

  • 3.Window是個抽象概念:每一個Window對應(yīng)著一個ViewRootImpl,Window通過ViewRootImpl來和View建立聯(lián)系,View是Window存在的實體,只能通過WindowManager來訪問Window。

  • 4.WindowManager的實現(xiàn)是WindowManagerImpl,其再委托WindowManagerGlobal來對Window進行操作,其中有四種List分別儲存對應(yīng)的View、ViewRootImpl、WindowManger.LayoutParams和正在被刪除的View。

  • 5.Window的實體是存在于遠端的WindowMangerService,所以增刪改Window在本端是修改上面的幾個List然后通過ViewRootImpl重繪View,通過WindowSession(每Window個對應(yīng)一個)在遠端修改Window。

  • 6.Activity創(chuàng)建Window:Activity會在attach()中創(chuàng)建Window并設(shè)置其回調(diào)(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy類創(chuàng)建PhoneWindow實現(xiàn)的。然后通過Activity#setContentView()調(diào)用PhoneWindow的setContentView。

6. 應(yīng)用程序安裝到手機上時發(fā)生了什么?

image.png
  • 復(fù)制APK到/data/app目錄下,解壓并掃描安裝包
  • 資源管理器解析APK里的資源文件。
  • 解析AndroidManifest.xml文件,并在/data/data/目錄下創(chuàng)建對應(yīng)的應(yīng)用數(shù)據(jù)目錄。
  • 然后對dex文件進行優(yōu)化,并保存在dalvik-cache目錄下。
  • ,將AndroidManifest文件解析出的四大組件信息注冊到PackageManagerService中。
  • 安裝完成后,發(fā)送廣播。

7. Android的打包流程?(即清點擊 Android Studio 的 build 按鈕后發(fā)生了什么?)apk里有哪些東西?簽名算法的原理?

apk打包流程

Android的包文件APK分為兩個部分:代碼和資源,所以==打包方面也分為資源打包和代碼打包兩個方面==,下面就來分析資源和代碼的編譯打包原理。

image.png
  • 通過AAPT工具進行資源文件(包括AndroidManifest.xml、布局文件、各種xml資源等)的打包,生成R.java文件
  • 通過AIDL工具處理AIDL文件,生成相應(yīng)的Java文件。
  • 通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。
  • 通過dex命令,將.class文件和第三方庫中的.class文件處理生成classes.dex,該過程主要完成Java字節(jié)碼轉(zhuǎn)換成Dalvik字節(jié)碼,壓縮常量池以及清除冗余信息等工作。
  • 通過ApkBuilder工具將資源文件、DEX文件打包生成APK文件
  • 通過Jarsigner工具,利用KeyStore對生成的APK文件進行簽名
  • 如果是正式版的APK,還會利用ZipAlign工具進行對齊處理,對齊的過程就是將APK文件中所有的資源文件距離文件的起始距位置都偏移4字節(jié)的整數(shù)倍,這樣通過內(nèi)存映射訪問APK文件的速度會更快,并且會減少其在設(shè)備上運行時的內(nèi)存占用。

==apk組成==

  • dex:最終生成的Dalvik字節(jié)碼。

  • res:存放資源文件的目錄。

  • asserts:額外建立的資源文件夾。

  • lib:如果存在的話,存放的是ndk編出來的so庫。

  • META-INF:存放簽名信息

    MANIFEST.MF(清單文件):其中每一個資源文件都有一個SHA-256-Digest簽名,MANIFEST.MF文件的SHA256(SHA1)并base64編碼的結(jié)果即為CERT.SF中的SHA256-Digest-Manifest值。

    CERT.SF(待簽名文件):除了開頭處定義的SHA256(SHA1)-Digest-Manifest值,后面幾項的值是對MANIFEST.MF文件中的每項再次SHA256并base64編碼后的值。

    CERT.RSA(簽名結(jié)果文件):其中包含了公鑰、加密算法等信息。首先對前一步生成的MANIFEST.MF使用了SHA256(SHA1)-RSA算法,用開發(fā)者私鑰簽名,然后在安裝時使用公鑰解密。最后,將其與未加密的摘要信息(MANIFEST.MF文件)進行對比,如果相符,則表明內(nèi)容沒有被修改

  • androidManifest.xml:程序的全局清單配置文件。

  • resources.arsc:編譯后的二進制資源文件。

==為什么要簽名==

  • 確保Apk來源的真實性。
  • 確保Apk沒有被第三方篡改。

什么是簽名

簽名是在Apk中寫入一個“指紋”。指紋寫入以后,Apk中有任何修改,都會導(dǎo)致這個指紋無效,Android系統(tǒng)在安裝Apk進行簽名校驗時就會不通過,從而保證了安全性。

數(shù)字摘要

對一個任意長度的數(shù)據(jù),通過一個Hash算法計算后,都可以得到一個固定長度的二進制數(shù)據(jù),這個數(shù)據(jù)就稱為“摘要”。

補充:

  • 散列算法的基礎(chǔ)原理:將數(shù)據(jù)(如一段文字)運算變?yōu)榱硪还潭ㄩL度值。
  • SHA-1:在密碼學(xué)中,SHA-1(安全散列算法1)是一種加密散列函數(shù),它接受輸入并產(chǎn)生一個160 位(20 字節(jié))散列值,稱為消息摘要 。
  • MD5:MD5消息摘要算法(英語:MD5 Message-Digest Algorithm),一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個128位(16字節(jié))的散列值(hash value),用于確保信息傳輸完整一致。
  • SHA-2:名稱來自于安全散列算法2(英語:Secure Hash Algorithm 2)的縮寫,一種密碼散列函數(shù)算法標(biāo)準(zhǔn),其下又可再分為六個不同的算法標(biāo)準(zhǔn),包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。

特征:

  • 唯一性
  • 固定長度:比較常用的Hash算法有MD5和SHA1,MD5的長度是128拉,SHA1的長度是160位。
  • 不可逆性
簽名和校驗的主要過程

簽名就是在摘要的基礎(chǔ)上再進行一次加密,對摘要加密后的數(shù)據(jù)就可以當(dāng)作數(shù)字簽名。

簽名過程

  • 1、計算摘要:通過Hash算法提取出原始數(shù)據(jù)的摘要。
  • 2、計算簽名:再通過基于密鑰(私鑰)的非對稱加密算法對提取出的摘要進行加密,加密后的數(shù)據(jù)就是簽名信息。
  • 3、寫入簽名:將簽名信息寫入原始數(shù)據(jù)的簽名區(qū)塊內(nèi)。

校驗過程

  • 1、首先用同樣的Hash算法從接收到的數(shù)據(jù)中提取出摘要。
  • 2、解密簽名:使用發(fā)送方的公鑰對數(shù)字簽名進行解密,解密出原始摘要。
  • 3、比較摘要:如果解密后的數(shù)據(jù)和提取的摘要一致,則校驗通過;如果數(shù)據(jù)被第三方篡改過,解密后的數(shù)據(jù)和摘要將會不一致,則校驗不通過。

數(shù)字證書

如何保證公鑰的可靠性呢?答案是數(shù)字證書,數(shù)字證書是身份認證機構(gòu)(Certificate Authority)頒發(fā)的,包含了以下信息:

  • 證書頒發(fā)機構(gòu)
  • 證書頒發(fā)機構(gòu)簽名
  • 證書綁定的服務(wù)器域名
  • 證書版本、有效期
  • 簽名使用的加密算法(非對稱算法,如RSA)
  • 公鑰等

接收方收到消息后,先向CA驗證證書的合法性,再進行簽名校驗。

注意:Apk的證書通常是自簽名的,也就是由開發(fā)者自己制作,沒有向CA機構(gòu)申請。Android在安裝Apk時并沒有校驗證書本身的合法性,只是從證書中提取公鑰和加密算法,這也正是對第三方Apk重新簽名后,還能夠繼續(xù)在沒有安裝這個Apk的系統(tǒng)中繼續(xù)安裝的原因。

keystore和證書格式

keystore文件中包含了私鑰、公鑰和數(shù)字證書。根據(jù)編碼不同,keystore文件分為很多種,Android使用的是Java標(biāo)準(zhǔn)keystore格式JKS(Java Key Storage),所以通過Android Studio導(dǎo)出的keystore文件是以.jks結(jié)尾的。

keystore使用的證書標(biāo)準(zhǔn)是X.509,X.509標(biāo)準(zhǔn)也有多種編碼格式,常用的有兩種:pem(Privacy Enhanced Mail)和der(Distinguished Encoding Rules)。jks使用的是der格式,Android也支持直接使用pem格式的證書進行簽名。

兩種證書編碼格式的區(qū)別:

  • DER(Distinguished Encoding Rules)
    二進制格式,所有類型的證書和私鑰都可以存儲為der格式。
  • PEM(Privacy Enhanced Mail)
    base64編碼,內(nèi)容以-----BEGIN xxx----- 開頭,以-----END xxx----- 結(jié)尾。

jarsigner和apksigner的區(qū)別

Android提供了兩種對Apk的簽名方式,一種是基于JAR的簽名方式,另一種是基于Apk的簽名方式,它們的主要區(qū)別在于使用的簽名文件不一樣:jarsigner使用keystore文件進行簽名;apksigner除了支持使用keystore文件進行簽名外,還支持直接指定pem證書文件和私鑰進行簽名。

在簽名時,除了要指定keystore文件和密碼外,也要指定alias和key的密碼,這是為什么呢?

keystore是一個密鑰庫,也就是說它可以存儲多對密鑰和證書,keystore的密碼是用于保護keystore本身的,一對密鑰和證書是通過alias來區(qū)分的。所以jarsigner是支持使用多個證書對Apk進行簽名的,apksigner也同樣支持。

Android Apk V1 簽名原理

  • 1、解析出 CERT.RSA 文件中的證書、公鑰,解密 CERT.RSA 中的加密數(shù)據(jù)。
  • 2、解密結(jié)果和 CERT.SF 的指紋進行對比,保證 CERT.SF 沒有被篡改。
  • 3、而 CERT.SF 中的內(nèi)容再和 MANIFEST.MF 指紋對比,保證 MANIFEST.MF 文件沒有被篡改。
  • 4、MANIFEST.MF 中的內(nèi)容和 APK 所有文件指紋逐一對比,保證 APK 沒有被篡改。

==V1簽名和V2簽名==

  • V1簽名靠META_INFO文件夾下的簽名文件
  • V2驗證壓縮文件的所有字節(jié),因此,在簽名后無法再更改
  • 只勾選v1簽名并不會影響什么,但是在7.0上不會使用更安全的驗證方式
  • 只勾選V2簽名7.0以下會直接安裝完顯示未安裝,7.0以上則使用了V2的方式驗證
  • V1和V2可以同是勾選

==v3簽名key和v2還有v1有什么區(qū)別==?

  • 在v1版本的簽名中,簽名以文件的形式存在于apk包中,這個版本的apk包就是一個標(biāo)準(zhǔn)的zip包,V2和V1的差別是V2是對整個zip包進行簽名,而且在zip包中增加了一個apk signature block,里面保存簽名信息。
  • v2版本簽名塊(APK Signing Block)本身又主要分成三部分:
  1. SignerData(簽名者數(shù)據(jù)):主要包括簽名者的證書,整個APK完整性校驗hash,以及一些必要信息
  2. Signature(簽名):開發(fā)者對SignerData部分數(shù)據(jù)的簽名數(shù)據(jù)
  3. PublicKey(公鑰):用于驗簽的公鑰數(shù)據(jù)
  • v3版本簽名塊也分成同樣的三部分,與v2不同的是在SignerData部分,v3新增了attr塊,其中是由更小的level塊組成。每個level塊中可以存儲一個證書信息。前一個level塊證書驗證下一個level證書,以此類推。最后一個level塊的證書,要符合SignerData中本身的證書,即用來簽名整個APK的公鑰所屬于的證書。

8. 說下Android虛擬機和Java虛擬機的區(qū)別?

JVM和Dalvik虛擬機(DVM)的區(qū)別:

  • JVM編譯產(chǎn)物:java --javac-> .class --jar-> .jar
    架構(gòu):堆和棧的架構(gòu)
  • DVM編譯產(chǎn)物:java --javac-> .class -> dx.bat -> .dex
    架構(gòu):寄存器

==Android2個虛擬機的區(qū)別==(一個5.0之前,一個5.0之后)?

Dalvik:Dalvik是Google公司自己設(shè)計用于Android平臺的Java虛擬機,它可以支持已轉(zhuǎn)換為.dex(即Dalvik Executable)格式的Java應(yīng)用程序的運行,.dex格式是專為Dalvik應(yīng)用設(shè)計的一種壓縮格式,適合內(nèi)存和處理器速度有限的系統(tǒng)。Dalvik經(jīng)過優(yōu)化,允許在有限的內(nèi)存中同時運行多個虛擬機的實例,并且每一個Dalvik應(yīng)用作為獨立的Linux進程執(zhí)行。獨立的進程可以防止在虛擬機崩潰的時候所有程序都被關(guān)閉。

ART:ART代表Android Runtime,其處理應(yīng)用程序執(zhí)行的方式完全不同于Dalvik,Dalvik是依靠一個Just-In-Time(JIT)編譯器去解釋字節(jié)碼。開發(fā)者編譯后的應(yīng)用代碼需要通過一個解釋器在用戶的設(shè)備上運行,這一機制并不高效,但讓應(yīng)用能更容易在不同硬件和架構(gòu)上運行。ART則完全改變了這套做法,在應(yīng)用安裝的時候就預(yù)編譯字節(jié)碼為機器語言,這一機制叫Ahead-Of-Time(AOT)編譯。在移除解釋代碼這一過程后,應(yīng)用程序執(zhí)行將更有效率,啟動更快。

ART的優(yōu)點:

  • 系統(tǒng)性能的顯著提升。
  • 應(yīng)用啟動更快、運行更快、體驗更流暢、觸感反饋更及時。
  • 更長的電池續(xù)航能力。
  • 支持更低的硬件。

ART缺點:

  • 更大的存儲空間占用,可能會增加10%-20%。
  • 更長的應(yīng)用安裝時間。

9. ==為什么系統(tǒng)不建議在子線程訪問UI==?

  • Android的UI控件不是線程安全的,如果在多線程中并發(fā)訪問可能會導(dǎo)致UI控件處于不可預(yù)期的狀態(tài)。

這時你可能會問為何系統(tǒng)不對UI控件的訪問加上鎖機制呢?

  • 加鎖機制會讓UI訪問邏輯變的復(fù)雜
  • 加鎖機制會降低UI的訪問效率,因為加鎖會阻塞某些線程的執(zhí)行。

10. ==怎么保證應(yīng)用啟動不卡頓? 黑白屏怎么處理?==

應(yīng)用啟動速度,取決于你在application里面時候做了什么事情,比如你集成了很多sdk,并且sdk的init操作都需要在主線程里實現(xiàn)所以會有卡頓的感覺。在非必要的情況下可以把加載延后或則開啟子線程處理
另外,影響界面卡頓的兩大因素,分別是界面繪制和數(shù)據(jù)處理。

  • ==布局優(yōu)化==(使用include,merge標(biāo)簽,復(fù)雜布局推薦使用ConstraintLayout等)
  • ==onCreate() 中不執(zhí)行耗時操作 把頁面顯示的 View 細分一下,放在 AsyncTask 里逐步顯示,用 Handler 更好==。這樣用戶的看到的就是有層次有步驟的一個個的 View 的展示,不會是先看到一個黑屏,然后一下顯示所有 View。最好做成動畫,效果更自然。
  • 利用多線程的目的就是==盡可能的減少 onCreate() 和 onReume()的時間==,使得用戶能盡快看到頁面,操作頁面。
  • 減少主線程阻塞時間。
  • 提高 Adapter 和 AdapterView 的效率

黑白屏處理:

  • ==黑白屏產(chǎn)生原因==:當(dāng)我們在啟動一個應(yīng)用時,系統(tǒng)會去檢查是否已經(jīng)存在這樣一個進程,如果不存在,系統(tǒng)的服務(wù)會先檢查startActivity中的intent的信息,然后在去創(chuàng)建進程,最后啟動Acitivy,即冷啟動。而啟動出現(xiàn)白黑屏的問題,就是在這段時間內(nèi)產(chǎn)生的。系統(tǒng)在繪制頁面加載布局之前,首先會初始化窗口(Window),而在進行這一步操作時,系統(tǒng)會根據(jù)我們設(shè)置的Theme來指定它的Theme 主題顏色,我們在Style中的設(shè)置就決定了顯示的是白屏還是黑屏。
  1. windowIsTranslucent和windowNoTitle,將這兩個屬性都設(shè)置成true (會有明顯的卡頓體驗,不推薦)
  2. 如果啟動頁只是是一張圖片,那么為啟動頁專一設(shè)置一個新的主題,設(shè)置主題的android:windowBackground屬性為啟動頁背景圖即可
  3. 使用layer-list制作一張圖片launcher_layer.xml,將其設(shè)置為啟動頁專一主題的背景,并將其設(shè)置為啟動頁布局的背景。

11. 如何通過Gradle配置多渠道包?

  • 首先要了解設(shè)置多渠道的原因。在安裝包中添加不同的標(biāo)識,配合自動化埋點,應(yīng)用在請求網(wǎng)絡(luò)的時候攜帶渠道信息,方便后臺做運營統(tǒng)計,比如說統(tǒng)計我們的應(yīng)用在不同應(yīng)用市場的下載量等信息。

  • 這里以友盟統(tǒng)計為例

  1. 首先在manifest.xml文件中設(shè)置動態(tài)渠道變量:
image.png
  1. 接著在app目錄下的build.gradle中配置productFlavors,也就是配置打包的渠道:
image.png

最后在編輯器下方的Teminal輸出命令行

  1. 執(zhí)行./gradlew assembleRelease ,將會打出所有渠道的release包;
    執(zhí)行./gradlew assembleVIVO,將會打出VIVO渠道的release和debug版的包;
    執(zhí)行./gradlew assembleVIVORelease將生成VIVO的release包。

12. 對于應(yīng)用更新這塊是如何做的? (灰度,強制更新、分區(qū)域更新)

  • 內(nèi)部更新:
  1. 通過接口獲取線上版本號,versionCode
    比較線上的versionCode
  2. 和本地的versionCode,彈出更新窗口
  3. 下載APK文件(文件下載)
  4. 安裝APK
  • 灰度更新:
  • 找單一渠道投放特別版本。
  • 做升級平臺的改造,允許針對部分用戶推送升級通知甚至版本強制升級。
  • 開放單獨的下載入口。
  • 是兩個版本的代碼都打到app包里,然后在app端植入測試框架,用來控制顯示哪個版本。測試框架負責(zé)與服務(wù)器端api通信,由服務(wù)器端控制app上A/B版本的分布,可以實現(xiàn)指定的一組用戶看到A版本,其它用戶看到B版本。服務(wù)端會有相應(yīng)的報表來顯示A/B版本的數(shù)量和效果對比。最后可以由服務(wù)端的后臺來控制,全部用戶在線切換到A或者B版本~
  • 無論哪種方法都需要做好版本管理工作,分配特別的版本號以示區(qū)別。 當(dāng)然,既然是做灰度,數(shù)據(jù)監(jiān)控(常規(guī)數(shù)據(jù)、新特性數(shù)據(jù)、主要業(yè)務(wù)數(shù)據(jù))還是要做到位,該打的數(shù)據(jù)樁要打。 還有,灰度版最好有收回的能力,一般就是強制升級下一個正式版。
  • 強制更新:

一般的處理就是進入應(yīng)用就彈窗通知用戶有版本更新,彈窗可以沒有取消按鈕并不能取消。這樣用戶就只能選擇更新或者關(guān)閉應(yīng)用了,當(dāng)然也可以添加取消按鈕,但是如果用戶選擇取消則直接退出應(yīng)用。

  • 增量更新:

二進制差分工具bsdiff是相應(yīng)的補丁合成工具,根據(jù)兩個不同版本的二進制文件,生成補丁文件.patch文件。通過bspatch使舊的apk文件與不定文件合成新的apk。 注意通過apk文件的md5值進行區(qū)分版本。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容