Android自定義Lint檢查有效提高代碼質量、避免人工的低級失誤、規範代碼,屬於程序自動化的內容,這部份內容涉及的資料較少,可是實際意義重大,尤爲是對有規模的團隊而言。node
提示:文中連接須要點擊文章末尾處閱讀原文才能點擊。android
![](http://static.javashuo.com/static/loading.gif)
一、 Coding時遇到的問題json
案例1:com.alibaba.fastjson.JSONapi
工程中常常會使用 FastJson 來解析 Json 數據,因爲會使用反射機制構造 JavaBean 對象,那麼 release 版本混淆的狀況下,若是沒有對相應的 JavaBean 對象作keep處理的話,JavaBean 沒法成功構建,從而出現對象爲 NULL 的狀況。每每會在臨上線的兩三天在release包中忽然發現莫名的崩潰、功能失效之類的問題,都是因爲這個緣由。形成往往發版本就要加班的窘境。數組
案例2:activity基類安全
因爲有一些統計,例如友盟統計活躍的需求,須要在 Activity 中的 OnResume/OnPause 實現某些方法,固然還有不少咱們項目自身的緣由,須要全部工程中的 Activity都要繼承自某一個咱們實現的 BaseActivity,若是是個小工程小團隊,咱們能夠全局搜索一下,按期檢查一下,均可以。若是是個十餘人甚至更大的團隊,每一個版本的需求中都有可能產生新的 Activity,或者在大的工程重構後,可否保證人不會犯錯,不會忘記將咱們的 Activity 繼承自咱們的 BaseActivity ?微信
案例3:團隊的編碼規範網絡
當一個團隊技術負責人認認真真的制訂了少許有效的編碼規範後,苦口婆心的像是傳銷似的要求團隊成員遵循,難道須要咱們對工程中的每行代碼都要 review 嗎?培養習慣真的不容易。app
好了,管中窺豹而已,項目中的「非典型技術的技術問題」還有不少是否是?除了自動化咱們就別想期望人來解決。ide
類型1: 若是你根本沒據說過 Lint,請趕忙 Google 一下 Android Lint。由於你是一個或者極可能會成爲一個技術 Leader,若是到時候要靠人工審覈這些,你的麻煩就大了去了;(初級-看一下整個第二大部分)
類型2: 若是你據說過Lint沒有使用過,打開你的工程cd到主工程,再 ../gradlew Lint 一下。或者在 AndroidStudio Menu 中點擊Analyse -> Inspect Code。由於知識不僅停留在:「啊,我據說過」;(初級-看一下整個第二大部分)
類型3: 若是常用 Google 提供的 Lint,然而沒有自定義過 Lint,這篇文章最適合你。由於關於自定義 Custom-Lint 資料很少,我也把好的資料地址都放進來了;
類型4: 若是你是自定義 Lint 高手,聯繫我 Email,交換一下學習心得,這個最可貴。
版權說明:此部分概念性內容大部分摘抄自網絡,並不是原創,地址放在文章最後一部分參考資料中。
Android Lint 是一個靜態代碼分析工具,它可以對你的 Android 項目中潛在的 bug 、可優化的代碼、安全性、性能、可用性、可訪問性、國際化等進行檢查。Android Lint 內置了不少 Lint 規則,到如今爲止是230餘項檢查,總共能夠分爲如下幾類:
Correctness 正確性
Security 安全性
Performance 性能
Usability 可用性
Accessibility 可訪問性
Internationalization 國際化
靜態代碼分析工具常被用來檢測代碼中的質量問題或者編碼規範問題。Lint 做爲最先的靜態代碼分析工具,已被用來做爲靜態代碼分析工具的代名詞。所以,Android SDK 也把其靜態代碼分析工具取名爲 Android Lint。Android Lint 內置了不少 Lint 規則,用來檢測一些常見的代碼問題(例如,正確性問題、安全問題、性能問題,等等)。同時,Android Lint 也支持自定義 Lint 規則,以便開發者靈活應用,更好地提高項目代碼質量。利用自定義 Lint 規則,既能夠用來在項目中檢測代碼質量問題,也能夠用來保證編碼規範的執行。
更直觀的講,咱們平時代碼寫的疏漏,Java文件、xml 文件等等寫的有問題時,第一時間報警給咱們,編譯時報錯沒法經過,這都是 Lint 在幫咱們作檢查。固然,這些檢查都是 Google 默認幫咱們寫好的。
下面列舉一些常見的lint會檢測的代碼問題:缺乏翻譯(和未使用的翻譯);
佈局性能問題(老的 layout opt 工具會用於查找全部這樣的問題,和除此以外更多的問題);
未使用的資源;
不一致的數組大小(當在多個配置中定義數組);
可訪問性和國際化問題(硬編碼字符串,缺乏 contentDescription 等);
圖標問題 (如丟失密度、 重複圖標、 錯誤尺寸等);
可用性問題 (如不在文本字段上指定輸入的類型);
清單錯誤。
Google 提供的默認 Lint 檢查很全面可是咱們終歸會有不少項目特性、自定義規則沒法知足,如開頭我提到的幾個案例,這時候咱們須要自定義 Lint。另外更深層的問題是要自動化檢查取代人工檢查的成本,提升生產效率,下降人工低級失誤帶來的負面影響,這個理論是自從工業革命開始就早已被確認的毋庸置疑了,沒什麼可爭論的,無論自動化過程花費多長時間、多大精力,咱們都要堅持。Google 在 Custom-Lint 上提供了強大的 API 支持咱們,並且更新速度很快,只惋惜相關文檔仍是比較少的。
說明:此部分可參見教程:自定義 Lint 規則簡介,這裏僅羅列大致思路和使用時的備註。
A. Gradle配置包
compile 'com.android.tools.lint:lint-api:25.2.0' compile 'com.android.tools.lint:lint-checks:25.2.0'
至於使用的版本號,你能夠查看一下最新的,請務必如此,我以前在寫「FastJsonDetector」時,使用的是24.3.1版本,想查看某個類是否實現了某個接口,調查了好久而不得方法,結果發現新版本25.1.0裏面新增了「getInterfaces」這個方法。因此但願你們儘可能使用新版本API。
B. com.android.tools.lint.client.api.IssueRegistry
實現一個繼承自此類的子類,他起到的做用是註冊你有哪些檢查要開放出去在 Lint 過程當中被執行。
另一定注意這個地方,要在 Gradle 配置上他才能夠。
jar { manifest { attributes('Lint-Registry': 'com.qjoy.LFIssueRegistry') } }
C. Detector 實例+ XXXScanner 接口
繼承 Detector 並選擇 Detector 中合適的 XXXScanner 接口來實現。在這裏根據自身業務需求,實現各類自定義探測器(Detector ),並定義各類 issue,根據自身需求的不一樣這樣的類能夠有一個或多個。
其中,com.android.tools.lint.detector.api.Detector 提供了7種 XXXScanner 接口。
另外,利用 Context(此處的 Context 是 Lint 檢查的類,不是 Android 的那個)的 report 方法報警,就會在錯誤日誌中產生一條記錄啦。
怎麼樣,是否是足夠強大,檢查全部你能想到的。
每種 XXXScanner 接口功能說明:
JavaScanner 功能:Specialized interface for detectors that scan Java source file parse trees
ClassScanner 功能:Specialized interface for detectors that scan Java class files
BinaryResourceScanner 功能:Specialized interface for detectors that scan binary resource files
ResourceFolderScanner 功能:Specialized interface for detectors that scan resource folders (the folder directory itself, not the individual files within it)
XmlScanner 功能:Specialized interface for detectors that scan XML files
GradleScanner 功能:Specialized interface for detectors that scan Gradle files
OtherFileScanner 功能:Specialized interface for detectors that scan other files
說明:最好看一下源碼: GitHub follow&star。
咱們選擇兩個咱們實現的Detector簡單分析一下,其他的請查看源代碼吧:
目標:類是否繼承自 LFBaseActivity 或者 LFBaseAppCompatActivity。
public class BaseActivityDetector extends Detector implements Detector.JavaScanner { ...省略非核心代碼... public AstVisitor createJavaVisitor(JavaContext context) { return new ForwardingAstVisitor() { @Override public boolean visitClassDeclaration(ClassDeclaration node) { ...核心代碼... 在這裏分析node,檢查經過或者報警 } } }
因爲是掃描 Java 代碼內容,咱們實現 JavaScanner,利用createJavaVisitor 接口的 visitClassDeclaration 掃描內容。
這裏咱們使用一個遞歸方法recursiveSupperClass
查看父類,追溯直到checkActivityRules
發現繼承了 LFBaseActivity/LFBaseAppCompatActivity,或者直到發現直接繼承了 Activity/AppCompatActivity,或者直接繼承了 Object (說明他根本不是 Activity )。
目標:檢查圖片文件尺寸是否超過某個限定的大小。
public class ImageFileSizeDetector extends Detector implements Detector.BinaryResourceScanner { ...省略非核心代碼... @Override public boolean appliesTo(ResourceFolderType var1) { return var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.MIPMAP)) || var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.DRAWABLE)); } @Override public void checkBinaryResource(ResourceContext context) { String filename = context.file.getName(); ...核心代碼... 在這裏分析node,檢查經過或者報警 } }
因爲是掃描二進制資源,咱們實現 BinaryResourceScanner,利用 BinaryResourceScanner 接口的 checkBinaryResource 掃描內容。
經過 ResourceContext 能夠獲取文件信息,用來作咱們判斷的條件。
最後,讓咱們看看執行效果吧:
官方文檔:lint-api 25.1.0版本
沒有什麼比讀官方api文檔更高效的方法了,這裏看看官方最新的版本是什麼,以後替換鏈接中的25.1.0查看最新的文檔。
GitHub-AndroidDevNotes
構建自定義lint檢查整個工程什麼樣的結構;
教程:自定義 Lint 規則簡介
美團app-lint實現方案
google實現好的lint檢查源代碼
a11n-android-lint
英文原文的;
Github-yongce/AndroidArch
不錯的實例程序;
教程-Android Lint
全面而系統講了原理相關知識,應該是目前能搜索到的最高級的資料了。
工程源碼託管在 GitHub follow&star。
本文由原做者薛晴獨家受權Open軟件開發小組發佈,著做權歸原做者全部。如需轉載請聯繫原做者申請受權。
申請加羣交流學習請加主編微信:Jf-1994(井方哥),並備註:姓名-地區-公司-職業-加羣。
專一Android開發,歡迎關注open_dev!
本文分享自微信公衆號 - Open軟件開發小組(open_dev)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。