記錄我修改JakeWharton的ButterKnife bug的實用經(jīng)驗

前言

不得不說ButterKnife是一個很有學習價值的項目翁狐。我從學習源碼类溢,修改bug后,最后pull request露懒,學到了很多東西闯冷。如果你對Butterknife 源碼還不了解,建議先看一下這篇文章懈词。本文章不介紹基礎的源碼流程蛇耀,主要是深入一部分代碼,分享一些我在調(diào)試bug坎弯,修改bug的經(jīng)驗纺涤。

與其拿著一個黑盒子看著表面译暂,不停得猜測里面到底哪里出了問題,不如打開盒子看一下洒琢,看懂它的邏輯秧秉,比在外面猜要容易的多。

找個bug去練手

在前不久學習完了ButterKnife 源碼后衰抑,總有一種紙上得來終覺淺象迎,絕知此事要躬行的感覺,于是我打算去issue中找一些bug改改呛踊,順便看看自己是否完全了解了這個源碼砾淌。最后找了一個多人反映的問題Missing resource ID for OnClick annotation,就開啟源碼谭网,進行bug的定位汪厨。

簡單描述一個問題,當子module使用kotlin時愉择,對于相同的資源劫乱,如果在事件注解(例如:@OnClick)之前不使用其他注解(例如:@bindview),就會出現(xiàn)崩潰锥涕。

Bug 定位

調(diào)試后發(fā)現(xiàn)衷戈,在生成view_binding.java之后,Utils.findRequiredView() 使用原始整數(shù)而不是 R 引用层坠,發(fā)現(xiàn)這個整數(shù)在apk中R文件殖妇,沒有對應的參數(shù)值。也就是說沒有這個資源破花。

正常情況:

在這里插入圖片描述

ButterKnife生成代碼如下谦趣,可以看到上面都是使用的R引用,所以不會出現(xiàn)資源找不到的問題

在這里插入圖片描述

異常情況

注釋掉@BindView的代碼

在這里插入圖片描述

ButterKnife生成代碼如下座每,這里直接使用了數(shù)字前鹅,但是這個數(shù)字,在R文件中沒有對應的值

在這里插入圖片描述

問題來了:

1尺栖、這個整數(shù)值是哪里來的嫡纠,為什么沒有與代碼中的資源對應起來?

2延赌、為什么@OnClick之前使用了 @OnBindView 就正常呢?

3叉橱、是butterknife 生成代碼的時候出問題挫以?

4、是傳遞給butterknife的時候窃祝,就已經(jīng)是數(shù)字了掐松?

Bug 分析思路

調(diào)試后發(fā)現(xiàn)這個整數(shù)值是子module R文件里的值,但是在打包資源合并后,這個值發(fā)生了變化

打包合并資源時大磺,R文件的靜態(tài)值會被更改抡句。 所以導致 Missing resource ID 。

下圖是在反編譯apk杠愧,觀察其中的R文件和R2 文件待榔。(R2是對R的復制,把R中的靜態(tài)變量流济,更改為R2中靜態(tài)常量锐锣,變量名和值不變)

在這里插入圖片描述

思考過程:

靜態(tài)常量,編譯期常量绳瘟,編譯時就確定值雕憔。常量值存儲在JVM內(nèi)存中的常量區(qū)中,在類不加載時即可訪問糖声。

靜態(tài)變量斤彼,需要類加載后,才能確定具體的值蘸泻。

難道是因為R2的引入琉苇,導致的?但是仔細一想蟋恬,如果是編譯期進行靜態(tài)常量值替換翁潘,那么為什么 不注釋掉@BindView的代碼,R的引用值就沒有被替換呢歼争?所以我把焦點轉(zhuǎn)移到了對View_Binding 文件生成的過程拜马。

因為ButterKnife是在編譯期根據(jù)注解生成代碼的,所以需要在編譯期調(diào)試代碼沐绒。

如果是Java俩莽,使用注解處理AnnotationProcessor,就使用遠程調(diào)試乔遮,很容易搞定扮超。但是項目是Kotlin,使用注解處理 Kapt蹋肮,和Java的遠程調(diào)試不太一樣出刷,當時搞了好久斷點沒作用。

后來決定把這個子module改為Java坯辩,先把問題找到馁龟,解決了。kapt的調(diào)試放后邊處理漆魔。結(jié)果發(fā)現(xiàn)使用Java沒有任何問題坷檩,就是Kotlin有問題却音,沒辦法,各種嘗試矢炼,功夫不負有心人系瓢,終于找到了如何調(diào)試kapt,可查看我的這篇文章 Java AnnotationProcessor 和 Kotlin Kapt 編譯期調(diào)試代碼——實踐與原理

于是開始了愉快的調(diào)試句灌,發(fā)現(xiàn)在生成Id(Butterknife 中的Id類)就已經(jīng)使用了整數(shù)

在這里插入圖片描述

那么就會導致夷陋,在生成方法的時候,使用了數(shù)字涯塔,而不是R引用肌稻。我們希望的情況是下圖的code 是個R.引用。

在這里插入圖片描述

為什么@OnClick之前使用了 @OnBindView 就正常呢匕荸?

因為在處理@OnBindView 傳入的是R引用爹谭,所以在生成代碼的時候,上圖的code是個R 引用榛搔。

同一個資源id(例子中的textview2)诺凡,會使用相同的Id(Butterknife 中的Id類),所以@OnClick之前使用了 @OnBindView是正常的践惑。

于是我想如果能讓上圖的code的值腹泌,不是數(shù)字,而是R引用尔觉,那么就可以解決這個問題了凉袱。于是一路往上找,看看哪里讓他發(fā)生了變化侦铜。

方法getTree 专甩,返回的JCTree 就已經(jīng)是整數(shù)了,那么跟進去getTree钉稍,最后是在一個map中獲取對應的值涤躲,那我們就繼續(xù)跟一下,這個map是怎么傳值進去的贡未。斷點打好种樱,在來一次

在這里插入圖片描述

原來傳進來的時候就是數(shù)字

在這里插入圖片描述

后來發(fā)現(xiàn)網(wǎng)上也有人遇到這個問題,詳見

在跟下去就是kapt的代碼了俊卤,能力有限嫩挤,跟不下去了,去網(wǎng)上查了一下kapt消恍。因為這是在注解處理器的過程俐镐,難道是kapt的原因?kapt是怎么處理kotlin文件的呢哺哼?

kapt 生成的stub中的java文件佩抹,已經(jīng)把靜態(tài)常量進行了替換。(關(guān)于kapt取董,推薦一篇文章棍苹,文章中提到的stub和我真是看到的不太一樣,可能因為kapt已經(jīng)更新了吧)

在這里插入圖片描述

能力有限茵汰,我修改不了kapt 枢里,所以只能想著怎么在注解處理過程,讓這個整數(shù)值替換為對應的R引用

Bug的解決思路

總思路:在生成Id(Butterknife 中的Id類)類的時候蹂午,通過遍歷R引用栏豺,把整數(shù)替換為對應的R引用,

怎么實現(xiàn)呢豆胸?

1奥洼、剛開始想到通過反射來修改class文件,代碼都寫好了晚胡,每次調(diào)試都發(fā)現(xiàn)灵奖,找不到class。仔細一想估盘,這個階段還處在編譯期瓷患,還沒有生成class文件,所以這個方法行不通

2遣妥、效仿butterknife 使用語法數(shù)JCTree的方式擅编,可不可以獲取到R文件的語法樹JCTree呢?

根據(jù)env中的獲取到R 文件的Element 箫踩,就獲取到JCTree爱态,于是問題迎刃而解

在這里插入圖片描述

代碼編譯過程中,不同階段使用不同的方式修改編譯期代碼

最后對之前學到一些知識進行歸納總結(jié)

在字節(jié)碼生成之前

1班套、JCTree 獲取一些源碼信息

2肢藐、使用JavaPot生成代碼類

在字節(jié)碼生成之后

1、可通過反射修改代碼

2吱韭、通過ASM吆豹、Javassit修改class 代碼(實際應用:Android字節(jié)碼插樁——詳細講解 附帶Demo

圖片來自

在這里插入圖片描述
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末理盆,一起剝皮案震驚了整個濱河市痘煤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猿规,老刑警劉巖衷快,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姨俩,居然都是意外死亡蘸拔,警方通過查閱死者的電腦和手機师郑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來调窍,“玉大人宝冕,你說我怎么就攤上這事〉巳” “怎么了地梨?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缔恳。 經(jīng)常有香客問我宝剖,道長,這世上最難降的妖魔是什么歉甚? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任万细,我火速辦了婚禮,結(jié)果婚禮上铃芦,老公的妹妹穿的比我還像新娘雅镊。我一直安慰自己,他們只是感情好刃滓,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布仁烹。 她就那樣靜靜地躺著,像睡著了一般咧虎。 火紅的嫁衣襯著肌膚如雪卓缰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天砰诵,我揣著相機與錄音征唬,去河邊找鬼。 笑死茁彭,一個胖子當著我的面吹牛总寒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播理肺,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼摄闸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妹萨?” 一聲冷哼從身側(cè)響起年枕,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乎完,沒想到半個月后熏兄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年摩桶,在試婚紗的時候發(fā)現(xiàn)自己被綠了桥状。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡典格,死狀恐怖岛宦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耍缴,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布挽霉,位于F島的核電站防嗡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏侠坎。R本人自食惡果不足惜蚁趁,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望实胸。 院中可真熱鬧他嫡,春花似錦、人聲如沸庐完。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽门躯。三九已至淆党,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讶凉,已是汗流浹背染乌。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懂讯,地道東北人荷憋。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像褐望,于是被迫代替她去往敵國和親勒庄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容