lint是著名的C/C++語(yǔ)言靜態(tài)代碼分析工具之一,Android Lint顧名思義,針對(duì)Android的靜態(tài)代碼分析工具,能夠?qū)ndroid項(xiàng)目中潛在的bug、可優(yōu)化的代碼、安全性、性能、可用性、可訪問(wèn)性、國(guó)際化等進(jìn)行檢查。
在Android SDK Tools 16及更高的版本中,Lint工具會(huì)自動(dòng)安裝。通過(guò)對(duì)Android工程源代碼等進(jìn)行掃描檢查,可發(fā)現(xiàn)潛在的問(wèn)題,更好的提升代碼質(zhì)量。Android Lint提供了命令行方式執(zhí)行,也與IDE(如Eclipse、Android Studio)集成提供了IDE圖形界面,單獨(dú)輸出的xml和html結(jié)果報(bào)告可以提供更豐富的信息。
初步掃描手管代碼得到一份html的報(bào)告,結(jié)果分類(lèi)比較清晰,但有2000+error,12000+warning,,嚇的手一抖直接關(guān)掉了。。
為了降低大家的心理門(mén)檻,我們從手管已經(jīng)接入Daily的NewApi規(guī)則來(lái)看看lint是怎么工作的
最簡(jiǎn)單的,先來(lái)看看NewApi規(guī)則說(shuō)明:
可以對(duì)NewApi規(guī)則有個(gè)大致的了解,掃描App中的Android Api,對(duì)起始版本大于AndroidManifest.xml中聲明的minSdkVersion,即未加判斷調(diào)用的高版本Api進(jìn)行提示。沒(méi)有判斷調(diào)用不支持的Api會(huì)怎么樣呢?低版本機(jī)器在執(zhí)行到該代碼段時(shí)就會(huì)拋出NoSuchMethodException異常crash。
再來(lái)看看NewApi的掃描結(jié)果:
可以看到檢查結(jié)果中的issueid、summary、PRiority、severity、category、explanation和說(shuō)明中是一致的,message中有更詳細(xì)的代碼段接口版本說(shuō)明,location字段中給出了對(duì)應(yīng)的代碼位置。
Issueid:規(guī)則名,唯一;
Summary:規(guī)則的簡(jiǎn)單概述;
Priority:優(yōu)先級(jí),1~10,10為最嚴(yán)重
Severity:嚴(yán)重性,F(xiàn)atal,Error,Warning,Information,Ignore
Category:類(lèi)別,Correctness 正確性Security 安全性Performance 性能Usability 可用性accessibility 可達(dá)性i18n 國(guó)際化
Explanation:規(guī)則詳細(xì)描述及問(wèn)題解決建議
從NewApi在手管的落地實(shí)踐來(lái)看NewApi確實(shí)是解決Api版本兼容性的一大利器,lint是怎么實(shí)現(xiàn)這一規(guī)則的呢?lint支持的280+規(guī)則都是怎么實(shí)現(xiàn)的呢?
我們來(lái)看看lint規(guī)則的主要模塊:
Issue:lint規(guī)則定義,比如NewApi,lint已有規(guī)則列表維護(hù)在BuiltinIssueRegistry類(lèi)中,目前l(fā)int官網(wǎng)提供有280+個(gè)規(guī)則,可以按需打開(kāi)也可以修改各個(gè)規(guī)則的嚴(yán)重級(jí)別,已有規(guī)則配置可以見(jiàn)實(shí)踐篇;
Detetor:檢索項(xiàng)目中檢測(cè)項(xiàng)對(duì)應(yīng)的問(wèn)題,一個(gè)檢測(cè)器可以檢索多個(gè)獨(dú)立但相關(guān)的問(wèn)題,比如通過(guò)一個(gè)檢測(cè)器查找多種Manifest相關(guān)的問(wèn)題;
Implematation:連接檢查項(xiàng)和檢測(cè)器,也聲明規(guī)則的查找范圍,常用的scope包括CLASS_FILE,java_FILE,RESOURCE_FILE等;
Registry:注冊(cè)模塊,lint維護(hù)了一張所有規(guī)則的列表,檢查規(guī)則通過(guò)注冊(cè)添加到規(guī)則列表中;
從NewApi檢查項(xiàng)的注冊(cè)定義可以看到,issueid、summary等均在issue注冊(cè)時(shí)傳入以便在結(jié)果報(bào)告中展示,Implematations中scope聲明了規(guī)則查找范圍,Scope.CLASS_FILE標(biāo)明了NewApi檢查項(xiàng)針對(duì)編譯后的class字節(jié)碼進(jìn)行掃描:
再來(lái)看看NewApi掃描核心的ApiDetector:
ApiDetector檢測(cè)器繼承自ResourceXmlDetector并實(shí)現(xiàn)Detector.ClassScanner和Detector.JavaScanner接口,Detector類(lèi)中提供了7種XXXScanner接口
Scanner也并不是直接進(jìn)行代碼行查找,scanner中通過(guò)lombok.ast(Abstract Syntax Tree抽象語(yǔ)法樹(shù)) API來(lái)進(jìn)行代碼節(jié)點(diǎn)的查找,有興趣的童鞋可以參照Eclipse AST介紹。
掃描規(guī)則實(shí)際上就是實(shí)現(xiàn)detector的過(guò)程,每個(gè)detector可以定義1個(gè)或多個(gè)不同類(lèi)型的issue,像ApiDetector中會(huì)處理多個(gè)Api調(diào)用相關(guān)的規(guī)則:NewApi,InlinedApi,Override,UnusedAttribute;
繼續(xù)查看ApiDetector最主要的checkClass()可以更深入了解NewApi的掃描過(guò)程:
Api版本庫(kù)中維護(hù)了一份Android每個(gè)版本Class的類(lèi)關(guān)系和成員變量,是Api兼容性檢測(cè)的前提條件
首先進(jìn)行類(lèi)掃描處理,如果沒(méi)有TargetApi定義的局部miniSDK則獲取AndroidManifest.xml中minSdkVersion定義,首先進(jìn)行繼承類(lèi)和接口類(lèi)的掃描判斷,發(fā)現(xiàn)的問(wèn)題通過(guò)report()函數(shù)輸出:
然后開(kāi)始對(duì)類(lèi)節(jié)點(diǎn)的掃描處理,同樣判斷方法前是否有TargetApi標(biāo)注定義了局部miniSdk,依次檢查類(lèi)中method、field、LDC引用值,源碼中可以看到在method、field的調(diào)用判斷中,也對(duì)android常用的版本判斷格式if(Build.VERSION.SDK_INT >= XX)的分支進(jìn)行判斷檢查
對(duì)應(yīng)的掃描結(jié)果中message字段返回了兼容性調(diào)用問(wèn)題的類(lèi)型及起始版本,并將發(fā)現(xiàn)的問(wèn)題通過(guò)report()函數(shù)輸出。
通過(guò)走讀lintNewApi的實(shí)現(xiàn)過(guò)程,我們也清楚了lint中的規(guī)則是如何定義并實(shí)現(xiàn)的,我們自己是否也可以參照這個(gè)結(jié)構(gòu)來(lái)自定義規(guī)則呢?答案是肯定的,lint也支持自定義規(guī)則擴(kuò)展,自定義規(guī)則通過(guò)IssueRegistry加入到規(guī)則表中和其他規(guī)則一起使用。什么場(chǎng)景適合自定義規(guī)則呢?比如手管UI庫(kù)的編寫(xiě)規(guī)范,典型問(wèn)題的修復(fù)情況,某些封裝了不建議直接使用的Api的調(diào)用等都可以通過(guò)自定義規(guī)則來(lái)規(guī)范和提醒。
自定義lint規(guī)則是以jar形式存在的,通過(guò)繼承l(wèi)int的兩個(gè)類(lèi)來(lái)實(shí)現(xiàn)規(guī)則擴(kuò)展:
①繼承IssueRegistry:自定義Lint規(guī)則的主類(lèi),有且只有一個(gè),注冊(cè)這個(gè)自定義Lint項(xiàng)目中有哪些自定義的issue:
②繼承Detector并實(shí)現(xiàn)Detector中合適的XXXScanner接口:可以根據(jù)需求實(shí)現(xiàn)多個(gè)自定義Detector類(lèi),在每個(gè)Detector類(lèi)中實(shí)現(xiàn)自定義的一個(gè)或多個(gè)issue;
在eclipse中新建java工程并引用sdk/tools/lib/lint-api.jar包,手動(dòng)添加導(dǎo)出配置MANIFEST.MF文件
export導(dǎo)出jar包,生成的jar包放到~/.android/lint/路徑下,此時(shí)調(diào)用命令行工具就可以看到我們自定義的規(guī)則了
管中窺豹,走讀已有規(guī)則的實(shí)現(xiàn)可以讓我們對(duì)工具有更全面的了解,更好的應(yīng)用到項(xiàng)目中,網(wǎng)上關(guān)于自定義規(guī)則的示例也不多,源碼中的規(guī)則實(shí)現(xiàn)也是一個(gè)很好的參照途徑,也需要我們更進(jìn)一步分析代碼問(wèn)題挖掘個(gè)中需求,才能發(fā)揮工具的更大作用。
本文簡(jiǎn)單結(jié)合手機(jī)管家NewApi的實(shí)踐來(lái)了解Lint代碼掃描過(guò)程,期待大家一起來(lái)探討代碼掃描工具有哪些更有價(jià)值的應(yīng)用場(chǎng)景呢?
參考資料:
[1] http://tools.android.com/tips/lint/writing-a-lint-check
[2]https://android.googlesource.com/platform/tools/base/+/master/lint/
[3]https://www.bignerdranch.com/blog/building-custom-lint-checks-in-android/
[4] Android Lint: 靜態(tài)檢查Android版本兼容性問(wèn)題[5]Android Lint工作原理剖析
【TMQ新書(shū)專(zhuān)欄】https://weidian.com/?userid=984448577
原文鏈接:http://tmq.QQ.com/2017/02/newapi_lint/
關(guān)注我們的微信公眾號(hào)查看完整內(nèi)容哦~~~~
想知道更多測(cè)試相關(guān)干貨 請(qǐng)關(guān)注我們的微信公眾號(hào):騰訊移動(dòng)品質(zhì)中心TMQ 二維碼:
版權(quán)聲明:騰訊TMQ擁有內(nèi)容的全部版權(quán),任何人或單位對(duì)本貼內(nèi)容進(jìn)行復(fù)制、轉(zhuǎn)載時(shí)請(qǐng)申明原創(chuàng)騰訊tmq,否則將追究法律責(zé)任。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注