记录使用 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,不然有可能会不生效。

相关推荐
用户79457223954133 小时前
【AFNetworking】OC 时代网络请求事实标准,Alamofire 的前身
objective-c·swift
Hilaku4 小时前
做中后台业务,为什么我不建议你用 Tailwind CSS?
前端·css·代码规范
Digitally4 小时前
如何不用 iTunes 将 iPhone 备份到移动硬盘?
ios·iphone
sysinside4 小时前
Cisco Catalyst 9000 IOS XE 26.1.1 GA - 思科 Catalyst 9000 交换产品系列 IOS XE 系统软件
ios·cisco
低保和光头哪个先来5 小时前
解决 ios 使用 video 全屏未铺满页面问题
前端·javascript·vue.js·ios·前端框架
报错小能手5 小时前
SwiftUI 框架 认识 SwiftUI 视图结构 + 布局
ui·ios·swift
2501_915921436 小时前
HTTP和HTTPS协议全面解析:技术原理与安全应用
安全·http·ios·小程序·https·uni-app·iphone
悟空爬虫-彪哥6 小时前
VRCFaceTracking安装和iPhone面捕配置教程,有bug
ios·bug·iphone
想个名字想老半天6 小时前
uni离线打包实现 ios 支付StoreKit 2,其实没有想象中那么复杂,不需要写原生插件,不需要转 uts
macos·ios·cocoa
东坡肘子6 小时前
被 Vibe 摧毁的版权壁垒,与开发者的新护城河 -- 肘子的 Swift 周报 #131
人工智能·swiftui·swift