Android 項目代碼質量保證實踐
- 2019 年 12 月 12 日
- 筆記
來源:http://www.ltesting.net
1 背景
一個項目開發必然會涉及團隊協作,而工程質量就需要團隊去保證。一般我們期望的代碼:無潛在風險、無重複邏輯、風格無差異、可閱讀性好、新人上手速度快等。為了達到上述目標,一般團隊都會制定一套自己認可的編碼規範,並且周期性進行 code review。然而編碼規範的制定,那麼一套編碼規範需要包含哪些內容,另外編碼規範僅僅是一套軟規範,實際程序員同學能遵守到什麼程序還是一個未知數,所以需要我們進行人肉 code review,而這種人肉排查方式,很容易遺漏部分問題,保障性還是有些不足。 為此,我們從編碼前期、編碼中期和編碼後期保證進行了初步嘗試。
2 編碼前期 – 編碼規範
對於一個 Android 項目,一般需要涉及的編碼規範有:
- 普通 java 編碼風格規範 如每個方法最大行數,每個類文件的最大行數,每個方法最大參數數等
- 普通 java 編碼最佳實踐 如
if
、for
、try
等嵌套深度規範,變量初始化規範等 - 通用 Android 編碼規範(java 部分和 xml 部分), 包含 Android java 部分和 Android xml 部分,如避免使用普通內部類定義handler,避免 layout xml 中存在無用結點等
- Gradle 編碼規範 如盡量避免 lib 使用 module,獨立工程可以通過 aar 或 mvn 方式導入
- 具體項目相關的編碼規範等 如項目團隊規定使用自定義 LogUtil 打日誌,Activity、Fragment 等重要類的繼承關係,Activity 對應的 xml 文件必須以
activity_
開頭等
制定了這些內容可以一定程度上規範程序猿的編碼,配合團隊進行了周期性的 code review (一般是一個版本一次,大概 4 個星期一次),會有比較好的效果。然而即使這麼做,還是存在一定的問題,距離我們期望的目標還是比較遠。比如各個單例類的定義五花八門,使用 LogUtil
代替 Log
的使用,Message.Obtain()
代替 new Message()
,Activity
部分文件命名,甚至 Activity
、Fragment
的基類定義規則還是很容易發生錯誤,並沒有被發現。隨着編碼規範的完善充實,多個開發的編碼規範如何保證,就會成為一個顯而易見的問題。
3 編碼中期 – 編碼模板
為了實現公用代碼復用,我們定義了一些 util
工具類,但隨着各個開發的補充,這套 util
工具類也越來越多,如 LogUtil
、KeyboardUtil
等,而這些類一部分是為了統一入口,如統一使用 LogUtil
,可以統一做到測試服打開本地日誌,線上服關閉日誌;KeyboardUtil
方便使用者控制鍵盤的彈出隱藏等操作。雖然定義了這些工具類,但終究存在應該使用而沒有使用的情況。當然這些工具代碼並不難,開發在自己的模塊也能很容易的實現和使用,一般也不會出問題。然而上述講的優點都會消失掉。而這些問題依賴 code review 也是件頭疼的問題。 此外,RecycleView
的編碼方式,單例模式的實現方式等等,各個開發可能寫出各式代碼,甚至實現的單例模式並不是線程安全的。 提了這麼多,另一方面,要求開發在繁忙的業務中嚴格遵守這些規範,也有些強人所難。所幸,Android Studio 為我們提供了編碼模板來解放開發的工作,並一定程度上統一編碼風格。
3.1 Live Template
3.1.1 系統模板
查看一個使用 Android Studio 中很常見的例子,輸入 for
,出現下拉列表如下:

image
當選擇 fori
,出現編碼片段:

image
確認循環變量 i
,跳入循環結果值的輸入:

image
上例,就是 Android Studio 中系統提供的 Live Template
一個實例。這個類似於 iOS 中的 Code Snippets
,提供了代碼片段的能力。 Android Studio
(Mac) 進入 Settings/Preferences
-> Editor
-> Live Templates
,可以看到已定義的模板組:

image
查看 fori
編碼模板的實現:

image
- A: 完成模板的快捷鍵
Tab
- B: 位置分類
iterations
- C: 編碼模板對應的縮寫
fori
- D: 模板的內容
- E: 模板應用環境
3.1.2 自定義模板
- 構建項目
group

image 輸入 group 的名稱

image
- 構建具體編碼模板

image
- Abbreviation:觸發編碼模板的縮寫
- Description:模板的具體描述
- Template Text:具體的模板內容
- 變量定義 變量形式為
$<variable_name>$
,點擊Edit variables
可設置變量具體內容:

image
- Name:變量名
- Expression:變量表現
- Default value:默認值
- Skip if defined:是否跳過編輯已經定義的值
- 模板應用環境 點擊
No application contexts yet. Define
,設置為 java 環境:

image
- 模板文件 構建了模板 group 後,在
android studio configtemplates
目錄下查看到yanxuan.xml
。 windows:C:Users\<user>\.AndroidStudiox.xconfigtemplates
(user 為你的計算機用戶名) mac:~/Library/Preferences/AndroidStudiox.x/templates
<templateSet group="test"> <template name="yxtest" value="testMethod($a$, $b$);" description="這是一個測試模板" toReformat="false" toShortenFQNames="true"> <variable name="a" expression="lineNumber()" defaultValue="2" alwaysStopAt="false" /> <variable name="b" expression="" defaultValue="" alwaysStopAt="true" /> <context> <option name="JAVA_CODE" value="true" /> <option name="JAVA_STATEMENT" value="true" /> <option name="JAVA_EXPRESSION" value="true" /> <option name="JAVA_DECLARATION" value="true" /> <option name="JAVA_COMMENT" value="true" /> <option name="JAVA_STRING" value="true" /> <option name="COMPLETION" value="true" /> </context> </template> </templateSet>
- 設置完畢,實踐查看:

image yxtest

image singleton
3.2 Android Studio Template
- 背景 除了
Live Template
之外,工程項目中很多新建的類也有很多機械的代碼,如我們定義的 Activity 要麼繼承自BaseBlankActivity
,要麼繼承自BaseActionBarActivity
,另外項目中採用MVP
模式,因此一個 Activity 基本上會有一個對應的presenter
類,一個layout
文件,同時很多時候,一個頁面中會有一個需要支持刷新的RecycleView
等。除此之外,ViewHolder
、HttpTask
等代碼也是固定模式的代碼。 這些都是固定機械的代碼,而如果是人肉去寫的話,難免會出現代碼風格不一致、不規範的情況,同時也浪費了一部分的時間。所幸,Android Studio 提供了工程類模板,方便我們實現這樣的功能。 - 系統模板 查看 Android Studio 系統類模板,我們能發現有很多定義好的類模板:

image 如需要創建一個空的 Activity 頁面,可以選擇 Empty Activity
,並填寫類名,layout 名稱等信息,之後就能出現對應的添加或修改:MainActivity.java
、activity_main.xml
、AndroidManifest.xml
:

image 而這些模板定義,可以在相關路徑文件中找到: < >Windows: ${Android Studio 的安裝目錄}/plugins/android/lib/templates/
Mac: Android Studio.app/Contents/plugins/android/lib/templates/

image
針對 EmpytActivity 這裡需要定義的文件有: < >globals.xml.ftl
:定義當前模板的一些全局變量recipe.xml.ftl
:定義模板拷貝的邏輯等template.xml
:定義模板對話框的樣式template_blank_activity.png
:定義模板的圖標root/src/app_package/SimpleActivity.java.ftl
:具體的模板文件

image16
圖片來自:http://www.slideshare.net/murphonic/custom-android-code-templates-15537501
- 自定義模板 而針對我們需要自定義的模板,可以在模板定義路徑下新建文件夾和文件即可,細節內容可查看 Tutorial How To Create Custom Android Code Templates 項目的模板文件內容:

image17
- 設置完模板文件之後,重啟 Android Studio,可以生效模板文件,使用模板文件如下:

- image18
4 編碼後期 – 靜態代碼檢查
由上,我們定義了編碼規範,定義了 Live Template 和 Android Studio Template 方便程序猿更好的准守我們的項目編碼規範。然後編碼規範畢竟只是軟規範,而提供編碼模板更多的解決大量 util 的使用問題和便利小夥伴完成機械編碼,並不能完全保證程序猿嚴格按照全部的規範來編碼。 為此,我們需要一套靜態代碼檢查機制能檢查已有的代碼是否遵守規範。總結已有的規範,可以將規範類型歸納為普通 Java 規範、普通 Android 規範、具體項目規範等。而這些檢查點,可以配合不同的檢查工具進行檢查。
4.1 檢查 java 代碼風格 – CheckStyle
對於 java
規範,checkstyle 幫助開發者實現常用的檢查。這裡 CheckStyle 能檢查的內容有:
- Javadoc 注釋
- 命名約定
- 標題
- Import 語句
- 體積大小
- 空白
- 修飾符
- 塊
- 代碼問題
- 類設計
- 混合檢查(包活一些有用的比如非必須的System.out和printstackTrace)
檢查內容很多,而檢查項需要和具體的項目規範做結合。如,每行代碼字符數控制在 80,單頁代碼行數控制在 800 等。因此需要結合配置文件,來檢查項目中的 java 代碼。在 Android Studio 上配置 CheckStyle 流程如下:
- 在 Android Studio 中添加 gradle Plugin
apply plugin: 'checkstyle'
- 設置 CheckStyle 版本
checkstyle { toolVersion '6.1.1' showViolations true }
- 配置 CheckStyle 檢查項
task checkstyle(type: Checkstyle) { configFile file("$configDir/checkstyle/checkstyle.xml") configProperties.checkstyleSuppressionsPath = file("$configDir/checkstyle/suppressions.xml").absolutePath source 'src' include '**/*.java' // 檢查 java 代碼 exclude '**/gen/**' // 排除生成的代碼 classpath = files() ignoreFailures true // 忽略檢查失敗的情況,避免gradle命令執行中止 }
- 配置自定義的檢查項:
checkstyle.xml
:<!--單個文件方法數上限最多為 30--> <module name="MethodCount"> <property name="maxTotal" value="30"/> </module> <!--方法名的首字母是小寫--> <module name="MethodName"> <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> </module> <!--靜態變量名的首字符是 s--> <module name="StaticVariableName"> <property name="format" value="^[a-z][a-zA-Z0-9]*$"/> <property name="applyToPublic" value="true"/> <property name="applyToProtected" value="true"/> <property name="applyToPackage" value="true"/> <property name="applyToPrivate" value="true"/> </module> <!--只有私有構造函數的類需要定義成 final 類型--> <module name="FinalClass"/> ...
具體其他的檢查項配置可以查看 檢查配置鏈接 - 執行 checkstyle 檢查
./gradlew checkstyle
- 查看檢查結果 命令執行結束,查看檢查結果文件:
${project}/app/build/reports/checkstyle/checkstyle.html

- image
4.2 檢查 java 代碼質量 – FindBugs
與 CheckStyle
工具不同的是,FindBugs
不注重樣式或者格式,而是試圖尋找出真正的缺陷或者現在的性能問題。FindBugs
檢查類和 Jar
文件,不是通過分析類文件的形式或結構來分析程序,而是使用 Visitor
模式,將位元組碼與一組缺陷模式進行對比以發現可能的問題。而這些問題比如如下:
- 1. 忽略返回值

image 上述代碼執行結束之後,並沒有什麼意義,變量 a
的值也不會變成 dddbbbccc
。因此,上述代碼很可能是程序猿的 bug。為此 FindBugs 能找出這種問題
- 2. 空指針示例

image 上述最後一行代碼,很明顯在執行的時候會發生空指針異常,這裡因為 FindBugs 無法知道變量 strMaps
是否確實有 aaa
這個 key,為此這裡會檢查出錯誤。
- 3. 未初始化的成員變量使用

- image
- 這裡由於類成員變量
actions
並未初始化,因此當actions.add("TEST")
被執行的時候會發生異常。
Android Studio 上 FindBugs 的集成如下:
- 在 gradle 中引入插件
apply plugin: 'findbugs'
- 在 gradle 中配置 findbugs task
task findbugs(type: FindBugs, dependsOn: "assembleDebug") { ignoreFailures = false effort = "max" reportLevel = "high" excludeFilter = new File("$configDir/findbugs/findbugs-filter.xml") classes = files("${project.rootDir}/app/build/intermediates/classes") source 'src' include '**/*.java' exclude '**/gen/**' reports { xml.enabled = false html.enabled = true xml { destination "$reportsDir/findbugs/findbugs.xml" } html { destination "$reportsDir/findbugs/findbugs.html" } } classpath = files() ignoreFailures true // 避免檢查失敗 gradle 執行中止 }
- 執行 findbugs 檢查
./gradlew findbugs
- 查看檢查結果 查看檢查結果文件:
${project}/app/build/reports/findbugs/findbugs.html

image
4.3 檢查 Android 代碼質量 – Lint
4.3.1 基本介紹
前面 FindBugs
的檢查實例(忽略返回值
, 未初始化的成員變量使用
),可以發現在 Android Studio IDE 上,已經出現了標黃提示,我們把光標放上去,就能看到具體的提示了:

image
按 cmd + F1
可以看到具體的錯誤提示:

image
這就原生 Lint
給我們提供的錯誤提示功能。除了和 FindBugs
重複的純 java
代碼檢查之外,Lint 能檢查很多其他工具無法檢查的內容,也更貼合 Android:

image
在 Activity 內定義非靜態內部類 Handler 的報警

image
在
AndroidManifest.xml
中定義 export 為 true 的廣播接受器,但沒有定義權限,Lint 檢查認為是不安全的

image
build.gradle 文件中引用的 support 包的版本低的提示
Android Lint 是一個靜態代碼檢查工具,能夠對潛在的 bug,可能的安全性、性能、可用性、可訪問性、國際化等優化內容做出監測:

image
來自官方文檔 Improve Your Code with Lint
- App Source Files:工程中的源文件,包括 java 代碼、資源 xml 代碼、gradle 文件,圖片資源文件以及 progroud 等文件
- lint.xml:配置文件,配置哪些 lint 檢查可以排除,自定義問題的嚴重級別
- lint Tool:靜態代碼檢查工具,可以是命令行或者集成在 Android Studio 上
- lint Output:代碼檢查結果,可以直接顯示在 Console 上,也可以是
lint-result.html
4.3.2 原生 Lint 檢查
在 Android SDK Tools 16 及更高的版本中,Lint 工具會自動安裝。原生 Lint 的檢查項已經有 200 多項 (包括前面示例的 5 項內容),因此使用原生的功能點,就能檢查開發中的大部分通用問題。
- Android Studio IDE 上配置 Lint 檢查偏好設置 (Mac 下)
Preferences
→Editor
→Inspections
進入Android Studio
的Lint
配置界面

image
- A:配置 Profile,方便不同項目或者不同情況下使用不同的 Profile 進行檢查
- B:Lint 檢查點 Group
- C:Lint 檢查點具體描述
- D:Lint 檢查點警告級別設置
- E:Lint 檢查點開關
lint.xml
上配置 Lint 除了可以通過 IDE 配置 Lint,還可以通過直接 lint.xml 為單個項目配置檢查規則<?xml version="1.0" encoding="UTF-8"?> <lint> <!-- Disable the given check in this project --> <issue id="IconMissingDensityFolder" severity="ignore" /> <!-- Ignore the ObsoleteLayoutParam issue in the specified files --> <issue id="ObsoleteLayoutParam"> <ignore path="res/layout/activation.xml" /> <ignore path="res/layout-xlarge/activation.xml" /> </issue> <!-- Ignore the UselessLeaf issue in the specified file --> <issue id="UselessLeaf"> <ignore path="res/layout/main.xml" /> </issue> <!-- Change the severity of hardcoded strings to "error" --> <issue id="HardcodedText" severity="error" /> </lint>
來源 Android Develop 文檔 Improve Your Code with Lint- gradle 中配置 Lint task
android { lintOptions { abortOnError false // 配置 lint 過程中出錯,不中止 gradle 任務 xmlReport false htmlReport true lintConfig file("$configDir/lint/lint.xml") // 配置 lint 檢查規則 htmlOutput file("$reportsDir/lint/lint-result.html") // 配置 lint 輸出文件 xmlOutput file("$reportsDir/lint/lint-result.xml") // 配置 lint 輸出文件 } }
- 執行檢查 在工程根目錄執行以下命令 (Mac),以執行檢查任務
./gradlew lint
- 檢查結果 生成的檢查結果在
${項目工程}/app/build/reports/lint/lint-result.html

image
4.3.3 自定義 Lint 檢查
雖然原生的 Lint 檢查已經很強大了,檢查項也已經很多,然而還是無法滿足項目中的特有需求:
- log 統一使用
LogUtil
- 對應 Activity 的 layout 命名為
activity_XXX
- 對應 Fragment 的 layout 命名為
fragment_XXX
- Activity 必須派生自
BaseBlankActivity
或BaseActionBarActivity
對於以上這些需求,原生 Lint 檢查(包括 CheckStyle
,FindBugs
)就已經無能為力了,我們必須編碼支持自定義檢查。以項目中集成的 Lint 檢查為例,講述流程:
4.3.3.1 配置 Gradle,引入 lint
庫
dependencies { ... compile 'com.android.tools.lint:lint-api:24.5.0' compile 'com.android.tools.lint:lint-checks:24.5.0' }
- lint-api: 官方給出的API,API並不是最終版,官方提醒隨時有可能會更改API接口。
- lint-checks:已有的檢查。
4.3.3.2 定義 IssueRegistry
類
新建一個 MyIssueRegistry
類,繼承自 IssueRegistry
。用來註冊我們自定義的全部 issue
public class MyIssueRegistry extends IssueRegistry { @Override public List<Issue> getIssues() { System.out.println("********YXLint rules works!!!********"); return Arrays.asList( LogUsageDetector.ISSUE, ToastUsageDetector.ISSUE, ActivitySuperClassDetector.ACTIVITY_SUPER_CLASS_ISSUE, ... BuildGradleVersionDetector.ISSUE); } }
其中:
LogUsageDetector.ISSUE
:用於檢查不允許直接使用Log.*
方式輸出本地日誌的代碼ToastUsageDetector.ISSUE
:用於檢查直接用Toast
方式顯示 toast 的代碼ActivitySuperClassDetector.ACTIVITY_SUPER_CLASS_ISSUE
:用於檢查 Activity 的基類BuildGradleVersionDetector.ISSUE
:用於檢查 gradle 文件中不允許直接寫數字版本號的代碼
4.3.3.3 gradle 清單項中註冊前面定義的 IssueRegistry
類
jar { manifest { attributes('Lint-Registry': 'com.netease.htlint.lintrules.MyIssueRegistry') } }
4.3.3.4 定義 Detector
MyIssueRegistry
類中聲明註冊了各個 Detector
的 Issue
。Issue
由 Detector
發現並報告,是 Android 程序代碼可能存在的風險。而這裡就需要真正實現這些 Detector
,以檢查 Activity 的基類為例。

image
ACTIVITY_SUPER_CLASS_ISSUE
這個 Issue
的定義需要使用 Issue.create(...)
方式實現,同時需要傳入 6 個參數分別如下:
- A:一個固定的唯一的 id 代表這個
Issue
- B:對於問題的簡短總結,描述問題而不是修復措施
- C:完整的問題解釋和修復建議
- D:問題類別,現在已有的問題類別有如下
- Lint
- Correctness (incl. Messages)
- Security
- Performance
- Usability (incl. Icons, Typography)
- Accessibility
- Internationalization
- Bi-directional text
- E:優先級,必須在1到10之間,10為最重要/最嚴重。
- F:嚴重級別,可選值有
Fatal
,Error
,Warning
,Informational
,Ignore
- G:為
Issue
和Detector
提供映射關係,Detector
就是當前類。聲明掃描檢測的範圍Scope
,描述Detector
需要分析時需要考慮的文件集,包括:Resource
文件或目錄、Java
文件、Class
文件
ActivitySuperClassDetector
繼承自 Detector
,並實現 Detector.JavaScaner
。這裡主要自定義實現的方法如上圖 H,I
- H:檢查類的基類是 "android.support.v4.app.Activity" 或 "android.app.Activity"
- I:具體檢查類的方法,這裡需要排除非 yanxuan 包名下的代碼,判斷當前類的基類是否是
BaseBlankActivity
或BaseActionBarActivity
?如果都不是的話,則報告錯誤 - J:報出問題的方法:該方法中指定參數有:
- 需要報錯的 Issue
- 發生問題的代碼在語法樹上的節點
- 發生問題的代碼位置
- 警告的信息
4.3.3.5 生成 jar 包
完成上述步驟,可以在控制台中通過命令 ../../gradlew assemble
來執行編譯任務,就可以輸出我們需要的 jar 文件 (htlintrules_jar-0.0.1.jar
) 了
4.3.3.6 jar 的使用
按照 Google 方法,可以將 htlintrules_jar-0.0.1.jar
拷貝到 ~/.android/lint
中,但缺點是針對會影響一台機器其他的工程。很明顯,我們的自定義 Lint
檢查有很多是項目中特有的一些編碼規範。 為此,我們採用 LinkedIn
方案:將 jar 放到一個 aar 中。這樣我們就可以針對工程進行自定義 Lint,lint.jar 只對當前工程有效。 在現有的 htlintrules_jar
工程的 build.gradle 中添加代碼,整體看起來如下:
apply plugin: 'java' apply plugin: 'maven' dependencies { compile 'com.android.tools.lint:lint-api:24.5.0' compile 'com.android.tools.lint:lint-checks:24.5.0' } jar { manifest { attributes('Lint-Registry': 'com.netease.htlint.lintrules.MyIssueRegistry') } } configurations { lintJarOutput } dependencies { lintJarOutput files(jar) } defaultTasks 'assemble'
同時新建另一個工程 htlint
,在其 build.gradle
文件中添加如下代碼:
/* * rules for including "lint.jar" in aar */ configurations { lintJarImport } dependencies { lintJarImport project(path: ':htlintrules_jar', configuration: "lintJarOutput") } task copyLintJar(type: Copy) { from (configurations.lintJarImport) { rename { String fileName -> 'lint.jar' } } into 'build/intermediates/lint/' } project.afterEvaluate { def compileLintTask = project.tasks.find { it.name == 'compileLint' } compileLintTask.dependsOn(copyLintJar) }
最後在 app 工程的 build.gradle
中添加 htlint 引用,配置完成
dependencies { compile project(':htlint') // lint 檢查庫 ... }
4.3.3.7 自定義 Lint 檢查執行及結果檢查
在 ${項目工程}/app/
目錄下執行 ../gradlew lint
:

image
根據提示查看 lint-result.html
文件,可以查看到前面編寫的 ActivitySuperClassDetector.ACTIVITY_SUPER_CLASS_ISSUE
已經生效,並且檢查出了相關的非規範代碼。

image

image
4.3.3.8 排除錯誤的檢查結果
前面很好的給出了檢查結果了,然而我們會發現,FullScreenVideoActivity
確實是需要的錯誤檢查結果,而 WXEntryActivity
卻不是,這個類是有集成微信分享時需要的,並且按照微信開放平台的文檔來編寫,因此並不需要按照項目規範,繼承 BaseBlankActivity
或 BaseActionBarActivity
。為此,我們期望 WXEntryActivity
不應該被檢查出 WrongActivitySuperClass
錯誤 為此,我們可以在 WXEntryActivity
類名簽名添加 SuppressLint
註解:
@SuppressLint("WrongActivitySuperClass") public class WXEntryActivity extends Activity implements IWXAPIEventHandler{ ... }
- 排除 java 類或者方法的 Lint 檢查 若需要抑制某個 Issue 檢查,可以在類定義簽名或者方法定義簽名,添加註解
@SuppressLint(${IssueId})
。這裡設置的就是具體某個Issue
的id
值 若需要抑制全部的 Issue 檢查,可以使用all
關鍵字,比如:@SuppressLint("all")
- 排除 xml 資源的 Lint 檢查 如項目中引入微博分享 sdk,按照官方文檔,需要在 AndroidManifest 中聲明
com.sina.weibo.sdk.net.DownloadService
這個 Service,而這個 Service 會被 Lint 檢查為未定義,為此需要 xml 文件中也過濾部分代碼的 Lint 的檢查:<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.netease.yanxuan"> ... <service android:name="com.sina.weibo.sdk.net.DownloadService" android:exported="false" tools:ignore="MissingRegistered" /> </manifest>
這裡對於單個 Issue 過濾的規則為:tools:ignore=${IssueId}
如果需要過濾全部的 Issue,可以使用all
關鍵字:tools:ignore="all"
4.4 其他代碼檢查工具
4.4.1 360 火線
360 火線 是 360 公司和信息安全部門深度合作,定製的適用於 360 公司產品的安卓 APP 安全檢查規則。總共覆蓋 61 項代碼檢查。使用也非常方便,細節看 使用文檔,可以直接使用 jar 包並執行命令或集成 Android Studio Plugin 執行檢查

image
4.4.2 pmd
pmd 代碼檢查工具,包含 16 個規則集,涵蓋了 Java 的各種常見問題。其中規則集包含 基本(rulesets/basic.xml)
,終結函數(finalizer)
,未使用的代碼(rulesets/unusedcode.xml)
,設計(rulesets/design.xml)
等。 相比 FindBugs
,pmd
的一些規則更具爭議,但 pmd
支持我們構建自己的規則集
<?xml version="1.0"?> <ruleset name="customruleset"> <description> Sample ruleset for developerWorks article </description> <rule ref="rulesets/design.xml"/> <rule ref="rulesets/naming.xml"/> <rule ref="rulesets/basic.xml"/> </ruleset>
4.5 代碼檢查工具整合及集成 jenkins
為整合這些檢查工具,在 gradle
中自定義 check 命名,並依賴其他的 task。在執行檢查的時候,可以通過 ./gradlew check
來執行全部的檢查命令。
check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint'
另一方面,這種代碼檢查,如果等到開發完成的時候再去執行,很可能問題積累了很多,甚至導致產品上線前,開發並不能來得及修正全部的問題。為此,可以將代碼檢查的命令集成 jenkins
,保證開發每天都能看到當前的代碼的缺陷,能及時的修改
5 總結
我們從編碼前的編碼規範,編碼進行中的編碼模板,編碼結束後的代碼靜態檢查,保障了程序小夥伴們的代碼。除此之外,還有很多不完善的地方需要我們做進一步處理:
- 和特定項目相關的自定義 Lint 檢查項,僅支持了一部分的編碼規範,自定義 Lint 檢查項需要後續完成
- 雖然檢查工具很多,檢查的結果內容也很多,而很明顯,這些檢查工具相互之間是有重複的情況(主要是純 java 代碼部分的檢查),因此如果整理檢查結果,並過濾出我們真正關心的問題,也是後續需要完成的內容
星雲測試
http://www.teststars.cc
奇林軟件
http://www.kylinpet.com
聯合通測
http://www.quicktesting.net