记录使用 SwiftLint检测代码内的硬编码字符串

花了 N多天的时间,总算达到了预期的效果(并没有,依旧有很多问题,加了很多特殊代码的排除规则,但也算基本能用了),记录一下,希望能帮到有类似需求的iOSer吧。

SwiftLint: github.com/realm/Swift...

1,先使用命令行安装 SwiftLint工具,命令如下:

复制代码
brew install swiftlint

2,在项目内接入 SwiftLint,可使用 Cocoapods,我使用的 SPM接入;

3,在项目根目录下(与.xcodeproj文件同层级)创建 .swiftlint.yml文件;

4,将下述规则代码粘贴进去,因为我这边的项目是 SwiftUI,所以控件都是用的 SwiftUI相关的。如果使用的是 UIKit,则需要替换一下;

SwiftLint 复制代码
only_rules:
  - custom_rules

excluded:
  - "**/Tests/**"
  - "**/UITests/**"
  - "**/Pods/**"
  - "**/DerivedData/**"

custom_rules:
  check_hardcoded_strings:
    name: "Hardcoded String"
    regex: '(?<!LocalizedStringKey\()(Text\(\s*"(?!.*[\\$]\(.*?\))([^"\\]|\\.)+"\s*\)|(Label|TextField|TextEditor|Alert|Picker|Menu|contextMenu|toolbar|navigationTitle|alert|confirmationDialog|prompt|navigationBarTitle|tabItem|Section|Toggle|ProgressView|Link|Gauge|DatePicker|Stepper|ColorPicker|SecureField|GroupBox|DisclosureGroup|OutlineGroup|LabeledContent)\([^)]*"(?!\s*$)(?!.*(systemImage|imageNamed|systemName|NSLocalizedString\s*\(|localizedString|String\.localized|DateFormatter\.\w+\.string\())[^"\n]+"[^)]*\))'
    message: "Avoid hard-coded strings and use localized strings instead."
    severity: error
    exclude:
      # SF Symbols icons
      - '\.(systemImage|symbolName)\s*:\s*"[a-z]+(\.[a-z]+)+"' # Match all SF Symbols formats
      - 'Label\([^,]+,\s*systemImage\s*:\s*"[^"]+"\)' # Enhanced Label detection
      - 'Image\(systemName:\s*"[^"]+"\)' # Cover all Image initializations
      
      # Image sources
      - 'image(Name[d]?|Resource|Path)\s*[:=]\s*"[^"]+"'
      - '\.image\(\s*"[^"]+"\)'
      
      # Basic exclusions
      - 'Text\(\s*"\s*"\s*\)' # Match empty strings and whitespace-only
      - 'Text\("[0-9]+(\.[0-9]+)?"\)' # Numbers
      - '([+]\s*Text\(\s*"\s*"\s*\))|(Text\(\s*"\s*"\s*\)\s*[+])' # Handle concatenation scenarios
      - '(?s)(HStack|VStack|ZStack)\s*\{.*?Text\(\s*"\s*"\s*\).*?\}' # Nested structure detection
      
      # Dynamic content exclusions
      - 'Text\(\s*[a-zA-Z_]\w*\s*\)' # Text(variable)
      - 'Text\(".*?[\\$]\(.*?\).*?"\)' # Any interpolation ($ or backslash)
      - 'Text\(\s*".*?\\.*?"\s*\)' # Contains escape characters
      
      # Special control handling
      - "\\bButton\\("
      - "\\bnavigationBarItems\\("
      - "TextField\\(\\s*\"\"\\s*,.*\\)"
      - "NavigationLink\\(\\s*\"\"\\s*,.*\\)"
      - "\\.accessibilityLabel\\(Text\\(.*\\)\\)"
      - "Group\\s*\\{.*?Text\\(.*?\\).*?\\}"
      
      # Other exclusions
      - "(?s)/\\*.*?\\*/"
      - "//.*?(\\n|$)"
      - "case\\s+\""
      - "@selector\\("
      - "(#if DEBUG)(.|[\\r\\n])*?(#endif)"
      - "(?s)preview\\s*\\{.*?\\}"
      - "assert\\(.*\\)"
      - "fatalError\\(.*\\)"
      - "UserDefaults\\.standard\\.string\\(forKey:.*\\)"
      - "Notification\\.Name\\(rawValue:.*\\)"
      - "NSLocalizedString\\([^)]*\\)"

5,在项目 Target - Build Phase内新增一个 New Run Script Phase,用来在编译时运行脚本代码;

6,在这个脚本内贴入下述代码,这里要注意 SwiftLint在 M芯片和 Intel芯片的 Mac上的安装路径是不一致的:

bash 复制代码
# Type a script or drag a script file from your workspace to insert its path.
SWIFTLINT_PATHS=(
  "/opt/homebrew/bin/swiftlint"  # the path fot M-series chip
  "/usr/local/bin/swiftlint"     # the path for Intel chip
)

CONFIG="${SRCROOT}/.swiftlint.yml"
SOURCES="${SRCROOT}"

# Trying to find out an available path
SWIFTLINT=""
for path in "${SWIFTLINT_PATHS[@]}"; do
  if [ -f "$path" ]; then
    SWIFTLINT="$path"
    break
  fi
done

echo "=== CHECK SWIFTLINT ENV ==="
echo "SwiftLint path: $SWIFTLINT"

if [ -n "$SWIFTLINT" ]; then
  echo "SwiftLint version: $($SWIFTLINT version)"
  "$SWIFTLINT" lint \
    --config "$CONFIG" \
    "$SOURCES" \
    --strict
  exit $?
else
  echo "error: SwiftLint not found. Please install it using: brew install swiftlint"
  exit 1
fi

7,将这个脚本拖拽到 Compile Sources之前,在编译之前就运行;

8,Command + B,如果代码内有硬编码字符串,应该就会提示报错了。此外如果要修改 .swiftlint.yml文件内的规则,修改规则后务必要先 Clean Build Folder,然后再 Command + B,不然有可能会不生效。

相关推荐
杂雾无尘2 小时前
iOS 分享扩展(四):让分享扩展与主应用无缝衔接
ios·swift·apple
烈焰晴天2 小时前
新发布的一款使用ReactNative新架构加载Svga动画的开源插件[android/ios]
android·react native·ios
前端与小赵2 小时前
ios如何把H5网页变成主屏幕webapp应用
ios·web app
章鱼paul帝4 小时前
iOS 启动优化之自注册--attribute(section)
ios·性能优化
大熊猫侯佩6 小时前
SwiftUI 中无法对添加模糊(blur)效果视图截图的初步解决
swiftui·swift·apple
大熊猫侯佩6 小时前
Swift 异步序列 AsyncStream 新“玩法”以及内存泄漏、死循环那些事儿(下)
swift·编程语言·apple
大熊猫侯佩6 小时前
Swift 异步序列 AsyncStream 新“玩法”以及内存泄漏、死循环那些事儿(上)
swift·编程语言·apple
依旧风轻7 小时前
ChangeNotifierProvider 本质上也是 Widget
flutter·ios·dart·widget·changenotifier·provider·sqi
杂雾无尘1 天前
iOS 分享扩展(三):轻松定制 iOS 分享界面,提升用户体验
ios·swift·apple