本篇文章主要是對(duì)產(chǎn)品項(xiàng)目6.5.0版本的分包處理及總結(jié)墓卦。先附上在處理過程中查閱的一些博客及資料:
1枚粘、背景
由于6.5.0版本加入了大量的需求,導(dǎo)致項(xiàng)目方法數(shù)超過了65536個(gè)际长,項(xiàng)目無法正常編譯,在加入官方分包方法后解決了單個(gè)dex過大的問題兴泥,但又發(fā)現(xiàn)在Android3.0以下手機(jī)出現(xiàn)INSTALL_FAILED_DEXOPT安裝失敗工育。然后這時(shí)才意識(shí)到分包的影響很大,慌忙查閱資料試圖解決此問題搓彻,然后才發(fā)現(xiàn)這上面的一個(gè)個(gè)的坑如绸。
方法數(shù)超了的直觀體現(xiàn)是,編譯時(shí)報(bào)如下異常:
TROUBLE WRITING OUTPUT: TOO MANY METHOD REFERENCES: 70048; MAX IS 65536.
或者
UNEXPECTED TOP-LEVEL EXCEPTION: JAVA.LANG.ILLEGALARGUMENTEXCEPTION: METHOD ID NOT IN [0, 0XFFFF]: 65536
此時(shí)如果添加官方的分包方法旭贬,編譯問題得到解決怔接,但是正式打包安裝時(shí)會(huì)出現(xiàn)INSTALL_FAILED_DEXOPT問題導(dǎo)致無法安裝。
INSTALL_FAILED_DEXOPT問題的原因稀轨,從根本上分析扼脐,主要有2個(gè):
單個(gè)dex文件方法總數(shù)65536的限制
Dexopt的LinearAlloc限制
65536限制
這是由于Dex文件對(duì)于方法索引是用一個(gè)short類型的數(shù)據(jù)來存放的.而short的最大值是65535,因此當(dāng)項(xiàng)目足夠大包含方法數(shù)目足夠多超過了65535(包括引用的外部Lib里面的所有方法)
LinearAlloc限制
LinearAlloc 主要用來管理 Dalvik 中 class 加載時(shí)的內(nèi)存,就是讓 App 在執(zhí)行時(shí)減少系統(tǒng)內(nèi)存的占用奋刽。在 App 的安裝過程中瓦侮,系統(tǒng)會(huì)運(yùn)行一個(gè)名為 dexopt 的程序?yàn)樵搼?yīng)用在當(dāng)前機(jī)型中運(yùn)行做準(zhǔn)備。dexopt 使用 LinearAlloc 來存儲(chǔ)應(yīng)用的方法信息杨名。App 在執(zhí)行前會(huì)將 class 讀進(jìn) LinearAlloc 這個(gè) buffer 中脏榆,這個(gè) LinearAlloc 在 Android 2.3 之前是 4M 或 5M ,到 4.0 之后變?yōu)?8M 或 16M台谍。因?yàn)?5M 實(shí)在是太小了须喂,可能還沒有 65536 就已經(jīng)超過 5M 了吁断,什么意思呢,就是只有一個(gè)包的情況下也有可能出現(xiàn) INSTALL_FAILED_DEXOPT 坞生,原因就在于 LinearAlloc仔役。
2、解決65536及LinearAlloc限制
按照官方MultiDex方式配置實(shí)現(xiàn):
通過在defaultConfig節(jié)中設(shè)置multiDexEnabled標(biāo)簽為true是己,開啟multi-dex支持.
在項(xiàng)目的build.gradle文件的dependencies 節(jié)中添加分包設(shè)置:
代碼中加入支持Multidex的功能又兵,有三種方案實(shí)現(xiàn),此處只列一種卒废,重寫的Application中加入:
通過上述可解決方法數(shù)的問題沛厨,但是打包出的dex可能還是過大,無法安裝摔认。
通過如下方式逆皮,設(shè)置每個(gè)dex的最大方法數(shù)–set-max-idx-number=,可以解決LinearAlloc限制:
3参袱、存在的問題
雖然上述的方法可以解決問題电谣,但還是會(huì)留下很多的坑。
1抹蚀、啟動(dòng)時(shí)間變長(zhǎng)剿牺,容易黑屏或ANR
2、NoClassDefFoundError異常
3环壤、不知道哪些文件該放在主dex文件中
第一個(gè)是因?yàn)榉殖啥鄠€(gè)dex文件之后晒来,除主dex外的從dex(dex2、dex3)太大加載比較耗時(shí)導(dǎo)致郑现;第二個(gè)是由于啟動(dòng)引用的class打包時(shí)不在主dex文件中潜索,所有class文件找不到;為了解決class not found問題需要將所有啟動(dòng)時(shí)的類都要放到主dex文件中懂酱,這又是一個(gè)比較難解決的問題,因?yàn)槲募嗔恕?/p>
4誊抛、最后總結(jié)
鑒于發(fā)版在即列牺,暫時(shí)無法做到完美。
本次的解決方案:先按照官方分包方式拗窃,保證從dex比較小瞎领,主dex比較大,這樣避免啟動(dòng)ANR及Crash問題随夸,但缺點(diǎn)是3.0以下手機(jī)無法正常安裝(3.0以下LinearAlloc限制問題)九默。
后續(xù)解決方案:將項(xiàng)目中百川sdk和一元奪寶模塊移除作為插件apk加載,這樣減少主apk的方法數(shù)宾毒,從而達(dá)到解決方法數(shù)及3.0限制問題驼修。插件化的實(shí)現(xiàn)方案目前在研究360助手的方式,后續(xù)實(shí)現(xiàn)完成后會(huì)繼續(xù)分享。
上述主要是記錄本次分包原因乙各、過程及最終選擇的方案墨礁,具體細(xì)節(jié)的分包原理及解析大家可以看下開頭的資料及網(wǎng)上查閱,此處不做細(xì)節(jié)述說耳峦。
PS:5月25日嘗試將百川sdk和奪寶移到插件項(xiàng)目中發(fā)現(xiàn)即使這樣在2.3以下手機(jī)上依然安裝不了恩静,所以通過插件話方式暫時(shí)也無法解決。繼續(xù)嘗試分包方式蹲坷。
PS:5月26日嘗試分包處理驶乾,通過設(shè)置每個(gè)dex的最大方法數(shù)(48000)打包后可安裝到2.3及以下手機(jī),而且通過測(cè)試幾部手機(jī)暫時(shí)未發(fā)現(xiàn)啟動(dòng)ANR和Crash現(xiàn)象(包括2.3手機(jī))循签,暫時(shí)這樣處理级乐,后續(xù)再添加maindexlist文件。