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