iOS应用如何使用命令行构建打包及上传AppStore

前言

我以往的工作经验主要是基于Android平台进行应用开发,Android平台的APK打包流程主要依赖于Gradle实现编译Debug/Release包,通过配置项目下的build.gradle.kts文件,可以很方便的完成打包和签名的操作。

Android打包依赖于gradle构建工具:

  • Debug打包
    • ./gradlew assembleDebug : 编译Debug包,一般使用debug.keystore(Android Debug包签名密钥)进行签名
    • ./gradlew bundleDebug : 编译Bundle包,一般用于Google Play应用商店的包发布
  • Release打包
    • ./gradlew assembleRelease : 编译Release包,一般使用relese.jks(自行生成的签名密钥)进行签名
    • ./gradlew bundleRelease: 编译Bundle的Release签名包,一般用于正式版本的发布

iOS打包依赖于xcodebuild构建工具:

  • xcodebuild build 编译项目生成可执行的.app文件(可用于编译检查、本地调试) -> 类似 Android 的 ./gradlew build 构建生成Debug包之类的
  • xcodebuild archive + -configuration Debug-configuration Release 生成归档文件iosApp.xcarchive -> 类似 Android 的 ./gradlew assembleDebug 或者 ./gradlew assembleRelease 生成.apk
  • xcodebuild -exportArchiveiosApp.xcarchive导出为.ipa文件并签名(通过配置ExportOptions.plist) -> 类似 Android 的 .apk.aab 的安装包

xcodebuildgradle 指令对比:

功能描述 xcodebuild 指令 gradlew 指令 说明
清理构建 xcodebuild clean ./gradlew clean 清除之前的构建产物
构建调试版 xcodebuild -configuration Debug ./gradlew assembleDebug 构建用于调试的版本
构建发布版 xcodebuild -configuration Release ./gradlew assembleRelease 构建用于发布的版本
生成归档文件 xcodebuild archive -archivePath <path> ./gradlew bundleRelease iOS生成xcarchive,Android生成aab
运行测试 xcodebuild test ./gradlew test 执行单元测试
构建并安装 xcodebuild install ./gradlew installDebug 构建并安装到设备
查看依赖 xcodebuild -list ./gradlew dependencies 查看项目依赖信息
检查签名 codesign --verify --deep --verbose=4 example.appcodesign --display -vvv example.app ./gradlew signingReport 验证签名信息

如果你刚好有一些Android的开发工作经验,对比上图基本上就能搞清楚iOS构建工具的使用了,虽然很相似,其实也差不多。

下面的内容主要是关于 iOS 应用编译的一些指令的说明,如果你看完上面的内容并且理解了,就可以直接基于实际的项目进行实践测试。毕竟实践出真知,每个人的环境都不一样~

xcodebuild 相关指令

列出iOS应用构建信息

主要功能

  • 解析项目的 Swift Package 依赖(显示在 Resolved source packages 部分)
  • 列出工作区所有可用 Scheme(显示在 Information about workspace 部分)

对于iOS项目,可以运行以下命令(如果应用更复杂且使用工作区,只需将 -project 替换为 -workspace <project>.xcworkspace 即可):

示例展示

# 这里是在KMP项目中的iosApp路径下执行如下指令
xcodebuild -list -project iosApp.xcodeproj

执行之后的结果如下:

Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -list -project iosApp.xcodeproj

User defaults from command line:
    IDEPackageSupportUseBuiltinSCM = YES

Resolve Package Graph


Resolved source packages:
  AppAuth: https://github.com/openid/AppAuth-iOS.git @ 1.7.5
  GTMSessionFetcher: https://github.com/google/gtm-session-fetcher.git @ 3.4.1
  GoogleSignIn: https://github.com/google/GoogleSignIn-iOS @ 7.1.0
  GTMAppAuth: https://github.com/google/GTMAppAuth.git @ 4.1.1

Information about project "iosApp":
    Targets:
        iosApp

    Build Configurations:
        Debug
        Release

    If no build configuration is specified and -scheme is not passed then "Release" is used.

    Schemes:
        AppAuth
        AppAuth-AppAuthCore_Privacy
        AppCheckCore
        ffmpeg-kit-ios-full-gpl
        Firebase
        FirebaseAnalytics
        FirebaseAppCheckInterop
        FirebaseAuth
        FirebaseAuth-FirebaseAuth_Privacy
        FirebaseAuthInterop
        FirebaseCore
        FirebaseCore-FirebaseCore_Privacy
        FirebaseCoreExtension
        FirebaseCoreExtension-FirebaseCoreExtension_Privacy
        FirebaseCoreInternal
        FirebaseCoreInternal-FirebaseCoreInternal_Privacy
        FirebaseCrashlytics
        FirebaseCrashlytics-FirebaseCrashlytics_Privacy
        FirebaseInstallations
        FirebaseInstallations-FirebaseInstallations_Privacy
        FirebaseRemoteConfigInterop
        FirebaseSessions
        GoogleAppMeasurement
        GoogleDataTransport
        GoogleDataTransport-GoogleDataTransport_Privacy
        GoogleSignIn
        GoogleSignIn-GoogleSignIn
        GoogleUtilities
        GoogleUtilities-GoogleUtilities_Privacy
        GTMAppAuth
        GTMAppAuth-GTMAppAuth_Privacy
        GTMSessionFetcher
        GTMSessionFetcher-GTMSessionFetcher_Core_Privacy
        iosApp
        MobileVLCKit
        nanopb
        nanopb-nanopb_Privacy
        Pods-iosApp
        PromisesObjC
        PromisesObjC-FBLPromises_Privacy
        PromisesSwift
        PromisesSwift-Promises_Privacy
        PurchasesHybridCommon
        PurchasesHybridCommon-PurchasesHybridCommon
        RecaptchaInterop
        RevenueCat
        RevenueCat-RevenueCat

以上是使用xcodebuild -list -project iosApp.xcodeproj的执行输出结果,下面我们来试一下使用iosApp.xcworkspace为目标来执行以下指令

# 如果iosApp路径下存在iosApp.xcworkspace则可以执行指令
xcodebuild -list -workspace iosApp.xcworkspace

执行之后的结果如下:

Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -list -workspace iosApp.xcworkspace

User defaults from command line:
    IDEPackageSupportUseBuiltinSCM = YES

Resolve Package Graph


Resolved source packages:
  GTMSessionFetcher: https://github.com/google/gtm-session-fetcher.git @ 3.5.0
  GoogleSignIn: https://github.com/google/GoogleSignIn-iOS @ 7.1.0
  GTMAppAuth: https://github.com/google/GTMAppAuth.git @ 4.1.1
  AppAuth: https://github.com/openid/AppAuth-iOS.git @ 1.7.5

Information about workspace "iosApp":
    Schemes:
        AppAuth
        AppAuth-AppAuthCore_Privacy
        AppCheckCore
        ffmpeg-kit-ios-full-gpl
        Firebase
        FirebaseAnalytics
        FirebaseAppCheckInterop
        FirebaseAuth
        FirebaseAuth-FirebaseAuth_Privacy
        FirebaseAuthInterop
        FirebaseCore
        FirebaseCore-FirebaseCore_Privacy
        FirebaseCoreExtension
        FirebaseCoreExtension-FirebaseCoreExtension_Privacy
        FirebaseCoreInternal
        FirebaseCoreInternal-FirebaseCoreInternal_Privacy
        FirebaseCrashlytics
        FirebaseCrashlytics-FirebaseCrashlytics_Privacy
        FirebaseInstallations
        FirebaseInstallations-FirebaseInstallations_Privacy
        FirebaseRemoteConfigInterop
        FirebaseSessions
        GoogleAppMeasurement
        GoogleDataTransport
        GoogleDataTransport-GoogleDataTransport_Privacy
        GoogleSignIn
        GoogleSignIn-GoogleSignIn
        GoogleUtilities
        GoogleUtilities-GoogleUtilities_Privacy
        GTMAppAuth
        GTMAppAuth-GTMAppAuth_Privacy
        GTMSessionFetcher
        GTMSessionFetcher-GTMSessionFetcher_Core_Privacy
        iosApp
        MobileVLCKit
        nanopb
        nanopb-nanopb_Privacy
        Pods-iosApp
        PromisesObjC
        PromisesObjC-FBLPromises_Privacy
        PromisesSwift
        PromisesSwift-Promises_Privacy
        PurchasesHybridCommon
        PurchasesHybridCommon-PurchasesHybridCommon
        RecaptchaInterop
        RevenueCat
        RevenueCat-RevenueCat
Note

可以看到这两个指令得到的结果是一致的,这个指令可以用于在CI的流程中获取当前项目的引入的包依赖及版本信息

关于以上输出内容,可以查看下面的技术分析

技术分析

以下是 xcodebuild -list 命令输出的详细技术解析,按模块分类说明:

  • 命令核心作用

执行的 xcodebuild -list -project iosApp.xcodeprojxcodebuild -list -workspace iosApp.xcworkspace 主要完成两个任务:

  1. 解析项目的 Swift Package 依赖(显示在 Resolved source packages 部分)
  2. 列出工作区所有可用 Scheme(显示在 Information about workspace 部分)
  • 依赖包解析结果

    关键包及作用

    包名 来源 典型用途
    GTMSessionFetcher Google 官方库 OAuth 网络请求基础组件
    GoogleSignIn Google 登录 SDK 应用内集成 Google 账号登录
    Firebase* Firebase 系列服务 数据分析、崩溃监控、认证等功能
    RevenueCat 第三方订阅管理平台 应用内购买与订阅系统集成
    MobileVLCKit VLC 开源播放器核心 视频播放功能支持
    ffmpeg-kit FFmpeg 多媒体框架封装 高级音视频编解码处理
  • 版本锁定机制

    • @ 3.5.0 等后缀表示 精确版本锁定,常见于以下情况:
      • 项目 Package.swift 中指定了精确版本(如 .exact("3.5.0")
      • CocoaPods 的 Podfile.lock 版本固化
      • 手动强制解析特定 commit
  • Scheme 清单分析

    Scheme 分类

    类型 示例 Scheme 说明
    主应用 Scheme iosApp 你的应用核心构建目标,对应 Xcode 中可运行的入口
    CocoaPods 生成 Pods-iosApp CocoaPods 集成时自动生成的聚合 Scheme,用于统一构建所有 Pod 依赖
    第三方库原生 Scheme FirebaseAnalyticsGoogleSignIn 依赖库自带的构建目标(通常用于库的独立测试或 Demo)
    隐私清单 Scheme FirebaseAuth-FirebaseAuth_Privacy Xcode 15+ 新特性,自动生成的隐私清单校验目标(用于 App Store 提交)
    模块化子组件 FirebaseCoreExtension 大型库(如 Firebase)拆分的子模块 Scheme
  • 开发者关注重点

    1. 构建选择

      • 日常开发:只需关注 iosApp Scheme,其他 Scheme 通常由系统自动管理
      • 特殊场景示例:
        # 单独构建 GoogleSignIn 的单元测试
        xcodebuild test -scheme GoogleSignIn -workspace iosApp.xcworkspace
        
    2. 依赖冲突排查

      若遇到类似错误: Multiple commands produce 'GTMSessionFetcher.framework' 需检查是否存在以下问题:

      • CocoaPods 与 Swift Package Manager 重复导入同一库
      • 不同库依赖同一子库但版本不兼容(如 Firebase 和 RevenueCat 对 Protobuf 版本的要求冲突)
    3. 隐私清单合规

      所有含 _Privacy 后缀的 Scheme 对应 Xcode 15 的 隐私清单强制校验App Store 中新增的隐私功能),需确保:

      • 第三方库已提供隐私清单(如 RevenueCat 已适配)
      • 未适配的库需要手动添加隐私声明

      关于更多隐私合规的问题可以查看 App Store 即将实行的要求

  • CI/CD 优化建议

    1. 构建加速

      xcodebuild archive 命令中添加参数排除无用构建:

      # 只构建主 Scheme,跳过检查其他依赖 Scheme
      xcodebuild archive -scheme iosApp -workspace iosApp.xcworkspace \
                         -skipUnavailableActions
      
    2. 依赖缓存

      对解析结果中的仓库 URL(如 https://github.com/google/gtm-session-fetcher.git)做镜像缓存,防止因网络问题导致解析失败:

      # 示例:GitLab CI 缓存配置
      variables:
        SPM_CACHE_PATH: "./spm_cache"
      
      cache:
        paths:
          - $SPM_CACHE_PATH
      
      script:
        - xcodebuild -resolvePackageDependencies -workspace iosApp.xcworkspace \
                     -clonedSourcePackagesDirPath "$SPM_CACHE_PATH"
      

通过这份解析,你可以清晰掌握项目的依赖结构和构建入口,同时为后续的持续集成与代码审计提供基础数据支撑。

清理指令

如果你想确保项目的构建从零开始,可以使用以下单行命令来清理之前的构建工件:

xcodebuild clean
Tip

xcodebuild clean 指令可以理解为类似于Android编译中的 ./gradlew clean 操作

执行xcodebuild clean指令后,将获得如下输出结果:

Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild clean

User defaults from command line:
    IDEPackageSupportUseBuiltinSCM = YES

Resolve Package Graph


Resolved source packages:
  GoogleSignIn: https://github.com/google/GoogleSignIn-iOS @ 7.1.0
  AppAuth: https://github.com/openid/AppAuth-iOS.git @ 1.7.5
  GTMAppAuth: https://github.com/google/GTMAppAuth.git @ 4.1.1
  GTMSessionFetcher: https://github.com/google/gtm-session-fetcher.git @ 3.4.1


** CLEAN SUCCEEDED **

编译指令

xcodebuild build

  • 用途
    • 编译项目并生成可执行文件(如 .app),主要用于本地测试或调试。
  • 输出结果
    • 生成二进制文件(.app)和调试符号(.dSYM,仅限某些配置),存储在 DerivedData(~/Library/Developer/Xcode/DerivedData)目录中。
    • 不会生成分发包或归档文件。
  • 典型场景
    • 在模拟器或真机上运行应用。
    • 快速验证代码变更是否编译通过。
  • 项目案例
    xcodebuild build -scheme "iosApp" -sdk iphoneos -destination generic/platform=iOS
    
  • 指令特点
    • 默认使用 Debug 配置(可手动指定为 Release)。
    • 不强制验证代码签名(如为 Debug 模式使用开发证书)。

xocdebuild archive

  • 用途
    • 编译项目并生成 .xcarchive 归档文件,专为分发应用(如提交至 App StoreTestFlight)或生成 IPA 包设计。
  • 输出结果
    • 生成 .xcarchive 文件,包含:
      • 应用二进制文件(.app)。
      • 调试符号(.dSYM)。
      • 资源文件(如图标、资产)。
      • 元数据(版本号、构建配置等)。
    • 归档文件默认存储在 ~/Library/Developer/Xcode/Archives
  • 典型场景
    • 准备提交到 App Store Connect。
    • 生成 Ad Hoc 或 Enterprise 分发的 IPA 文件。
  • 项目案例
    xcodebuild archive -scheme "iosApp" -sdk iphoneos -destination generic/platform=iOS -configuration Release -archivePath ../archive/iOS/20250309/iosApp.xcarchive
    
  • 指令特点
    • 通常要求 Release 配置。
    • 强制验证代码签名(需正确的分发证书和配置文件)。
    • 支持后续通过 -exportArchive 生成 IPA 包。

关键区别总结

维度 xcodebuild build xcodebuild archive
主要目的 本地运行、调试 分发应用(App Store、TestFlight 等)
输出产物 .app(在 DerivedData 目录) .xcarchive 归档文件
代码签名验证 可选(依赖配置) 强制(需有效分发证书)
典型配置 Debug(默认) Release
后续步骤 直接安装到设备 通过 -exportArchive 生成 IPA 文件

进阶说明

  • 归档与 IPA 生成: 执行 archive 后,通常需要配合 xcodebuild -exportArchive.xcarchive 转换为 .ipa 文件,例如:

    xcodebuild -exportArchive -archivePath iosApp.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath Output/
    

    其中 ExportOptions.plist 定义了分发方式(App Store、Ad Hoc 等)。

  • 调试支持.xcarchive 包含的 .dSYM 文件可用于符号化崩溃日志,是线上问题排查的关键。

通过合理选择命令,可高效完成开发调试与分发包准备工作。

生成 .ipa

配置 ExportOptions.plist 文件

最终,你需要创建iOS App 的 .ipa 文件,但是你需要一个 ExportOptions.plist 文件。

这个文件是通过XCode进行应用编译和归档后生成的。大致上的结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>compileBitcode</key>
  <false/>
  <key>method</key>
  <string>debugging</string>
  <key>signingStyle</key>
  <string>automatic</string>
  <key>stripSwiftSymbols</key>
  <true/>
  <key>teamID</key>
  <string>YOUR_TEAM_ID</string>
  <key>testFlightInternalTestingOnly</key>
  <false/>
  <key>uploadSymbols</key>
  <false/>
</dict>
</plist>

这是一个 Xcode 导出选项配置文件(ExportOptions.plist),主要用于在 自动化构建CI/CD 流程 中定义 iOS/Mac 应用的打包和签名规则。

以下是关键参数的解析:

  • 核心作用

    该文件通过 xcodebuild -exportOptionsPlist 参数使用,控制以下行为:

    xcodebuild -exportArchive \
               -archivePath iosApp.xcarchive \
               -exportOptionsPlist ExportOptions.plist \  # 指定此文件
               -exportPath Output/
    
  • 参数详解

    参数名称 说明
    compileBitcode false 禁用 Bitcode 编译,加速构建,但提交 App Store 时必须设为 true
    method debugging 导出方式:调试模式(仅限设备调试,不能上架)
    signingStyle automatic 自动签名(Xcode 自动选择证书和描述文件)
    stripSwiftSymbols true 移除 Swift 符号,减小包体积(Release 建议开启)
    teamID YOUR_TEAM_ID 开发者团队 ID(需替换为实际值,如 ABCDE12345
    testFlightInternalTestingOnly false 禁用仅限 TestFlight 内部测试成员分发(设为 true 限制测试范围)
    uploadSymbols false 不上传调试符号文件(Release 需设为 true 以支持崩溃分析)
  • 典型使用场景

    1. 本地调试构建 禁用 Bitcode 和符号上传,快速生成调试包。
    2. CI/CD 测试环境 配合自动化工具(如 Fastlane/Jenkins),确保每次构建签名配置一致。
    3. 内部分发限制 若需限制 TestFlight 测试范围,可将 testFlightInternalTestingOnly 设为 true
  • 注意事项

    1. 签名方式选择
      • 若需手动指定证书,应将 signingStyle 改为 manual 并添加 signingCertificate 参数。
      • 自动签名依赖本地或 CI 环境的钥匙串中存在有效证书。
    2. App Store 提交要求
      • 正式包必须开启 compileBitcode=trueuploadSymbols=true
      • method 需改为 app-store
    3. 多环境配置 建议为不同环境(Debug/Release)创建多个 plist 文件,例如:
      • ExportOptions-Debug.plist
      • ExportOptions-Release.plist
  • 扩展配置项

    可添加更多参数实现高级控制:

    <!-- 指定分发渠道 -->
    <key>destination</key>
    <string>export</string>
    
    <!-- 手动指定描述文件 -->
    <key>provisioningProfiles</key>
    <dict>
      <key>com.yourcompany.app</key>
      <string>Profile Name</string>
    </dict>
    
    <!-- 启用Bitcode -->
    <key>compileBitcode</key>
    <true/>
    
    <!-- 设置iCloud容器 -->
    <key>iCloudContainerEnvironment</key>
    <string>Development</string>
    
Important

建议通过 Xcode 生成标准模板:

Product > Archive > Distribute App > Export > 选择选项后生成 ExportOptions.plist

示例展示

执行指令:

xcodebuild -exportArchive -archivePath ../archive/iOS/20250309/iosApp.xcarchive -exportOptionsPlist ../archive/iOS/ExportOptionsManual.plist -exportPath ../archive/iOS/20250309

生成结果:

.
├── DistributionSummary.plist
├── ExportOptions.plist
├── Packaging.log
└── example.ipa

以下是通过 xcodebuild -exportArchive 操作后生成的四个核心文件的解析,按实际使用场景分类说明:

  • DistributionSummary.plist

    • 定位: 分发元数据报告
    • 内容结构:
      <dict>
        <key>Team</key>           <!-- 开发者团队名称 -->
        <key>TeamID</key>         <!-- 团队ID (如YOUR_TEAM_ID) -->
        <key>SigningCertificate</key> <!-- 签名证书SHA-1指纹 -->
        <key>Thinning</key>       <!-- 设备裁剪信息 (arm64等) -->
        <key>AppName</key>        <!-- 应用显示名称 -->
        <key>Method</key>         <!-- 分发方式 (app-store/ad-hoc等) -->
      </dict>
      
    • 使用场景:
      • 验证构建参数是否符合预期(如是否误用开发证书签名发布包)
      • 审计历史构建记录时快速查看关键配置
      • 通过 plutil -p DistributionSummary.plist 快速查看内容
  • ExportOptions.plist

    • 定位: 构建参数镜像文件
    • 特殊点: 该文件是 构建时实际使用的参数副本,而非原始输入文件。若通过 Xcode GUI 修改过选项,此文件会与初始传入的不同
    • 风险点: CI/CD 环境中需对比此文件与源码库中的版本,防止因 GUI 操作导致配置漂移
  • Packaging.log

    • 定位: 二进制级构建日志
    • 关键信息示例:
      # 签名阶段
      Executing codesign -v --force --sign ABCD1234.../path/to/framework
      # 资源验证
      Verifying asset catalog for iOS device target...
      # IPA结构生成
      Creating app extension payload/PlugIns/ShareExtension.appex
      
    • 调试技巧:
      • 搜索 error: failed 关键词定位问题
      • 结合 codesign --verify 验证签名步骤是否完整
      • 检查资源文件路径是否正确(常见于 Asset Catalog 路径错误)
  • example.ipa

    • 文件结构 (解压后):
      Payload/
      └── example.app
          ├── Frameworks/       # 嵌入的第三方动态库
          ├── PlugIns/          # 应用扩展(如Today Widget)
          ├── _CodeSignature/   # 核心签名数据
          ├── Assets.car        # 编译后的Asset Catalog
          └── ... 
      
    • 质量检查命令:
      # 验证签名完整性
      codesign --verify --deep --verbose=4 example.app
      
      # 检查支持的设备架构
      lipo -info example.app/example
      

CI/CD 集成建议

  1. 产物保留策略:
    • 永久存档 .ipa + ExportOptions.plist(用于后续重新导出)
    • 临时保留 Packaging.log(建议保存至日志系统如Splunk)
    • 可删除 DistributionSummary.plist(其信息已包含在日志中)
  2. 自动化验证步骤:
    # 检查IPA是否包含无效架构(如模拟器架构i386)
    unzip -q example.ipa -d temp
    find temp -name '*.app' -exec lipo -info {} \; | grep 'i386'
    
    # 验证签名证书类型(禁止开发证书出现在Release包)
    codesign -dvvv example.app 2>&1 | grep 'Apple Development'
    
  3. 安全扫描: 对 .ipa 进行静态分析(使用 OWASP ZAPAppScan),重点检查:
    • Info.plist 中是否开启不必要权限(如NSAllowsArbitraryLoads
    • 动态库是否包含已知漏洞版本
    • 是否包含测试环境 API 配置

通过以上文件组合分析,可快速定位如「测试包误用生产证书」、「资源文件签名遗漏」等典型问题。

签名验证

在这个产物的路径 Products/Applications/ 下,能看到编译之后的 *.app 产物,接下来可以通过 codesign 来测试输出的结果:

codesign --display -vvv ../archive/iOS/202503092308/iosApp.xcarchive/Products/Applications/example.app

输出结果如下:

Executable=/path/to/your/project/exmaple/archive/iOS/202503092308/iosApp.xcarchive/Products/Applications/example.app/example
Identifier=com.example.app
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20400 size=504721 flags=0x0(none) hashes=15762+7 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=YOUR_HASH_VALUE
CandidateCDHashFull sha256=YOUR_HASH_VALUE
Hash choices=sha256
CMSDigest=YOUR_HASH_VALUE
CMSDigestType=2
CDHash=YOUR_HASH_VALUE
Signature size=4775
Authority=Apple Development: YOUR_NAME (YOUR_CERTIFICATE_ID)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Mar 9, 2025 at 23:19:22
Info.plist entries=38
TeamIdentifier=YOUR_TEAM_ID
Sealed Resources version=2 rules=10 files=552
Internal requirements count=1 size=176

以下是对iOS应用包信息的逐项技术解析,关键参数已用粗体标注:

  • 基础信息

    • Executable: iosApp.xcarchive/Products/Applications/example.app/example 应用二进制文件路径,由Xcode归档(Archive)生成,通常用于发布或测试
    • Identifier: com.example.app Bundle ID,唯一标识应用,需与开发者账号配置和App Store Connect中的ID一致
    • Format: app bundle with Mach-O thin (arm64) 应用格式为Mach-O单架构(arm64),适用于64位iOS设备
  • 代码签名与安全

    • CodeDirectory v=20400: 代码签名目录版本为20400,包含签名的哈希值和元数据
    • Hash type=sha256: 使用SHA-256算法生成代码哈希,用于验证文件完整性
    • CDHash: YOUR_HASH_VALUE... 代码目录哈希(Code Directory Hash),用于快速验证签名一致性,匹配codesign -dv输出
    • CMSDigest: 与CandidateCDHashFull一致 签名证书的摘要值,用于验证证书链合法性
  • 证书与签名

    • Authority:

      Apple Development: YOUR_NAME (YOUR_CERTIFICATE_ID)
      → Apple Worldwide Developer Relations Certification Authority
      → Apple Root CA
      

      签名证书链,表明应用由开发者「YOUR_NAME」的证书(类型:开发证书)签发,并通过苹果两级CA认证

    • TeamIdentifier: YOUR_TEAM_ID 开发者团队ID,需与Apple Developer账号中的Team ID匹配,用于防止证书盗用

    • Signed Time: Mar 9, 2025 at 23:19:22 签名时间戳,若系统时间超过证书有效期(通常开发证书1年),应用将无法运行

    • 应用资源配置

    • Info.plist entries=38: Info.plist中共有38个配置项,包含Bundle ID、版本号、权限声明等关键参数

    • Sealed Resources:

      version=2    // 资源密封格式版本
      rules=10     // 签名规则数量(如可执行文件、动态库等)
      files=552    // 被签名保护的资源文件总数(图片、配置文件等)
      

      资源密封机制防止篡改,规则由Xcode自动生成

  • 关键验证点

    • 签名有效性: Authority链完整且包含苹果官方CA证书(Apple Root CA),表明签名合法。
    • 证书类型: 当前使用开发证书(Apple Development),若需发布到App Store需替换为Distribution证书。
    • 时间戳: 签名时间为2025年,需确认证书实际有效期(开发证书通常为1年),防止过期失效。
Important

此信息表明应用签名配置正常,但需注意证书类型和有效期是否符合分发场景要求(如TestFlight需Distribution证书)。

分发 ipa 文件

Ad Hoc - 企业内部测试渠道(内部测试人员)

要通过 Ad Hoc 方式分发 .ipa 文件,需要确保应用正确签名且 目标设备的UUID 已注册到Devices List配置文件中。以下是完整的配置流程:

准备证书与配置文件

  • 证书要求:
    • 签名证书:Apple 开发者账号中的 Ad Hoc 分发证书(需提前在 Apple Developer Portal 生成)。
    • 配置文件:创建 Ad Hoc 类型的 Provisioning Profile,并包含以下内容:
      • 关联 Ad Hoc 证书
      • 明确指定 App Bundle Identifier
      • 添加所有目标测试设备的 UUID(最多100台设备)
    • 操作步骤:
      • 登录 Apple Developer Portal → Certificates, Identifiers & Profiles。
      • 创建/下载 Ad Hoc 证书和配置文件(.mobileprovision)。
      • 在 Xcode 中导入证书和配置文件(或通过 xcodebuild 自动管理)。

生成Ad Hoc分发的 .ipa 文件

  • 关键配置
    • 在生成 .ipa 时,必须通过 -exportOptionsPlist 指定 Ad Hoc 分发模式。以下是典型配置:
     # 归档项目
      xcodebuild archive \
      -scheme iosApp \
      -archivePath iosApp.xcarchive \
      -configuration Release
    
      # 导出为 Ad Hoc 分发的 .ipa
      xcodebuild -exportArchive \
      -archivePath iosApp.xcarchive \
      -exportOptionsPlist ExportOptions.plist \
      -exportPath ./Output
    
    • ExportOptions.plist 文件内容:
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
      <dict>
        <key>method</key>
        <string>ad-hoc</string>  <!-- 关键:指定为 Ad Hoc 分发 -->
        <key>teamID</key>
        <string>YOUR_TEAM_ID</string>  <!-- 替换为你的 Team ID -->
        <key>compileBitcode</key>
        <false/>  <!-- 可选:禁用 Bitcode 加快编译 -->
        <key>uploadSymbols</key>
        <false/>  <!-- 可选:不上传调试符号 -->
      </dict>
      </plist>
    

验证 .ipa 签名

分发 .ipa 文件

对于 Ad Hoc 包,我们可以通过配置 mainifest.plist 文件然后将相关的版本发布到线上的静态链接地址上,提供可供下载的链接/二维码给到公司内部的测试人员。

Important

配置ADHoc包的下载地址: Example App ADHoc

配置地址为一般为: itms-services://?action=download-manifest&url= + https://download.example.app/ios/manifest.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>items</key>
	<array>
		<dict>
			<key>assets</key>
			<array>
				<dict>
					<key>kind</key>
					<string>software-package</string>
					<key>url</key>
					<string>https://download.example.app/ios/example.ipa</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>display-image</string>
					<key>url</key>
					<string>https://download.example.app/ios/image.57x57.png</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>full-size-image</string>
					<key>url</key>
					<string>https://download.example.app/ios/image.512x512.png</string>
				</dict>
			</array>
			<key>metadata</key>
			<dict>
				<key>bundle-identifier</key>
				<string>com.example.app</string>
				<key>bundle-version</key>
				<string>1.0.0</string>
				<key>kind</key>
				<string>software</string>
				<key>platform-identifier</key>
				<string>com.apple.platform.iphoneos</string>
				<key>title</key>
				<string>example</string>
			</dict>
		</dict>
	</array>
</dict>
</plist>

TestFlight - 外部测试渠道(外部内测用户)

环境准备

  • 必要条件:
    • Apple 开发者账号(付费账号,个人或组织)。
    • 应用已配置 App Store 分发证书(非 Ad Hoc)。
    • Xcode 项目设置中:
      • Bundle Identifier 在开发者后台已注册。
      • 版本号(CFBundleShortVersionString)和 构建号(CFBundleVersion)符合递增规则。

构建与上传

  • 构建步骤:
    • 生成归档文件(Archive)
    xcodebuild clean archive \
            -allowProvisioningUpdates \
            -workspace iosApp/iosApp.xcworkspace \
            -scheme iosApp \
            -sdk iphoneos \
            -destination generic/platform=iOS \
            -configuration Release \
            -archivePath archive/iOS/20250310/iosApp.xcarchive 
    
    • 配置 ExportOptions.plist 文件内容(本文导出的路径为当前项目的archive/iOS/ExportOptions.plist下)
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
      <dict>
          <key>compileBitcode</key>
          <false/>
          <key>method</key>
          <string>app-store-connect</string>
          <key>signingStyle</key>
          <string>automatic</string>
          <key>stripSwiftSymbols</key>
          <true/>
          <key>teamID</key>
          <string>YOUR_TEAM_ID</string>
          <key>testFlightInternalTestingOnly</key>
          <false/>
          <key>uploadSymbols</key>
          <false/>
      </dict>
      </plist>
    
    • 执行 Export 导出 .ipa 文件
    xcodebuild -allowProvisioningUpdates \
            -exportArchive -archivePath archive/iOS/20250310/iosApp.xcarchive \
            -exportOptionsPlist archive/iOS/ExportOptions.plist \
            -exportPath archive/iOS/20250310/build \
            -configuration Release 
    
    • 上传到 App Store
      • 前置准备:
        • 在上传文件到App Store之前,我们需要先安装软件: iTMSTransporter
      • 下载 App Store Connect Api Key 至本地
      • 运行上传指令
      xcrun altool --upload-package archive/iOS/20250310/build/example.ipa \
            --type ios \
            --apple-id YOUR_APPLE_ID \
            --bundle-id com.example.app \
            --bundle-short-version-string "1.0.0" \
            --bundle-version 100000 \
            --apiKey YOUR_API_KEY \
            --apiIssuer YOUR_API_ISSUER_ID --verbose
      

注意事项

  • 在上传AppStore之后苹果后台会初步给出一个邮件提醒,告知上传的结果,成功或者失败。
  • 一般会遇到错误:“二进制文件无效”,这种大部分都是因为发布的App中缺少所需的权限声明,基于苹果的隐私政策要求,只需要补充对应的Info.plist中权限的声明,重新编译后重新上传App
  • 上传App之后AppStore上的待审核版本并不会立刻更新,而是要等待片刻,等待更新之后苹果会发送一封邮件提示App上传成功 “The following build has completed processing”
  • 收到邮件之后,就可以将当前的版本加入到TestFlight中进行公司内部开发测试用户测试
  • 如果要提供给外部的内测用户使用,则需要提交TestFlight版本给到苹果进行审核,审核通过之后TestFlight版本才能正常通过链接下载。

AppStore - 线上测试渠道(所有用户)

在上传App到AppStore之前,请务必仔细阅读苹果官方文档 App 审核指南 在提交版本之前尽量避免指南中所禁止的问题。

环境准备

  • 应用配置要求

    • 确保 App Store Distribution 证书签名
    • 确保 ExportOptions.plist设置包含:
    <key>method</key>
    <string>app-store</string>
    <key>compileBitcode</key>
    <true/>
    <key>uploadSymbols</key>
    <true/>
    
    • 完整的应用隐私声明(Info.plist)
  • App Store Connect 配置

    • App Store Connect 创建应用
    • 准备应用介绍、截图、预览视频
    • 配置价格与销售范围
    • 填写隐私政策链接

构建与上传

# 1. 生成发布包
xcodebuild clean archive \
      -allowProvisioningUpdates \
      -workspace iosApp/iosApp.xcworkspace \
      -scheme iosApp \
      -sdk iphoneos \
      -destination generic/platform=iOS \
      -configuration Release \
      -archivePath archive/iOS/20250310/iosApp.xcarchive

# 2. 导出 IPA
xcodebuild -allowProvisioningUpdates \
      -exportArchive -archivePath archive/iOS/20250310/iosApp.xcarchive \
      -exportOptionsPlist archive/iOS/ExportOptions.plist \
      -exportPath archive/iOS/20250310/build \
      -configuration Release

# 3. 上传至 App Store
xcrun altool --upload-package archive/iOS/20250310/build/example.ipa \
      --type ios \
      --apple-id YOUR_APPLE_ID \
      --bundle-id com.example.app \
      --bundle-short-version-string "1.0.0" \
      --bundle-version 100000 \
      --apiKey YOUR_API_KEY \
      --apiIssuer YOUR_API_ISSUER_ID --verbose

发布流程

  1. 构建处理
    • 等待邮件通知:"Processing has completed"
    • 在 App Store Connect 检查构建版本是否可用
  2. 提交审核
    • 选择要发布的构建版本
    • 填写"What's New"版本说明
    • 确认所有必填项(年龄分级、版权信息等)
    • 提交审核
  3. 审核阶段
    • 一般审核周期 24-48 小时
    • 可能的审核状态
      • Waiting for Review: 等待审核
      • In Review: 审核中
      • Pending Developer Release: 审核通过待发布
      • Ready for Sale: 已上架销售

注意事项

  • 关键检查项

    • 确保所有使用的 API 符合苹果审核指南
    • 隐私相关功能需提供完整说明
    • 应用图标和启动图需符合尺寸规范
    • 所有付费功能必须使用 In-App Purchase
  • 常见拒绝原因处理

    • 功能不完整或存在崩溃问题
    • 缺少隐私政策或数据使用说明
    • 应用描述与实际功能不符
    • 违反人机界面准则
    • 使用私有 API
  • 发布后监控

    • 通过 App Analytics 监控下载量
    • 关注用户评价和反馈
    • 跟踪崩溃报告
    • 准备必要的应用更新

CI/CD 集成建议

# 自动化发布脚本示例
VERSION="1.0.0"
BUILD_NUMBER="100000"

# 更新版本号
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" Info.plist

# 构建、导出、上传一条龙
sh scripts/build_and_upload.sh

这样的发布流程可以确保 App 顺利通过审核并上架 App Store。要特别注意苹果的各项规范要求,这样可以减少审核被拒的概率。