本文只是個人為了整理Lint相關(guān)知識滚婉,依據(jù)谷歌翻譯整理而成图筹,水平確實不堪,很多地方自己都讀不太懂让腹,見諒...
新的2015年8月27日:現(xiàn)在有一個最新的示例項目远剩,顯示了如何編寫自定義lint檢查-包括單元測試
https://github.com/googlesamples/android-custom-lint-rules
該代碼庫編寫一個lint規(guī)則比下面寫上去包含的代碼有更好的基礎(chǔ)。
Lint 在ADT20上預(yù)先配置了大概100中檢查骇窍。但是瓜晤,也可以使用附加規(guī)則進(jìn)行擴(kuò)展。例如腹纳,如果你是庫項目的作者痢掠,并且你的庫項目具有一定的使用要求,則可以編寫額外的lint規(guī)則去檢查你的庫是否正確使用嘲恍,然后你可以向這個庫項目的用戶分發(fā)這些額外的lint規(guī)則足画。同樣,您可能需要執(zhí)行公司本地的規(guī)則蛔钙。
本文介紹如何編寫自定義lint規(guī)則锌云。首先,請參閱Google I/O 2012“開發(fā)工具的新功能”中的以下演講吁脱,用一個簡短的demo了解如何編寫和使用lint規(guī)則桑涎。(跳轉(zhuǎn)至視頻55分鐘18秒,如果嵌入式播放器未自動跳轉(zhuǎn)兼贡。)
(...................................內(nèi)嵌視頻好高端啊攻冷,諸位請自行官網(wǎng)............................................)
以下是該視頻的詳細(xì)信息。
為Android Studio創(chuàng)建自定義規(guī)則項目
首先遍希,你需要創(chuàng)建一個單獨的java項目去編譯這個lint 規(guī)則等曼。請注意,這是一個java項目,而不是Android項目禁谦,因為此代碼將被運行在Android studio胁黑,IntelliJ,Eclipse州泊,或Gradle丧蘸,或命令行l(wèi)int工具中運行--而不是在一臺設(shè)備上運行。
最簡單的方法是從示例項目開始遥皂,解壓它力喷,然后根據(jù)需要更改源代碼。你可以在Android Studio或者IntelliJ通過指向要導(dǎo)入的build.gradle項目.
這是一個Gradle項目演训,它具有使用Lint APIs的所有依賴項弟孟,并使用正確的清單條目構(gòu)建.jar文件。
為Eclipse創(chuàng)建自定義規(guī)則項目
如果你使用Eclipse样悟,使用一個簡單的庫創(chuàng)建一個簡單的java項目拂募。
接下來,添加 lint_api .jar文件到項目的classpath乌奇。這個jar文件包含規(guī)則實現(xiàn)的Lint APIS没讲,你可以在sdk的安裝目錄 tools/lib/lint_api.jar中找到lint_api jar包
創(chuàng)建檢測器
當(dāng)你實施“l(fā)int規(guī)則”時,你將準(zhǔn)備實現(xiàn)一個“檢測器”礁苗,它可以識別一個或多個不同類型的問題爬凑。這種分離使得單個檢查器識別與邏輯相關(guān)的不同類型的問題,但是可能具有不同的嚴(yán)重性,描述试伙,并且用戶可能想要獨立的抑制嘁信。例如,清單檢測器查找單獨的問題疏叨,如不正確的注冊順序潘靖,缺失minSdkVersion聲明等。有關(guān)如何編寫lint檢查的更多詳細(xì)信息蚤蔓,請參閱編寫Lint Check文檔卦溢。
在我們的示例中,我們假設(shè)我們有一個自定義View秀又,并且我們想要制定一個lint 規(guī)則单寂,確保這個自定義View的所有使用處都定義了這個特定的View屬性。
這里是完整的檢測器的源代碼:
首先你可以看到這個檢測器繼承ResourceXmlDetector吐辙。這是一種用于資源xml文件如布局和字符串資源聲明的檢測器宣决。還有其它類型的檢測器,例如處理java 源代碼或者字節(jié)碼的檢測器昏苏。
getApplicableElements()方法返回一組當(dāng)前檢測器關(guān)心的xml標(biāo)簽尊沸。這里我們只返回了我們自定義view的標(biāo)簽威沫。lint基礎(chǔ)設(shè)施將為每次出現(xiàn)的標(biāo)簽調(diào)用visitElement()方法--并且僅針對該標(biāo)記的出現(xiàn)。在visitElement()方法中洼专,我們簡單的看當(dāng)前的元素是否定義了我們自定義的屬性(“exampleString”)棒掠,如果沒有,我們就報告一份錯誤壶熏。
visitElement方法傳遞一個context對象句柠。這個context提供很多相關(guān)的context;例如棒假,你可以查找相應(yīng)的項目(從這兒請求minSdkVersion或者targetSdkVersion),或你可以查找正在被分析的xml文件的路徑精盅,或你可以創(chuàng)建一個錯誤的位置(如此處所示)帽哑。在這里,我們傳遞這個元素叹俏,這將使錯誤指向元素的開頭妻枕,但是你可以例如傳遞一個xml屬性對象,這將指向一個特定的屬性粘驰。
再說一次屡谐,查看Writing a Lint Check文檔以獲取更多的細(xì)節(jié)。
創(chuàng)建問題
report()方法第一個參數(shù)是ISSUE蝌数。這是該檢測器報告問題的引用愕掏。這是我們在上面類中頂部定義的靜態(tài)字段。
一個問題有幾個不同的屬性顶伞,按以上順序定義:
? ? ? ◆id饵撑,這是一個與這個問題有關(guān)的常量,應(yīng)該是簡短和描述性的唆貌;這個id例如用于java抑制注釋和
? ? ? ? xml抑制屬性來標(biāo)識這個問題滑潘。
? ? ? ◆摘要。這應(yīng)該是問題的簡要(單行)摘要锨咙,例如在Eclipse中的Lint Options UI和其它簡要描述
? ? ? ? 這個問題的地方语卤。
? ? ? ◆說明。這是對問題的更長的說明酪刀,這應(yīng)該向lint的用戶解釋這是什么問題粹舵。通常一次 lint 的錯誤
? ? ? ? 信息是簡短的(單行),并且有時候很難在單行錯誤信息中完全解釋一個細(xì)的問 題蓖宦,所以該說
? ? ? ? 明用于提供更多的上下文齐婴。該說明在lint命令行工具創(chuàng)建的完整HTML報告中顯示,在Eclipse
? ? ? ? Lint窗口中顯示當(dāng)前選定的問題等稠茂。
? ? ? ◆類別柠偶。這里有許多預(yù)定義的類別情妖,類別可以嵌套(例如可用性>圖標(biāo)),并且這有助于
? ? ? ? 用戶過濾和排序問題诱担,或者通過命令行僅運行某些類型的問題毡证。最常見的類別? ?
? ? ? ? 是“correctness”和"performance",但是也包括國際化,可訪問性蔫仙,可用性等料睛。
? ? ? ◆優(yōu)先權(quán)。優(yōu)先級是1-10之間的整數(shù)摇邦,其中10是最重要的恤煞,并且這被用于排序相應(yīng)每一個其
? ? ? ? 它優(yōu)先級的問題。
? ? ? ◆嚴(yán)重性施籍。一個問題可以有嚴(yán)重的居扒,錯誤,警告丑慎,或忽略默認(rèn)的嚴(yán)重性喜喂。請注意我所說的默
? ? ? ? 認(rèn):用戶可以通過一份lint.xml 文件(更多信息)覆蓋問題所使用的嚴(yán)重性。嚴(yán)重和錯誤在
? ? ? ? eclipse中作為“錯誤”展示竿裂,但是嚴(yán)重的問題在用戶想要在Eclipse當(dāng)中打包一份APK的任何
? ? ? ? 時候是自動運行的(沒有用戶的介入)玉吁,并且如果它們中的任何一個發(fā)現(xiàn)錯誤,然后這個
? ? ? ? 打包過程將被停止腻异〗保“忽略”嚴(yán)重性的規(guī)則不運行。
? ? ? ◆檢測器類捂掰。這只是指向負(fù)責(zé)識別問題的檢測器敢会,這應(yīng)該指向我們自己的類。請注意这嚣,我們
? ? ? ? 通過Lint自動實例化檢測器鸥昏,這是為每次運行完成的。因此姐帚,你不需要擔(dān)心在運行之后清除
? ? ? ? 檢測器中的實例狀態(tài)吏垮。在Eclipse中(其中Lint可以運行多次),將為每次運行創(chuàng)建一個新
? ? ? ? 的檢測器罐旗。因此膳汪,你的lint規(guī)則必須有一個公有的默認(rèn)構(gòu)造器。(如果沒有指定九秀,這個編譯
? ? ? ? 器將自動為你創(chuàng)建一個遗嗽,就是上面的例子
? ? ? ◆檢測范圍。這決定了這個問題適用于哪些類型的文件鼓蜒。這里我們只是聲明我們應(yīng)用于xml文
? ? ? ? 件痹换,但未使用的資源問題的范圍包含java和xml文件征字。
你還可以在問題上調(diào)用其它方法,例如娇豫,將問題定義為默認(rèn)禁用匙姜,或設(shè)置“更多信息”URL。
我們已經(jīng)創(chuàng)建了一個問題的實例冯痢。內(nèi)置的lint問題都在BuiltinIssueRegistry類中注冊氮昧。然而,對于自定義規(guī)則浦楣,我們需要提供我們自己的注冊表袖肥。每一個自定義jar文件提供它們自己問題的注冊類,其中每個問題注冊表可以包含由給定jar文件標(biāo)識的一個或多個問題振劳。
這是我們問題的自定義注冊表:
getIssues()方法返回的是由此注冊表提供的問題列表昭伸。我們在這種特殊的情況下明顯可以使用Collections.singletonList()來代替Arrays.asList(),但是這里通常會有多個問題澎迎。請注意,注冊表必須具有公共默認(rèn)構(gòu)造參數(shù)选调,以便它能夠被lint實例化夹供。
注冊注冊表
最后一件事情我們需要去做的是注冊這個問題注冊表,以便可以由lint找到仁堪。我們通過編輯jar文件的清單文件來做到這一點哮洽。
如果你是在Gradle/Android studio項目中使用它,則由Gradle處理弦聂;只要打開build.gradle文件并根據(jù)需要更新jar條目中注冊表的路徑鸟辅。
在Eclipse,創(chuàng)建一個清單文件莺葫,如下所示:
然后從你使用了上面清單文件的項目中導(dǎo)出一個jar文件匪凉。(我在Eclispe當(dāng)中遇到了一些困難;導(dǎo)出jar對話框中有明確的選項可以做到這一點捺檬,但是當(dāng)我查看導(dǎo)出的.jar文件并打開其中的manifest文件再层,它不包括我上面的兩行,所以我手動創(chuàng)建jar文件:jar cvfm customrule.jar META-INF/MANIFEST.MF googleio)
注意:Eclipse中的導(dǎo)出程序期望在第二行之后添加換行符堡纬。所以聂受,確保最后有一個空行,然后直接從Eclipse中導(dǎo)出應(yīng)該正常工作烤镐。
注冊自定義jar文件
現(xiàn)在我們有自己自定義規(guī)則.jar文件蛋济。當(dāng)lint運行時,它將在~/.android/lint/目錄查找自定義規(guī)則jar文件炮叶,因此我們需要將其放在那里:
(有人問過這個碗旅;Lint基本上調(diào)用了一般的Android工具方法來找到“工具設(shè)置目錄”渡处,用于模擬器快照,ddms配置等扛芽。你可以在這里找到相關(guān)的代碼:https://android.googlesource.com/platform/tools/base/+/master/common/src/main/java/com/android/prefs/AndroidLocation.java)
搜索位置
android目錄的位置通常是主目錄骂蓖;lint將在$ANDROID_SDK_HOME,${user.home}(java屬性)和在$HOME中搜索川尖,只是為了澄清登下。Lint按順序搜索第一個存在的位置:
◆ANDROID_SDK_HOME(系統(tǒng)環(huán)境或環(huán)境變量)
◆user.home(系統(tǒng)環(huán)境)
◆HOME(環(huán)境變量)
所以,如果ANDROID_SDK_HOME存在的話叮喳,然后user.home和HOME將被忽略被芳!這可能看起來是直觀的,但是原因是ANDROID_SDK_HOME并不指向你的SDK安裝路徑馍悟;環(huán)境變量為ANDROID_SDK畔濒。最近的代碼也在尋找ANDROID_HOME。所以锣咒,ANDROID_SDK_HOME真的是一個替代的主目錄位置侵状,當(dāng)你指向特定的模擬器AVDs等進(jìn)行單元測試時,在構(gòu)建服務(wù)器上使用毅整。這個命名是非常不幸的趣兄,并且導(dǎo)致了各種錯誤,但是很難改變悼嫉,而不會破壞用戶過去已經(jīng)依賴的記錄行為⊥叮現(xiàn)在,確保你不會使用環(huán)境變量ANDROID_SDK_HOME來指向你的sdk安裝目錄戏蔑。
之后蹋凝,它查找子路徑/.android/lint/,即其中一個對應(yīng)于剛找到的位置总棵。
◆ANDROID_SDK_HOME/.android/lint/
◆user.home/.android/lint/
◆HOME/.android/lint/
and loads any JAR files it finds there.
并加載在那里找到的任何jar文件鳍寂。
因此,如果你在?/ .android / lint /和ANDROID_SDK_HOME存在時有 Lint jar文件彻舰,你的JAR 文件將不會被讀取伐割。?
如果你在~/.android/lint/和ANDROID_SDK_HOME不存在時有Lint JAR文件,你的JAR文件將被讀取刃唤。
如果ANDROID_SDK_HOME存在隔心,將你的Lint JAR 文件放到ANDROID_SDK_HOME/.android/lint/
運行自定義檢查
最后,讓我們運行l(wèi)int去確保它知道我們的規(guī)則:
如果這不起作用尚胞,通過確保你的jar文件在正確的位置來解決這個問題硬霍,它包含在清單配置文件中正確注冊的行數(shù),完整的包名稱和類名稱是正確的笼裳,它是可實例化的(公有的默認(rèn)構(gòu)造器)唯卖,并注冊您的問題粱玲。
最后,讓我們來測試這條規(guī)則拜轨,這是一個示例布局文件:
現(xiàn)在讓我們在包含上面布局的項目中運行l(wèi)int(并使用 --check MyId參數(shù)抽减,我們僅檢查我們自己的問題):
使用Jenkins /其他構(gòu)建服務(wù)器
如果你作為正在連續(xù)構(gòu)建的一部分運行l(wèi)int,而不是將自定義lint規(guī)則放在構(gòu)建服務(wù)器使用的賬戶主目錄當(dāng)中橄碾,你還可以使用環(huán)境變量$ANDROID_LINT_JARS來指向包含要是用lint規(guī)則的jar文件的路徑(使用File.pathSeparator來分隔卵沉,例如在Windows和其它地方)。更多關(guān)于Jenkins+Lint的使用信息法牲,請查看https://wiki.jenkins-ci.org/display/JENKINS/Android+Lint+Plugin史汗。
更復(fù)雜的規(guī)則
上面的檢查非常簡單。還有更多的可能拒垃。一個真正有用的資源指出如何更多的查看存在的100左右的問題停撞。查看SDK git信息庫,在sdk/lint/悼瓮,特別是sdk/lint/dl/lint/libs/lint_checks/src/ com / android / tools / lint / checking戈毒。
貢獻(xiàn)規(guī)則
自定義lint規(guī)則支持在lint當(dāng)中主要用于編寫真正的本地規(guī)則。如果你想到一般感興趣的Lint檢查横堡,你可以使用上述方法來開發(fā)和檢查規(guī)則副硅。然而,請考慮將規(guī)則歸因于AOSP翅萤,以便所有的Android開發(fā)者可以從檢查中受益!請參閱合作頁腊满。
源代碼
在Gradle/Android Studio/IntelliJ中使用
和在 Eclipse中使用
在Eclipse當(dāng)中打開項目之前套么,上述自定義lint規(guī)則和 lint_api.jar包復(fù)制到項目的根目錄。
更多信息
如果你有Google+賬號碳蛋,你可以在此發(fā)表評論或提問胚泌。https://plus.google.com/u/0/116539451797396019960/posts/iyH3ER3LJF7