日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

swift 项目_如何对iOS项目进行静态分析

發(fā)布時(shí)間:2025/3/20 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 swift 项目_如何对iOS项目进行静态分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

隨著項(xiàng)目的擴(kuò)大,依靠人工codereview來(lái)保證項(xiàng)目的質(zhì)量,越來(lái)越不現(xiàn)實(shí),這時(shí)就有必要借助于一種自動(dòng)化的代碼審查工具:程序靜態(tài)分析。

程序靜態(tài)分析(Program Static Analysis)是指在不運(yùn)行代碼的方式下,通過(guò)詞法分析、語(yǔ)法分析、控制流、數(shù)據(jù)流分析等技術(shù)對(duì)程序代碼進(jìn)行掃描,驗(yàn)證代碼是否滿足規(guī)范性、安全性、可靠性、可維護(hù)性等指標(biāo)的一種代碼分析技術(shù)。(來(lái)自百度百科)

詞法分析,語(yǔ)法分析等工作是由編譯器進(jìn)行的,所以對(duì)iOS項(xiàng)目為了完成靜態(tài)分析,我們需要借助于編譯器。對(duì)于OC語(yǔ)言的靜態(tài)分析可以完全通過(guò)Clang,對(duì)于Swift的靜態(tài)分析除了Clange還需要借助于SourceKit。

Swift語(yǔ)言對(duì)應(yīng)的靜態(tài)分析工具是SwiftLint,OC語(yǔ)言對(duì)應(yīng)的靜態(tài)分析工具有Infer和OCLitn。以下會(huì)是對(duì)各個(gè)靜態(tài)分析工具的安裝和使用做一個(gè)介紹。

SwiftLint

對(duì)于Swift項(xiàng)目的靜態(tài)分析可以使用SwiftLint。SwiftLint 是一個(gè)用于強(qiáng)制檢查 Swift 代碼風(fēng)格和規(guī)定的一個(gè)工具。它的實(shí)現(xiàn)是 Hook 了 Clang 和 SourceKit 從而能夠使用 AST 來(lái)表示源代碼文件的更多精確結(jié)果。Clange我們了解了,那SourceKit是干什么用的?

SourceKit包含在Swift項(xiàng)目的主倉(cāng)庫(kù),它是一套工具集,支持Swift的大多數(shù)源代碼操作特性:源代碼解析、語(yǔ)法突出顯示、排版、自動(dòng)完成、跨語(yǔ)言頭生成等工作。

安裝

安裝有兩種方式,任選其一: 方式一:通過(guò)Homebrew

$ brew install swiftlint

這種是全局安裝,各個(gè)應(yīng)用都可以使用。 方式二:通過(guò)CocoaPods

pod 'SwiftLint', :configurations => ['Debug']

這種方式相當(dāng)于把SwiftLint作為一個(gè)三方庫(kù)集成進(jìn)了項(xiàng)目,因?yàn)樗皇钦{(diào)試工具,所以我們應(yīng)該將其指定為僅Debug環(huán)境下生效。

集成進(jìn)Xcode

我們需要在項(xiàng)目中的Build Phases,添加一個(gè)Run Script Phase。如果是通過(guò)homebrew安裝的,你的腳本應(yīng)該是這樣的。

if which swiftlint >/dev/null; thenswiftlint elseecho "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" fi

如果是通過(guò)cocoapods安裝的,你得腳本應(yīng)該是這樣的:

"${PODS_ROOT}/SwiftLint/swiftlint"

運(yùn)行SwiftLint

鍵入CMD + B編譯項(xiàng)目,在編譯完后會(huì)運(yùn)行我們剛才加入的腳本,之后我們就能看到項(xiàng)目中大片的警告信息。有時(shí)候build信息并不能填入項(xiàng)目代碼中,我們可以在編譯的log日志里查看。

定制

SwiftLint規(guī)則太多了,如果我們不想執(zhí)行某一規(guī)則,或者想要濾掉對(duì)Pods庫(kù)的分析,我們可以對(duì)SwfitLint進(jìn)行配置。

在項(xiàng)目根目錄新建一個(gè).swiftlint.yml文件,然后填入如下內(nèi)容:

disabled_rules: # rule identifiers to exclude from running- colon- trailing_whitespace- vertical_whitespace- function_body_length opt_in_rules: # some rules are only opt-in- empty_count# Find all the available rules by running:# swiftlint rules included: # paths to include during linting. `--path` is ignored if present.- Source excluded: # paths to ignore during linting. Takes precedence over `included`.- Carthage- Pods- Source/ExcludedFolder- Source/ExcludedFile.swift- Source/*/ExcludedFile.swift # Exclude files with a wildcard analyzer_rules: # Rules run by `swiftlint analyze` (experimental)- explicit_self# configurable rules can be customized from this configuration file # binary rules can set their severity level force_cast: warning # implicitly force_try:severity: warning # explicitly # rules that have both warning and error levels, can set just the warning level # implicitly line_length: 110 # they can set both implicitly with an array type_body_length:- 300 # warning- 400 # error # or they can set both explicitly file_length:warning: 500error: 1200 # naming rules can set warnings/errors for min_length and max_length # additionally they can set excluded names type_name:min_length: 4 # only warningmax_length: # warning and errorwarning: 40error: 50excluded: iPhone # excluded via stringallowed_symbols: ["_"] # these are allowed in type names identifier_name:min_length: # only min_lengtherror: 4 # only errorexcluded: # excluded via string array- id- URL- GlobalAPIKey reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)

一條rules提示如下,其對(duì)應(yīng)的rules名就是function_body_length。

! Function Body Length Violation: Function body should span 40 lines or less excluding comments and whitespace: currently spans 43 lines (function_body_length)

disabled_rules下填入我們不想遵循的規(guī)則。

excluded設(shè)置我們想跳過(guò)檢查的目錄,Carthage、Pod、SubModule這些一般可以過(guò)濾掉。

其他的一些像是文件長(zhǎng)度(file_length),類型名長(zhǎng)度(type_name),我們可以通過(guò)設(shè)置具體的數(shù)值來(lái)調(diào)節(jié)。

另外SwiftLint也支持自定義規(guī)則,我們可以根據(jù)自己的需求,定義自己的rule。

生成報(bào)告

如果我們想將此次分析生成一份報(bào)告,也是可以的(該命令是通過(guò)homebrew安裝的swiftlint):

# reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown) $ swiftlint lint --reporter html > swiftlint.html

xcodebuild

xcodebuild是xcode內(nèi)置的編譯命令,我們可以用它來(lái)編譯打包我們的iOS項(xiàng)目,接下來(lái)介紹的Infer和OCLint都是基于xcodebuild的編譯產(chǎn)物進(jìn)行分析的,所以有必要簡(jiǎn)單介紹一下它。

一般編譯一個(gè)項(xiàng)目,我們需要指定項(xiàng)目名,configuration,scheme,sdk等信息以下是幾個(gè)簡(jiǎn)單的命令及說(shuō)明。

# 不帶pod的項(xiàng)目,target名為T(mén)argetName,在Debug下,指定模擬器sdk環(huán)境進(jìn)行編譯 xcodebuild -target TargetName -configuration Debug -sdk iphonesimulator # 帶pod的項(xiàng)目,workspace名為T(mén)argetName.xcworkspace,在Release下,scheme為T(mén)argetName,指定真機(jī)環(huán)境進(jìn)行編譯。不指定模擬器環(huán)境會(huì)驗(yàn)證證書(shū) xcodebuild -workspace WorkspaceName.xcworkspace -scheme SchemeName Release # 清楚項(xiàng)目的編譯產(chǎn)物 xcodebuild -workspace WorkspaceName.xcworkspace -scheme SchemeName Release clean

之后對(duì)xcodebuild命令的使用都需要將這些參數(shù)替換為自己項(xiàng)目的參數(shù)。

Infer

Infer是Facebook開(kāi)發(fā)的針對(duì)C、OC、Java語(yǔ)言的靜態(tài)分析工具,它同時(shí)支持對(duì)iOS和Android應(yīng)用的分析。對(duì)于Facebook內(nèi)部的應(yīng)用像是 Messenger、Instagram 和其他一些應(yīng)用均是有它進(jìn)行靜態(tài)分析的。它主要檢測(cè)隱含的問(wèn)題,主要包括以下幾條:

  • 資源泄露,內(nèi)存泄露
  • 變量和參數(shù)的非空檢測(cè)
  • 循環(huán)引用
  • 過(guò)早的nil操作

暫不支持自定義規(guī)則。

安裝及使用

$ brew install infer

運(yùn)行infer

$ cd projectDir # 跳過(guò)對(duì)Pods的分析 $ infer run --skip-analysis-in-path Pods -- xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator

我們會(huì)得到一個(gè)infer-out的文件夾,里面是各種代碼分析的文件,有txt,json等文件格式,當(dāng)這樣不方便查看,我們可以將其轉(zhuǎn)成html格式:

$ infer explore --html

點(diǎn)擊trace,我們會(huì)看到該問(wèn)題代碼的上下文。

因?yàn)镮nfer默認(rèn)是增量編譯,只會(huì)分析變動(dòng)的代碼,如果我們想整體編譯的話,需要clean一下項(xiàng)目:

$ xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator clean

再次運(yùn)行Infer去編譯。

$ infer run --skip-analysis-in-path Pods -- xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator

Infer的大致原理

Infer的靜態(tài)分析主要分兩個(gè)階段:

1、捕獲階段

Infer 捕獲編譯命令,將文件翻譯成 Infer 內(nèi)部的中間語(yǔ)言。

這種翻譯和編譯類似,Infer 從編譯過(guò)程獲取信息,并進(jìn)行翻譯。這就是我們調(diào)用 Infer 時(shí)帶上一個(gè)編譯命令的原因了,比如: infer -- clang -c file.c, infer -- javac File.java。結(jié)果就是文件照常編譯,同時(shí)被 Infer 翻譯成中間語(yǔ)言,留作第二階段處理。特別注意的就是,如果沒(méi)有文件被編譯,那么也沒(méi)有任何文件會(huì)被分析。

Infer 把中間文件存儲(chǔ)在結(jié)果文件夾中,一般來(lái)說(shuō),這個(gè)文件夾會(huì)在運(yùn)行 infer 的目錄下創(chuàng)建,命名是 infer-out/。

2、分析階段

在分析階段,Infer 分析 infer-out/ 下的所有文件。分析時(shí),會(huì)單獨(dú)分析每個(gè)方法和函數(shù)。

在分析一個(gè)函數(shù)的時(shí)候,如果發(fā)現(xiàn)錯(cuò)誤,將會(huì)停止分析,但這不影響其他函數(shù)的繼續(xù)分析。

所以你在檢查問(wèn)題的時(shí)候,修復(fù)輸出的錯(cuò)誤之后,需要繼續(xù)運(yùn)行 Infer 進(jìn)行檢查,知道確認(rèn)所有問(wèn)題都已經(jīng)修復(fù)。

錯(cuò)誤除了會(huì)顯示在標(biāo)準(zhǔn)輸出之外,還會(huì)輸出到文件 infer-out/bug.txt 中,我們過(guò)濾這些問(wèn)題,僅顯示最有可能存在的。

在結(jié)果文件夾中(infer-out),同時(shí)還有一個(gè) csv 文件 report.csv,這里包含了所有 Infer 產(chǎn)生的信息,包括:錯(cuò)誤,警告和信息。

OCLint

OCLint是基于Clange Tooling編寫(xiě)的庫(kù),它支持?jǐn)U展,檢測(cè)的范圍比Infer要大。不光是隱藏bug,一些代碼規(guī)范性的問(wèn)題,例如命名和函數(shù)復(fù)雜度也均在檢測(cè)范圍之內(nèi)。

安裝OCLint

OCLint一般通過(guò)Homebrew安裝

$ brew tap oclint/formulae $ brew install oclint

通過(guò)Hombrew安裝的版本為0.13。

$ oclint --version LLVM (http://llvm.org/):LLVM version 5.0.0svn-r313528Optimized build.Default target: x86_64-apple-darwin19.0.0Host CPU: skylakeOCLint (http://oclint.org/):OCLint version 0.13.Built Sep 18 2017 (08:58:40).

我分別用Xcode11在兩個(gè)項(xiàng)目上運(yùn)行過(guò)OCLint,一個(gè)實(shí)例項(xiàng)目可以正常運(yùn)行,另一個(gè)復(fù)雜的項(xiàng)目卻運(yùn)行失敗,報(bào)如下錯(cuò)誤:

1 error generated 1 error generated ... oclint: error: cannot open report output file ..../onlintReport.html

我并不清楚原因,如果你想試試0.13能否使用的話,直接跳到安裝xcpretty。如果你也遇到了這個(gè)問(wèn)題,可以回來(lái)安裝oclint0.15版本。

OCLint0.15

我在oclint issuse #547這里找到了這個(gè)問(wèn)題和對(duì)應(yīng)的解決方案。

我們需要更新oclint至0.15版本。brew上的最新版本是0.13,github上的最新版本是0.15。我下載github上的release0.15版本,但是這個(gè)包并不是編譯過(guò)的,不清楚是不是官方自己搞錯(cuò)了,只能手動(dòng)編譯了。因?yàn)榫幾g要下載llvm和clange,這兩個(gè)包較大,所以我將編譯過(guò)后的包直接傳到了這里CodeChecker。

如果不關(guān)心編譯過(guò)程,可以下載編譯好的包,跳到設(shè)置環(huán)境變量那一步。

編譯OCLint

1、安裝CMake和Ninja這兩個(gè)編譯工具

$ brew install cmake ninja

2、clone OCLint項(xiàng)目

$ git clone https://github.com/oclint/oclint

3、進(jìn)入oclint-scripts目錄,執(zhí)行make命令

$ ./make

成功之后會(huì)出現(xiàn)build文件夾,里面有個(gè)oclint-release就是編譯成功的oclint工具。

設(shè)置oclint工具的環(huán)境變量

設(shè)置環(huán)境變量的目的是為了我們能夠快捷訪問(wèn)。然后我們需要配置PATH環(huán)境變量,注意OCLint_PATH的路徑為你存放oclint-release的路徑。將其添加到.zshrc,或者.bash_profile文件末尾:

OCLint_PATH=/Users/zhangferry/oclint/build/oclint-release export PATH=$OCLint_PATH/bin:$PATH

執(zhí)行source .zshrc,刷新環(huán)境變量,然后驗(yàn)證oclint是否安裝成功:

$ oclint --version OCLint (http://oclint.org/): OCLint version 0.15. Built May 19 2020 (11:48:49).

出現(xiàn)這個(gè)介紹就說(shuō)明我們已經(jīng)完成了安裝。

安裝xcpretty

xcpretty是一個(gè)格式化xcodebuild輸出內(nèi)容的腳本工具,oclint的解析依賴于它的輸出。它的安裝方式為:

$ gem install xcpretty

OCLint的使用

在使用OCLint之前還需要一些準(zhǔn)備工作,需要將編譯項(xiàng)COMPILER_INDEX_STORE_ENABLE設(shè)置為NO。

  • 將 Project 和 Targets 中 Building Settings 下的 COMPILER_INDEX_STORE_ENABLE 設(shè)置為 NO
  • 在 podfile 中 target 'target' do 前面添加下面的腳本,將各個(gè)pod的編譯配置也改為此選項(xiàng)
post_install do |installer|installer.pods_project.targets.each do |target|target.build_configurations.each do |config|config.build_settings['COMPILER_INDEX_STORE_ENABLE'] = "NO"endend end

使用方式

1、進(jìn)入項(xiàng)目根目錄,運(yùn)行如下腳本:

$ xcodebuild -workspace ProjectName.xcworkspace -scheme ProjectScheme -configuration Debug -sdk iphonesimulator | xcpretty -r json-compilation-database -o compile_commands.json

會(huì)將xcodebuild編譯過(guò)程中的一些信息記錄成一個(gè)文件compile_commands.json,如果我們?cè)陧?xiàng)目根目錄看到了該文件,且里面是有內(nèi)容的,證明我們完成了第一步。

2、我們將這個(gè)json文件轉(zhuǎn)成方便查看的html,過(guò)濾掉對(duì)Pods文件的分析,為了防止行數(shù)上限,我們加上行數(shù)的限制:

$ oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html -rc LONG_LINE=9999 -max-priority-1=9999 -max-priority-2=9999 -max-priority-3=9999

最終會(huì)產(chǎn)生一個(gè)oclintReport.html文件。

OCLint支持自定義規(guī)則,因?yàn)槠浔旧硪?guī)則已經(jīng)很豐富了,自定義規(guī)則的需求應(yīng)該很小,也就沒(méi)有嘗試。

封裝腳本

OCLint跟Infer一樣都是通過(guò)運(yùn)行幾個(gè)腳本語(yǔ)言進(jìn)行執(zhí)行的,我們可以將這幾個(gè)命令封裝成一個(gè)腳本文件,以O(shè)CLint為例,Infer也類似:

#!/bin/bash # mark sure you had install the oclint and xcpretty# You need to replace these values with your own project configuration workspace_name="WorkSpaceName.xcworkspace" scheme_name="SchemeName"# remove history rm compile_commands.json rm oclint_result.xml # clean project # -sdk iphonesimulator means run simulator xcodebuild -workspace $workspace_name -scheme $scheme_name -configuration Debug -sdk iphonesimulator clean || (echo "command failed"; exit 1);# export compile_commands.json xcodebuild -workspace $workspace_name -scheme $scheme_name -configuration Debug -sdk iphonesimulator | xcpretty -r json-compilation-database -o compile_commands.json || (echo "command failed"; exit 1);# export report html # you can run `oclint -help` to see all USAGE oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html -disable-rule ShortVariableName -rc LONG_LINE=1000 || (echo "command failed"; exit 1);open -a "/Applications/Safari.app" oclintReport.html

oclint-json-compilation-database命令的幾個(gè)參數(shù)說(shuō)明:

-e 需要忽略分析的文件,這些文件的警告不會(huì)出現(xiàn)在報(bào)告中

-rc 需要覆蓋的規(guī)則的閥值,這里可以自定義項(xiàng)目的閥值,默認(rèn)閥值

-enable-rule 支持的規(guī)則,默認(rèn)是oclint提供的都支持,可以組合-disable-rule來(lái)過(guò)濾掉一些規(guī)則 規(guī)則列表

-disable-rule 需要忽略的規(guī)則,根據(jù)項(xiàng)目需求設(shè)置

在Xcode中使用OCLint

因?yàn)镺CLint提供了xcode格式的輸出樣式,所以我們可以將它作為一個(gè)腳本放在Xcode中。

1、在項(xiàng)目的 TARGETS 下面,點(diǎn)擊下方的 "+" ,選擇 cross-platform 下面的 Aggregate。輸入名字,這里命名為 OCLint

2、選中該Target,進(jìn)入Build Phases,添加Run Script,寫(xiě)入下面腳本:

# Type a script or drag a script file from your workspace to insert its path. # 內(nèi)置變量 cd ${SRCROOT} xcodebuild clean xcodebuild | xcpretty -r json-compilation-database oclint-json-compilation-database -e Pods -- -report-type xcode

可以看出該腳本跟上面的腳本一樣,只不過(guò) 將oclint-json-compilation-database命令的-report-type由html改為了xcode。而OCLint作為一個(gè)target本身就運(yùn)行在特定的環(huán)境下,所以xcodebuild可以省去配置參數(shù)。

3、通過(guò)CMD + B我們編譯一下項(xiàng)目,執(zhí)行腳本任務(wù),會(huì)得到能夠定位到代碼的warning信息:

總結(jié)

以下是對(duì)這幾種靜態(tài)分析方案的對(duì)比,我們可以根據(jù)需求選擇適合自己的靜態(tài)分析方案。

SwiftLintInferOCLint支持語(yǔ)言SwiftC、C++、OC、JavaC、C++、OC易用性簡(jiǎn)單較簡(jiǎn)單較簡(jiǎn)單能否集成進(jìn)Xcode可以不能集成進(jìn)xcode可以自帶規(guī)則豐富度較多,包含代碼規(guī)范相對(duì)較少,主要檢測(cè)潛在問(wèn)題較多,包含代碼規(guī)范規(guī)則擴(kuò)展性可以不可以可以

參考

OCLint 實(shí)現(xiàn) Code Review - 給你的代碼提提質(zhì)量

Using OCLint in Xcode

Infer 的工作機(jī)制

LLVM & Clang 入門(mén)

總結(jié)

以上是生活随笔為你收集整理的swift 项目_如何对iOS项目进行静态分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。