實戰iOS-objectivec&swift靜態程式碼分析

樂少發表於2019-03-06
在此感謝前交友事業部小夥伴:HaiYi、LV、Yong,曾經的協助!

本文主要闡述使用SonarQube構建iOS:Objective-C、Swift靜態程式碼分析,包括分享遇到的坑,文章有限,一些細節不能到位的,請各位腦補下,謝謝。

SonarQube簡介

舊版Sonar展示維度如下(當時應該是11年左右開始使用的):

舊版sonar展示維度

新版SonarQube已經改變了關注維度,推出質量模型:
  • Bugs:是出現了明顯錯誤或是高度近似期望之外行為的程式碼。
  • 漏洞:是指程式碼中可能出現被黑客利用的潛在風險點。
  • 壞味道:程式碼異味會困擾程式碼的維護者並降低他們的開發效率。主要的衡量標準是修復它們所需的時間。
建議根據團隊需要更新到新版本:至少5.6+以上。
新版SonarQube質量模型

SonarQube架構

SonarQube平臺的組成:
  • 資料庫:存放SoanrQube的配置資料,程式碼質量的快照資料
  • Web服務:用於檢視SonarQube配置資料,程式碼質量的快照資料
  • 分析器:對專案程式碼進行分析,生成質量結果資料並存於資料庫中
  • 外掛:各種語言支援的外掛
不要忽略了CI:
雖然SonarQube具備分析器,可以對多種程式語言進行構建分析,但是依然建議使用CI工具,例如Jenkins來管理日常構建,讓SonarQube僅僅展示最終資料即可。

iOS靜態程式碼分析

目前iOS核心開發語言:Objective-C,也有不少專案採用了Swift語言,逐步過渡,因此專案的組成有兩種模式:
  • 單一語言使用:Objective-C、Swift
  • 混合語言使用:Objective-C+Swift
下面通過實戰分析兩種模式的構建。

iOS靜態程式碼分析的計劃

Objective-C原以為就跟Java構建一樣,如此簡單,
美好的計劃
實際遇到的坑是很大的,而且很受傷,
踩過坑的路才踏實

捅一萬刀也不過分

iOS靜態程式碼分析:Objective-C實戰

工欲善其事必先利其器,工具如下:
  • 環境工具:XCode 8.2+、Xcpretty 0.2.8、OCLint 0.12、xctool、gcovr
  • 構建靜態分析外掛
  • SonarCFamily:
  • 官方外掛太貴了,找開源吧
  • 開源SonarQube Plugin for Objective C(傳送門
  • 外掛安裝參考網上教程,下載jar拷貝到SonarQube專案目錄下:extensions/plugins
安裝成功的示例

  • 構建指令碼
  • run-sonar.sh
  • 在Jenkins的Execute shell配置指令碼如下,也可以按照專案要求重名更好格式
    cd $WORKSPACE

    xcodebuild -workspace xxx.xcworkspace -scheme xxx clean build | tee xcodebuild.log | xcpretty --report json-compilation-database


    mv build/reports/compilation_db.json compile_commands.json


    oclint-json-compilation-database -exclude Pods -- -report-type pmd -o oclint.xml -max-priority-1 99999 -max-priority-2 99999 -max-priority-3 99999 -rc LONG_LINE=140 -rc LONG_METHOD=80 -rc NCSS_METHOD=50 -rc SHORT_VARIABLE_NAME=1 -rc CYCLOMATIC_COMPLEXITY=13 -rc MINIMUM_CASES_IN_SWITCH=2 -rc NPATH_COMPLEXITY=1500


    rm -rf sonar-reports

    mkdir sonar-reports


    cat oclint.xml  | sed "s#Switch Statements Should Have Default Rule#switch statements should have default#g" \

    | sed "s#missing hash method#must override hash with isEqual#g" \

    | sed "s#prefer early exits and continue#use early exits and continue#g" \

    | sed "s#use boxed expression#replace with boxed expression#g" \

    | sed "s#use container literal#replace with container literal#g" \

    | sed "s#use number literal#replace with number literal#g" \

    | sed "s#use object subscripting#replace with object subscripting#g" \

    | sed "s#missing default in switch statements#switch statements should have default#g" \

    | sed "s#unnecessary default statement in covered switch statement#switch statements don't need default when fully covered#g" \

    | sed "s#covered switch statements dont need default#switch statements don't need default when fully covered#g" > sonar-reports/oclint.xml


    rm -f sonar-project.properties 

    cat > sonar-project.properties <<- EOF 

    sonar.projectKey=xxx-iOS

    sonar.projectName=xxx-iOS 

    sonar.projectVersion=x.x.x

    sonar.language=objectivec 

    sonar.sources=sources 

    sonar.sourceEncoding=UTF-8 

    sonar.objectivec.oclint.reportPath=sonar-reports/oclint.xml 

    EOF 


    /bin/sh sonar-scanner -X複製程式碼
  • 構建結果
  • 獨門絕技介紹(感謝交友事業部:haiyi大神傾親奉獻)
  • 構建錯誤errors generated
    3 errors generated.

    20 errors generated.

    20 errors generated.

    20 errors generated.

    8 errors generated.

    19 errors generated.

    3 errors generated.

    63 errors generated.複製程式碼
檢查OCLint,升級到0.12版本,與XCode8.2+配合
  • 構建錯誤does not exist
    The rule 'OCLint:use number literal' does not exist.

    The rule 'OCLint:use object subscripting' does not exist.

    The rule 'OCLint:ill-placed default label in switch statement' does not exist.

    The rule 'OCLint:Switch Statements Misplaced Default Label' does not exist.複製程式碼
主要原因是sonar-objective-c-plugin-0.5.0-SNAPSHOT.jar中未包含此規則,可以通過修改原始碼新增規則解決(網上有一堆教程),比較繁瑣的是,不同專案遇到不同錯誤,需要新增多次,則多次打包jar,再匯入SonarQube,開銷大,haiyi大大給的祕籍是:用sed替換構建的oclint.xml檔案
    sed "s#missing hash method#must override hash with isEqual#g"複製程式碼
將缺失規則:missing hash method,替換為:must override hash with isEqual,每次遇到有缺失的新規則,指令碼替換即可,至於怎麼準確匹配,去看看質量配置的具體含義再替換。

  • Objective-C實戰總結
    • 安裝構建工具所需版本號
    • xcodebuild構建專案生成compile_commands.json
    • oclint-json-compilation-database構建compile_commands.json生成oclint.xml
    • sed替換oclint.xml缺失規則
    • sonar-project.properties配置oclint.xml檔案路徑
    • /bin/sh sonar-scanner -X 增加-X輸出debug日誌跟蹤

iOS靜態程式碼分析:Swift實戰

工欲善其事必先利其器,工具如下:
  • 環境工具
    brew install Swiftlint

    gem install slather

    sudo pip install lizard複製程式碼
  • 構建靜態分析外掛
  • SonarSwifty:

  • 官方外掛太貴了,找開源吧
安裝成功的示例

  • 構建指令碼
  • run-sonar.sh
  • 在Jenkins的Execute shell配置指令碼如下,也可以按照專案要求重名更好格式
    cd $WORKSPACE

    rm -rf kuai-swiftlint.txt

    swiftlint lint --path Duobao > xxx-swiftlint.txt


    rm -rf sonar-project.properties

    cat > sonar-project.properties <<- EOF

    sonar.projectKey=xxx-iOS-swift

    sonar.projectName=xxx-iOS-swift

    sonar.projectVersion=x.x.x

    sonar.language=swift

    sonar.projectDescription=xxx with Swift

    sonar.sources=sources

    sonar.swift.workspace=xxx.xcworkspace

    sonar.swift.appScheme=xxx

    sonar.sourceEncoding=UTF-8

    sonar.swift.swiftlint.report=xxx-swiftlint.txt

    EOF

    /bin/sh sonar-scanner -X複製程式碼
  • 構建結果

  • 注意事項
  • In SonarQube under Quality Profiles the used Linter can be specified by selecting either the SwiftLint Profile or the Tailor Profile as Default profile for Swift Projects:
  • 如果不設定,關聯規則有問題
  • 目前暫無遇到缺失規則問題


  • Swift實戰總結
    • 安裝構建工具所需版本號
    • swiftlint生成xxx-swiftlint.txt
    • sonar-project.properties配置xxx-swiftlint.txt檔案路徑
    • /bin/sh sonar-scanner -X 增加-X輸出debu

iOS靜態程式碼分析:Objective-C+Swift實戰

這裡不詳細介紹實戰過程,直接說總結
  • Objective-C+Swift:分開構建,指令碼如下,當做兩個專案配置如上文所示
  • Objective-C+Swift:一起構建,本質上他們兩個的外掛是不同的,但是可以利用sonar模組的概念來構建
    ObjectiveC_Swift目錄結構

    --ObjectiveC:完整專案檔案

    --Swift:完整專案檔案複製程式碼
  • 指令碼如下
    sonar.projectKey=objectivec_swift

    sonar.projectName=objectivec_swift

    sonar.projectVersion=1.9.0

    sonar.sourceEncoding=UTF-8

    #分模組

    sonar.modules=objective,swift


    #構建objectivec

    objective.sonar.projectName=objectivec

    objective.sonar.language=objectivec

    objective.sonar.projectBaseDir=objectivec

    objective.sonar.sources=sources

    objective.sonar.oclint.reportPath=sonar-reports/oclint.xml


    #構建swift

    swift.sonar.projectName=swift

    swift.sonar.language=swift

    swift.sonar.sources=sources

    swift.sonar.projectBaseDir=swift

    swift.sonar.swift.workspace=swift/xxx.xcworkspace

    swift.sonar.swift.appScheme=Duobao

    swift.sonar.sourceEncoding=UTF-8

    swift.sonar.swift.swiftlint.report=swift/xxx-swiftlint.txt複製程式碼
  • 構建結果
沒有看到掃描規則問題展示,估計是配置檔案或者構建檔案路徑有問題,暫且告一段落吧,有折騰出來的小夥伴喊一下,謝謝喲,^_^

微信公眾號:樂少黑板報


相關文章