Hotaru's Notebook

XcodeGen: For people who hate Xcode

在过去 3 个月里我接触了 iOS app 开发, 这段学习 iOS 开发的时间让我对 Apple Inc. 的评价跌落 到了谷底。
在 Apple 刚发布第一代 iPhone 的时候, 我周围就有越来越多的人开始吹捧 Apple, 说 iPhone 多么 多么好用。Apple 能让大多数人认可 iPhone 这款产品说明它的确做得不错, 但这群果粉逐渐的开始变质 了, 它们变得开始听不得别人不认可 iPhone, 听不得半点有关 iPhone 的坏话, 颇有苏联垬的味道。
自从 Steve Jobs 死了以后我就越来越讨厌 Apple, 不只是因为 Apple 用户社区容不得其它声音, Apple 的产品一直都是把复杂的东西用美好的装饰隐藏起来并且阻止任何人去揭开那层装饰。iOS 就是一个 有代表性的操作系统, 它的可定制性几乎为 0, 出了问题就要花钱去找 Genius Bar。

直到我接触了 iOS app 开发。不得不说, Xcode 可能是我用过的所有 IDE 里最难用的, 不止是 Xcode 无响应或崩溃, 第二让我崩溃的是 xcodeproj 在 VSC 合并代码的时候非常容易出现冲突, 而且这种 冲突不是轻易就能解决的那种。有时候我改错了什么东西后想回到之前的状态, 连的 Cmd+Z 都没的用, 只能通过 git 命令来恢复。

为了解决绕开这个问题, 我尝试了个软件叫 Tuist, 用了一段时间后发现它还是有些 bug 导致项目 无法正常编译, 于是我就改用了 XcodeGen
XcodeGen 存在的目的就是替代 xcodeproj 并且成为工程内 “single source of truth”。
但它也带来了一些缺点。我的一个同事就抱怨 XcodeGen 反而把 GUI 的部分变得复杂化了, 但我愿意接触 复杂的事物来换取工程的可重现的构建性(eproducable Build)。

关于 XcodeGen 的用法可以阅读它的 Project SpecUsage
下面我贴一部分已经用在实际项目的 project.yml 作为示例:

name: "demo-app"
options:
  minimumXcodeGenVersion: "2.26.0"
  createIntermediateGroups: true
  # If you use a bundleId starts with `com.exmaple` your app won't launch and
  # Xode won't tell you that.
  bundleIdPrefix: "com.exmaple.demo-app"
  xcodeVersion: "13.0"
  groupSortPosition: "top"
  deploymentTarget:
    iOS: "11.0"
  findCarthageFrameworks: false
targets:
  DemoApp:
    type: application
    platform: "iOS"
    deploymentTarget: "11.0"
    sources:
      - path: "DemoApp/src"
        includes:
          - "**/*.h"
      - path: "DemoApp/src"
        includes:
          - "**/*.c"
          - "**/*.m"
      - path: "DemoApp/res"
    dependencies:
      - sdk: "StoreKit.framework"
      - framework: "Carthage/Build/FBLPromises.xcframework"
      - framework: "Carthage/Build/FBLFunctional.xcframework"
      - framework: "Carthage/Build/MMWormhole.xcframework"
    settings:
      "PRODUCT_BUNDLE_IDENTIFIER": "com.example.demo-app"
      "IPHONEOS_DEPLOYMENT_TARGET": "11.0"
      "DEVELOPMENT_TEAM": "TEAM_ID_HERE"
      "CODE_SIGN_ENTITLEMENTS": "DemoApp/App.entitlements"
      "TARGETED_DEVICE_FAMILY": "1" # Build for iPhone only.
      # A workaroud of the stupid xcode.
      # See: https://stackoverflow.com/questions/63267897/building-for-ios-simulator-but-the-linked-framework-framework-was-built
      "VALIDATE_WORKSPACE": true
      "ONLY_ACTIVE_ARCH": true
      "ENABLE_BITCODE": true
      "MARKETING_VERSION": "0.0.1"
      "VALID_ARCHS": "arm64 arm64e"
      "USER_HEADER_SEARCH_PATHS":
        - "$(SRCROOT)/DemoApp/src"
    info:
      path: "DemoApp/Info.plist"
      properties:
        "CFBundleIdentifier": "com.example.demo-app"
        "CFBundleName": "DemoApp"
        "CFBundleDisplayName": "$(EXECUTABLE_NAME)"
        "CFBundlePackageType": "$(PRODUCT_BUNDLE_PACKAGE_TYPE)"
        "CFBundleShortVersionString": "$(MARKETING_VERSION)"
        "UISupportedInterfaceOrientations":
          - "UIInterfaceOrientationPortrait"
        "UISupportedInterfaceOrientations~ipad":
          - "UIInterfaceOrientationPortrait"
        "UIRequiredDeviceCapabilities": ["arm64"]
        "UILaunchStoryboardName": "LaunchScreen"
        "UIMainStoryboardFile": "Main"
        "LSRequiresIPhoneOS": true
    entitlements:
      path: "DemoApp/App.entitlements"
      properties:
        "com.apple.security.application-groups":
          - "group.YOUR_TEAM_ID.com.example.demo-app"

前面提到了 “第二让我崩溃的东西是 xcodeproj”, 那第一让我崩溃的也是到目前为止最让我哭笑不得的 就是调试 iOS App Extension 完全就是靠猜以及靠猜积累起来的经验。抽空我会写一篇关于如何 Debug App Extension 的文章。

#Coding #Xcode #Apple #Objective-C