using-xtool
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUsing xtool
使用xtool
Overview
概述
xtool is a cross-platform Xcode replacement for building iOS apps with SwiftPM on Linux, Windows, and macOS. It is NOT XcodeGen, Tuist, or Xcode project files.
xtool是一款跨平台的Xcode替代工具,可在Linux、Windows和macOS系统上通过SwiftPM构建iOS应用。它并非XcodeGen、Tuist或Xcode项目文件。
Critical: xtool is NOT XcodeGen
重点说明:xtool 并非 XcodeGen
| xtool Uses | NOT These |
|---|---|
| |
| Xcode project files |
| |
| |
| xtool 使用的内容 | 不使用的内容 |
|---|---|
| |
| Xcode项目文件 |
| |
| |
Project Structure
项目结构
MyApp/
├── Package.swift # SwiftPM package definition
├── xtool.yml # xtool configuration
├── Sources/
│ ├── MyApp/ # Main app target
│ │ ├── MyAppApp.swift
│ │ └── ContentView.swift
│ └── MyWidget/ # Extension target (if any)
│ └── Widget.swift
├── MyApp-Info.plist # Optional custom Info.plist
└── MyWidget-Info.plist # Required for extensionsMyApp/
├── Package.swift # SwiftPM包定义文件
├── xtool.yml # xtool配置文件
├── Sources/
│ ├── MyApp/ # 主应用目标
│ │ ├── MyAppApp.swift
│ │ └── ContentView.swift
│ └── MyWidget/ # 扩展目标(如有)
│ └── Widget.swift
├── MyApp-Info.plist # 可选的自定义Info.plist
└── MyWidget-Info.plist # 扩展必备文件Quick Reference: Commands
快速参考:命令
bash
undefinedbash
undefinedProject lifecycle
项目生命周期
xtool new MyApp # Create new project
xtool new MyApp --skip-setup # Create without running setup
xtool dev # Build + run (same as )
xtool dev build # Build only
xtool dev build --ipa # Build IPA file
xtool dev run -s # Run on iOS Simulator (--simulator)
xtool dev run -c release # Release build (--configuration)
xtool dev run -u <udid> # Target specific device (--udid)
xtool dev generate-xcode-project # Generate .xcodeproj for debugging
xtool dev runxtool new MyApp # 创建新项目
xtool new MyApp --skip-setup # 创建项目但不执行初始化
xtool dev # 构建并运行(等同于)
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 dev runDevice management
设备管理
xtool devices # List connected devices
xtool install app.ipa # Install IPA to device
xtool launch # Launch installed app
xtool uninstall # Uninstall app from device
xtool devices # 列出已连接的设备
xtool install app.ipa # 将IPA安装到设备
xtool launch # 启动已安装的应用
xtool uninstall # 从设备卸载应用
Authentication & setup
认证与初始化
xtool setup # Full setup (auth + SDK)
xtool auth login # Authenticate with Apple
xtool auth status # Check auth status
xtool auth logout # Log out
xtool sdk # Manage Darwin Swift SDK
xtool setup # 完整初始化(认证+SDK配置)
xtool auth login # 登录Apple账号进行认证
xtool auth status # 检查认证状态
xtool auth logout # 登出账号
xtool sdk # 管理Darwin Swift SDK
Developer Services
开发者服务
xtool ds teams # List development teams
xtool ds certificates # Manage certificates
xtool ds profiles # Manage provisioning profiles
undefinedxtool ds teams # 列出开发团队
xtool ds certificates # 管理证书
xtool ds profiles # 管理描述文件
undefinedxtool.yml Format
xtool.yml 格式
Minimal:
yaml
version: 1
bundleID: com.example.MyAppFull options:
yaml
version: 1
bundleID: com.example.MyApp
product: MyApp # Which SwiftPM product is main app
infoPath: MyApp-Info.plist # Custom Info.plist (merged)
iconPath: Resources/AppIcon.png # App icon (1024x1024 PNG)
entitlementsPath: App.entitlements
resources: # Files copied to app bundle root
- Resources/GoogleServices-Info.plist
extensions: # App extensions
- product: MyWidget
infoPath: MyWidget-Info.plist最简配置:
yaml
version: 1
bundleID: com.example.MyApp完整配置选项:
yaml
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.plistAdding App Extensions (Widgets, Share, etc.)
添加应用扩展(Widget、Share等)
Step 1: Update Package.swift
步骤1:更新Package.swift
Add BOTH a product AND a target. Note: xtool uses (not ) - it bundles the library into an iOS app.
.library.executableswift
// 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"]), // ADD
],
targets: [
.target(name: "MyApp"),
.target(name: "MyWidget"), // ADD
]
)同时添加产品(product)和目标(target)。注意:xtool使用(而非)——它会将库打包到iOS应用中。
.library.executableswift
// 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"), // 添加此行
]
)Step 2: Update xtool.yml
步骤2:更新xtool.yml
yaml
version: 1
bundleID: com.example.MyApp
product: MyApp
extensions:
- product: MyWidget
infoPath: MyWidget-Info.plistyaml
version: 1
bundleID: com.example.MyApp
product: MyApp
extensions:
- product: MyWidget
infoPath: MyWidget-Info.plistStep 3: Create Extension Info.plist
步骤3:创建扩展的Info.plist
Minimal required (just the extension type):
xml
<?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>必备最简配置(仅需指定扩展类型):
xml
<?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>Step 4: Create Extension Code
步骤4:编写扩展代码
Sources/MyWidget/Widget.swiftswift
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)))
}
}Sources/MyWidget/Widget.swiftswift
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)))
}
}Step 5: Build and Run
步骤5:构建并运行
bash
xtool devbash
xtool devCommon Extension Types
常见扩展类型
| Extension | NSExtensionPointIdentifier |
|---|---|
| Widget (WidgetKit) | |
| Share | |
| Action | |
| Safari | |
| Keyboard | |
| Today (deprecated) | |
| 扩展类型 | NSExtensionPointIdentifier |
|---|---|
| Widget(WidgetKit) | |
| 分享扩展 | |
| 动作扩展 | |
| Safari扩展 | |
| 键盘扩展 | |
| Today扩展(已废弃) | |
Troubleshooting
故障排查
| Error | Solution |
|---|---|
| "Untrusted Developer" | Settings > General > VPN & Device Management > Trust |
| Device not found | Connect USB, run |
| Auth failed | Run |
| Build fails on first run | Normal - SDK modules building. Wait for completion. |
| 错误信息 | 解决方法 |
|---|---|
| "Untrusted Developer" | 前往设置 > 通用 > VPN与设备管理 > 信任开发者 |
| 设备未找到 | 连接USB线,运行 |
| 认证失败 | 运行 |
| 首次运行构建失败 | 属于正常现象,SDK模块正在编译,等待完成即可 |
Resources Configuration
资源配置
SwiftPM resources (in bundle subdirectory):
swift
.target(name: "MyApp", resources: [.copy("Blob.png")])
// Access: Image("Blob", bundle: Bundle.module)Top-level resources (in app bundle root):
yaml
undefinedSwiftPM资源(会放在应用包的子目录中):
swift
.target(name: "MyApp", resources: [.copy("Blob.png")])
// 访问方式:Image("Blob", bundle: Bundle.module)顶层资源(会放在应用包的根目录中):
yaml
undefinedxtool.yml
xtool.yml
resources:
- Resources/GoogleServices-Info.plist
undefinedresources:
- Resources/GoogleServices-Info.plist
undefinedEntitlements
权限配置
yaml
undefinedyaml
undefinedxtool.yml
xtool.yml
entitlementsPath: App.entitlements
```xml
<!-- 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>entitlementsPath: App.entitlements
```xml
<!-- 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>Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
Using | Use |
Using | Use |
Using | Use |
| Forgetting Package.swift | Extensions need product + target in Package.swift |
| Complex extension Info.plist | Only NSExtension/NSExtensionPointIdentifier required |
| 错误操作 | 修复方法 |
|---|---|
使用 | 改用 |
使用 | 改用 |
使用 | 改用 |
| 忘记配置Package.swift | 扩展需要在Package.swift中添加对应的product和target |
| 编写复杂的扩展Info.plist | 仅需保留NSExtension/NSExtensionPointIdentifier配置即可 |