使用xtoolSkill using-xtool

本技能详细介绍如何使用xtool这一跨平台Xcode替代工具进行iOS应用开发。涵盖在Linux、Windows和macOS上无需Xcode,通过SwiftPM构建iOS应用、创建项目、添加小组件等应用扩展、配置xtool.yml文件以及部署的全流程。关键词:xtool iOS开发,跨平台iOS开发,SwiftPM iOS,Xcode替代工具,iOS小组件开发,应用扩展配置。

移动开发 0 次安装 0 次浏览 更新于 2/28/2026

name: using-xtool description: 此技能应在使用xtool(无需Xcode的iOS开发)构建iOS应用、创建xtool项目、添加应用扩展或配置xtool.yml时使用。触发词包括“xtool”、“SwiftPM iOS”、“Linux上开发iOS”、“Windows上开发iOS”、“无需Xcode”、“应用扩展”、“小组件扩展”、“分享扩展”。涵盖项目设置、应用扩展和部署。

使用xtool

概述

xtool是一个跨平台的Xcode替代工具,用于在Linux、Windows和macOS上使用SwiftPM构建iOS应用。它不是XcodeGen、Tuist或Xcode项目文件。

关键点:xtool不是XcodeGen

xtool使用 不是这些
xtool.yml project.ymlProject.swift
Package.swift (SwiftPM) Xcode项目文件
xtool dev xtool buildxtool runxtool generate
Sources/目录 Extensions/目录

项目结构

MyApp/
├── Package.swift          # SwiftPM包定义
├── xtool.yml              # xtool配置
├── Sources/
│   ├── MyApp/             # 主应用目标
│   │   ├── MyAppApp.swift
│   │   └── ContentView.swift
│   └── MyWidget/          # 扩展目标(如果有)
│       └── Widget.swift
├── MyApp-Info.plist       # 可选的自定义Info.plist
└── MyWidget-Info.plist    # 扩展必需的Info.plist

快速参考:命令

# 项目生命周期
xtool new MyApp              # 创建新项目
xtool new MyApp --skip-setup # 创建但不运行设置
xtool dev                    # 构建+运行(同`xtool dev run`)
xtool dev build              # 仅构建
xtool dev build --ipa        # 构建IPA文件
xtool dev run -s             # 在iOS模拟器上运行(--simulator)
xtool dev run -c release     # 发布版本构建(--configuration)
xtool dev run -u <udid>      # 定位特定设备(--udid)
xtool dev generate-xcode-project  # 生成.xcodeproj用于调试

# 设备管理
xtool devices                # 列出已连接的设备
xtool install app.ipa        # 安装IPA到设备
xtool launch                 # 启动已安装的应用
xtool uninstall              # 从设备卸载应用

# 认证与设置
xtool setup                  # 完整设置(认证+SDK)
xtool auth login             # 使用Apple认证登录
xtool auth status            # 检查认证状态
xtool auth logout            # 登出
xtool sdk                    # 管理Darwin Swift SDK

# 开发者服务
xtool ds teams               # 列出开发团队
xtool ds certificates        # 管理证书
xtool ds profiles            # 管理配置文件

xtool.yml格式

最小配置:

version: 1
bundleID: com.example.MyApp

完整选项:

version: 1
bundleID: com.example.MyApp
product: MyApp                    # 哪个SwiftPM产品是主应用
infoPath: MyApp-Info.plist        # 自定义Info.plist(合并)
iconPath: Resources/AppIcon.png   # 应用图标(1024x1024 PNG)
entitlementsPath: App.entitlements
resources:                        # 复制到应用包根目录的文件
  - Resources/GoogleServices-Info.plist
extensions:                       # 应用扩展
  - product: MyWidget
    infoPath: MyWidget-Info.plist

添加应用扩展(小组件、分享等)

步骤1:更新Package.swift

添加产品目标。注意:xtool使用.library(不是.executable)——它将库打包到iOS应用中。

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "MyApp",
    platforms: [.iOS(.v17)],
    products: [
        .library(name: "MyApp", targets: ["MyApp"]),
        .library(name: "MyWidget", targets: ["MyWidget"]),  // 添加
    ],
    targets: [
        .target(name: "MyApp"),
        .target(name: "MyWidget"),  // 添加
    ]
)

步骤2:更新xtool.yml

version: 1
bundleID: com.example.MyApp
product: MyApp
extensions:
  - product: MyWidget
    infoPath: MyWidget-Info.plist

步骤3:创建扩展Info.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>NSExtension</key>
    <dict>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.widgetkit-extension</string>
    </dict>
</dict>
</plist>

步骤4:创建扩展代码

Sources/MyWidget/Widget.swift

import WidgetKit
import SwiftUI

@main struct MyWidgetBundle: WidgetBundle {
    var body: some Widget { MyWidget() }
}

struct MyWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
            Text(entry.date, style: .date)
                .containerBackground(.fill.tertiary, for: .widget)
        }
        .configurationDisplayName("My Widget")
    }
}

struct Entry: TimelineEntry { var date = Date() }

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> Entry { Entry() }
    func getSnapshot(in context: Context, completion: @escaping (Entry) -> Void) {
        completion(Entry())
    }
    func getTimeline(in context: Context, completion: @escaping (Entry) -> Void) {
        completion(Timeline(entries: [Entry()], policy: .after(.now + 3600)))
    }
}

步骤5:构建并运行

xtool dev

常见扩展类型

扩展 NSExtensionPointIdentifier
小组件 (WidgetKit) com.apple.widgetkit-extension
分享 com.apple.share-services
操作 com.apple.ui-services
Safari com.apple.Safari.web-extension
键盘 com.apple.keyboard-service
今日(已弃用) com.apple.widget-extension

故障排除

错误 解决方案
“不受信任的开发者” 设置 > 通用 > VPN与设备管理 > 信任
设备未找到 连接USB,运行xtool devices,启用开发者模式
认证失败 运行xtool auth login
首次运行构建失败 正常 - SDK模块正在构建。等待完成。

资源配置

SwiftPM资源(在包子目录中):

.target(name: "MyApp", resources: [.copy("Blob.png")])
// 访问:Image("Blob", bundle: Bundle.module)

顶级资源(在应用包根目录中):

# xtool.yml
resources:
  - Resources/GoogleServices-Info.plist

权限

# xtool.yml
entitlementsPath: App.entitlements
<!-- App.entitlements -->
<?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>com.apple.developer.homekit</key>
    <true/>
</dict>
</plist>

常见错误

错误 修复
使用xtool build 使用xtool dev build
使用project.yml 使用xtool.yml
使用Extensions/目录 使用Sources/(标准SwiftPM)
忘记Package.swift 扩展需要在Package.swift中有产品+目标
复杂的扩展Info.plist 仅需要NSExtension/NSExtensionPointIdentifier