記錄Tinker與R8的沖突與解決

簡單記錄一下上D8、R8之后的坑,之前業(yè)務(wù)上熱修復(fù)一直用的是Tinker,因?yàn)榇髲S加成加上支持加固(至于為啥上加固就不說了,該懂的都懂,要么加固要么不能上架)。

我們其實(shí)一直是用tinker作為灰度發(fā)布工具的。在長達(dá)一年多的時間里一直很穩(wěn)定,后面上了加固之后偶爾會出現(xiàn)異常,不過大多數(shù)情況其實(shí)是加固的自有升級導(dǎo)致的邊緣case,然后在今年使用D8+R8之后,加固的失敗率明星上升了。尤其是是在高版本的安卓設(shè)備上(7.0+)。跟了一下原因,主要是R8的過度優(yōu)化導(dǎo)致的。R8會把整個項(xiàng)目中的所有代碼,包括依賴庫中的代碼都進(jìn)行全局優(yōu)化,其優(yōu)化程度堪稱恐怖,這里就不細(xì)說了,有興趣可以可以看下Jake Wharton大神的博客

其中一個導(dǎo)致問題的優(yōu)化是全局公共方法抽出,R8會把全局中代碼相似度非常高的代碼抽出來,放到一個新生成的類里,從而減少方法數(shù)。然后這個方法可能會被放到別的dex里。于是當(dāng)啟用熱修復(fù)patch之后會導(dǎo)致tinker里的一部分代碼因?yàn)楸粌?yōu)化到別的dex里,在新合成的dex里并不存在,從而導(dǎo)致ClassNotFoundException,然后用戶就崩潰了。

分析問題,主要是Tinker的相關(guān)代碼被優(yōu)化處理了,并且這個優(yōu)化并沒有提供開關(guān),keep也沒用,keep并不能阻止R8的優(yōu)化。于是有了一個邪道方案:
第一步,先keep tinker的全部相關(guān)代碼。因?yàn)閜ackage name不同,自然就會被放到一個package里。
第二步,在一個獨(dú)立的項(xiàng)目里放入tinker 并且不啟動R8并且打包完成,然后把包拆開把相關(guān)的tinker代碼撈出來備用。
第三步,在主項(xiàng)目每次編譯完成后解開包,把主dex里的tinker代碼刪除掉再把獨(dú)立項(xiàng)目里的備用沒被r8處理過的代碼提出來替換進(jìn)去。
最后,打包回去,再簽名加固,萬事大吉。

似乎聽起來沒什么毛病,結(jié)果后面還是炸了。

再次跟進(jìn)問題,還是R8的優(yōu)化,tinker一個類的某個變量是私有的,有一個set方法,然而R8優(yōu)化的時候把他換成public的了(估計還是為了節(jié)約方法數(shù),當(dāng)初的dex 65535的坑真的大)。然而我們替換回去的tinker還是私有的,于是,再次出現(xiàn)了方法不存在錯誤。

所有問題又繞回來了,歸根結(jié)底還是要阻止R8對項(xiàng)目里tinker代碼的優(yōu)化。于是再上一個方案的基礎(chǔ)上,把主項(xiàng)目里對tinker的引用換成 compileOnly 不存在你總不能優(yōu)化了吧?再去查看了一下之前備用的tinker代碼塊方法數(shù),大概2000以內(nèi),于是手動造2000個空方法并且keep到主dex里,再之前的第三步里,把插入的樁方法全部干掉,換成沒被處理過的tinker的代碼。最后打包回去。

到此R8跟tinker的沖突暫時告一段落,不知道后面會不會還有新的坑。至于為什么步換成proguard?我也想啊,但是現(xiàn)在主項(xiàng)目已經(jīng)到了不上R8 主dex就一定會超出65535的地步了,這是另一個坑,這里就不說了。
相關(guān)代碼就不貼了,畢竟涉及到公司項(xiàng)目。希望這個思路可以幫助遇到相關(guān)問題的人。

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

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

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