diff --git a/Justfile b/Justfile
index a85057e..8764ba7 100644
--- a/Justfile
+++ b/Justfile
@@ -96,7 +96,14 @@ ios-fonts-fredoka:
ios-sim-build:
just ios-fonts
cd ios/CDrop && xcodegen generate
- cd ios/CDrop && xcodebuild -project CDrop.xcodeproj -scheme CDrop -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build/DD build
+ cd ios/CDrop && xcodebuild -project CommilitiaDrop.xcodeproj -scheme CommilitiaDrop -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build/DD build
+
+# macOS 原生客户端本地编译验证(ad-hoc 签名,无需 Apple 账号):xcodegen + xcodebuild -sdk macosx。
+# 当前为脚手架(MacApp/ 导航骨架 + 菜单栏占位);引擎 / 复用视图 / 桌面功能随后续阶段并入。
+# 产物 build/DD-mac/Build/Products/Debug/CommilitiaDropMac.app(用于本地打开自测)。
+mac-build:
+ cd ios/CDrop && xcodegen generate
+ cd ios/CDrop && xcodebuild -project CommilitiaDrop.xcodeproj -scheme CommilitiaDropMac -sdk macosx -destination 'platform=macOS' -derivedDataPath build/DD-mac build
# 真机构建 + 装机(自动 provisioning,经 ASC API Key)。前置:付费 ADP;App ID 的 App Groups /
# Push 能力(门户建好或自动建);根目录 gitignore 的 .env 配齐:CDROP_TEAM_ID / CDROP_ASC_KEY_PATH
@@ -108,8 +115,8 @@ ios-device udid:
[ -n "$CDROP_TEAM_ID" ] && [ -n "$CDROP_ASC_KEY_PATH" ] && [ -n "$CDROP_ASC_KEY_ID" ] && [ -n "$CDROP_ASC_ISSUER_ID" ] || { echo "缺 .env(CDROP_TEAM_ID / CDROP_ASC_KEY_PATH / CDROP_ASC_KEY_ID / CDROP_ASC_ISSUER_ID)——见 ios/CDrop/REALDEVICE.md"; exit 1; }
just ios-fonts
cd ios/CDrop && xcodegen generate
- cd ios/CDrop && xcodebuild -project CDrop.xcodeproj -scheme CDrop -configuration Debug -destination "platform=iOS,id={{udid}}" -derivedDataPath build/DD-device -allowProvisioningUpdates -authenticationKeyPath "$CDROP_ASC_KEY_PATH" -authenticationKeyID "$CDROP_ASC_KEY_ID" -authenticationKeyIssuerID "$CDROP_ASC_ISSUER_ID" DEVELOPMENT_TEAM="$CDROP_TEAM_ID" CODE_SIGN_STYLE=Automatic CODE_SIGN_IDENTITY="Apple Development" build
- xcrun devicectl device install app --device {{udid}} ios/CDrop/build/DD-device/Build/Products/Debug-iphoneos/CDrop.app
+ cd ios/CDrop && xcodebuild -project CommilitiaDrop.xcodeproj -scheme CommilitiaDrop -configuration Debug -destination "platform=iOS,id={{udid}}" -derivedDataPath build/DD-device -allowProvisioningUpdates -authenticationKeyPath "$CDROP_ASC_KEY_PATH" -authenticationKeyID "$CDROP_ASC_KEY_ID" -authenticationKeyIssuerID "$CDROP_ASC_ISSUER_ID" DEVELOPMENT_TEAM="$CDROP_TEAM_ID" CODE_SIGN_STYLE=Automatic CODE_SIGN_IDENTITY="Apple Development" build
+ xcrun devicectl device install app --device {{udid}} ios/CDrop/build/DD-device/Build/Products/Debug-iphoneos/CommilitiaDrop.app
# ---- deploy plumbing ----
diff --git a/ios/CDrop/.gitignore b/ios/CDrop/.gitignore
index ee6c161..44cda4b 100644
--- a/ios/CDrop/.gitignore
+++ b/ios/CDrop/.gitignore
@@ -1,5 +1,6 @@
-# CDrop.xcodeproj 由 xcodegen 从 project.yml 生成——不提交,用 `xcodegen generate` 重建。
-CDrop.xcodeproj/
+# .xcodeproj 由 xcodegen 从 project.yml 生成——不提交,用 `xcodegen generate` 重建。本目录去缩写后
+# 由 CDrop.xcodeproj 改名 CommilitiaDrop.xcodeproj;用通配符防再次改名遗漏。
+*.xcodeproj/
# Xcode 构建产物
build/
diff --git a/ios/CDrop/MacApp/CommilitiaDropMacApp.swift b/ios/CDrop/MacApp/CommilitiaDropMacApp.swift
new file mode 100644
index 0000000..3b664a4
--- /dev/null
+++ b/ios/CDrop/MacApp/CommilitiaDropMacApp.swift
@@ -0,0 +1,38 @@
+#if os(macOS)
+import SwiftUI
+
+// 原生 macOS 客户端入口。单窗口 + 菜单栏常驻,桌面壳(MacRootView)替代 iOS 的标签栏。
+// 当前为脚手架:导航骨架 + 菜单栏占位;引擎(LibWebRtcEngine + 离屏 WebView)、复用视图与
+// 桌面专属功能(剪贴板自动同步 / 全局热键 / 原生通知)随后续阶段并入。iOS 入口另见 CDropApp。
+@main
+struct CommilitiaDropMacApp: App
+{
+ var body: some Scene
+ {
+ // 启动即打开的单主窗口。
+ Window("Commilitia Drop", id: "main")
+ {
+ MacRootView()
+ .frame(minWidth: 820, minHeight: 560)
+ }
+ .defaultLaunchBehavior(.presented)
+ .windowResizability(.contentMinSize)
+ .commands
+ {
+ // 单窗口应用:移除「新建」(⌘N),对本应用无意义。
+ CommandGroup(replacing: .newItem) {}
+ }
+
+ // 菜单栏常驻:状态 + 快捷剪贴板 / Quick Send(当前占位)。
+ MenuBarExtra
+ {
+ MacMenuContent()
+ }
+ label:
+ {
+ Image(systemName: "paperplane")
+ }
+ .menuBarExtraStyle(.window)
+ }
+}
+#endif
diff --git a/ios/CDrop/MacApp/MacMenuContent.swift b/ios/CDrop/MacApp/MacMenuContent.swift
new file mode 100644
index 0000000..fe1eca9
--- /dev/null
+++ b/ios/CDrop/MacApp/MacMenuContent.swift
@@ -0,0 +1,27 @@
+#if os(macOS)
+import SwiftUI
+
+// 菜单栏常驻内容(占位):后续接入连接状态 + 一键剪贴板 push/pull + Quick Send。
+struct MacMenuContent: View
+{
+ @Environment(\.openWindow) private var openWindow
+
+ var body: some View
+ {
+ VStack(alignment: .leading, spacing: 10)
+ {
+ Text("Commilitia Drop")
+ .font(.headline)
+ Text("桌面功能适配中")
+ .font(.caption)
+ .foregroundStyle(.secondary)
+
+ Divider()
+ Button("打开主窗口") { openWindow(id: "main") }
+ Button("退出") { NSApplication.shared.terminate(nil) }
+ }
+ .padding(12)
+ .frame(width: 240)
+ }
+}
+#endif
diff --git a/ios/CDrop/MacApp/MacRootView.swift b/ios/CDrop/MacApp/MacRootView.swift
new file mode 100644
index 0000000..f0b92fe
--- /dev/null
+++ b/ios/CDrop/MacApp/MacRootView.swift
@@ -0,0 +1,126 @@
+#if os(macOS)
+import SwiftUI
+
+// 桌面根界面:NavigationSplitView 侧栏(传输 / 文件 / 消息 / 设备 / 设置)+ 详情 NavigationStack,
+// 替代 iOS 的标签栏。当前为脚手架:各区详情为占位(MacPlaceholder),随后续阶段接入复用视图
+// 与桌面专属功能。分区标签暂硬编中文;接入 i18n(Shared/I18n)后改走 t()(与 iOS 单一真源一致)。
+struct MacRootView: View
+{
+ @State private var selection: MacSection = .transfers
+
+ var body: some View
+ {
+ NavigationSplitView
+ {
+ List(selection: $selection)
+ {
+ brandHeader
+ .listRowInsets(EdgeInsets(top: 10, leading: 8, bottom: 14, trailing: 8))
+ .listRowSeparator(.hidden)
+ .selectionDisabled()
+ Section
+ {
+ ForEach(MacSection.sidebar)
+ { section in
+ Label(section.title, systemImage: section.icon)
+ .tag(section)
+ }
+ }
+ }
+ .navigationSplitViewColumnWidth(min: 200, ideal: 220, max: 280)
+ .navigationTitle("Commilitia Drop")
+ }
+ detail:
+ {
+ NavigationStack
+ {
+ detail
+ }
+ }
+ }
+
+ @ViewBuilder
+ private var detail: some View
+ {
+ switch selection
+ {
+ case .transfers:
+ MacPlaceholder(section: .transfers)
+ case .files:
+ MacPlaceholder(section: .files)
+ case .messages:
+ MacPlaceholder(section: .messages)
+ case .devices:
+ MacPlaceholder(section: .devices)
+ case .settings:
+ MacPlaceholder(section: .settings)
+ }
+ }
+
+ private var brandHeader: some View
+ {
+ HStack(spacing: 10)
+ {
+ Image(systemName: "paperplane.fill")
+ .font(.title2)
+ .foregroundStyle(.tint)
+ Text("Commilitia Drop")
+ .font(.title3.weight(.semibold))
+ .lineLimit(1)
+ }
+ }
+}
+
+// 侧栏分区。与 iOS 标签一致:传输 / 文件 / 消息 / 设备 / 设置。
+enum MacSection: Hashable, Identifiable, CaseIterable
+{
+ case transfers, files, messages, devices, settings
+
+ var id: Self { self }
+
+ var title: String
+ {
+ switch self
+ {
+ case .transfers: return "传输"
+ case .files: return "文件"
+ case .messages: return "消息"
+ case .devices: return "设备"
+ case .settings: return "设置"
+ }
+ }
+
+ var icon: String
+ {
+ switch self
+ {
+ case .transfers: return "arrow.up.arrow.down"
+ case .files: return "folder"
+ case .messages: return "bubble.left.and.bubble.right"
+ case .devices: return "laptopcomputer.and.iphone"
+ case .settings: return "gearshape"
+ }
+ }
+
+ static var sidebar: [MacSection] { MacSection.allCases }
+}
+
+// 阶段占位详情:标明该区将接入的功能,随后续阶段替换为实际视图。
+struct MacPlaceholder: View
+{
+ let section: MacSection
+
+ var body: some View
+ {
+ ContentUnavailableView
+ {
+ Label(section.title, systemImage: section.icon)
+ }
+ description:
+ {
+ Text("即将接入(原生数据面复用 iOS 引擎,桌面功能适配中)。")
+ }
+ .navigationTitle(section.title)
+ }
+}
+#endif
diff --git a/ios/CDrop/Support/macOS/App-Info.plist b/ios/CDrop/Support/macOS/App-Info.plist
new file mode 100644
index 0000000..95d6468
--- /dev/null
+++ b/ios/CDrop/Support/macOS/App-Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ zh-Hans
+ CFBundleDisplayName
+ Commilitia Drop
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleLocalizations
+
+ zh-Hans
+ zh-Hant
+ en
+
+ CFBundleName
+ Commilitia Drop
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ 26.0
+
+
diff --git a/ios/CDrop/Support/macOS/AppMac.entitlements b/ios/CDrop/Support/macOS/AppMac.entitlements
new file mode 100644
index 0000000..1adf03e
--- /dev/null
+++ b/ios/CDrop/Support/macOS/AppMac.entitlements
@@ -0,0 +1,14 @@
+
+
+
+
+
+ com.apple.security.application-groups
+
+ group.net.commilitia.Commilitia-Drop
+
+
+
diff --git a/ios/CDrop/Tests/LibWebRtcEngineTests.swift b/ios/CDrop/Tests/LibWebRtcEngineTests.swift
index a9d53dc..b559af0 100644
--- a/ios/CDrop/Tests/LibWebRtcEngineTests.swift
+++ b/ios/CDrop/Tests/LibWebRtcEngineTests.swift
@@ -1,5 +1,5 @@
import XCTest
-@testable import CDrop
+@testable import CommilitiaDrop
// LibWebRtcEngine 环回端到端测试:两个引擎在同进程内交叉连,跑完整线协议
// (offer/answer/ICE + meta/分片/done + ack + 收尾),验证收到的文件字节与源逐字节相等。
diff --git a/ios/CDrop/Widgets/ClipboardControls.swift b/ios/CDrop/Widgets/ClipboardControls.swift
index 46c0a51..239b9a9 100644
--- a/ios/CDrop/Widgets/ClipboardControls.swift
+++ b/ios/CDrop/Widgets/ClipboardControls.swift
@@ -20,7 +20,7 @@ struct UploadClipboardControl: ControlWidget
{
var body: some ControlWidgetConfiguration
{
- StaticControlConfiguration(kind: "net.commilitia.cdrop.control.upload")
+ StaticControlConfiguration(kind: "net.commilitia.Commilitia-Drop.control.upload")
{
ControlWidgetButton(action: UploadClipboardIntent())
{
@@ -35,7 +35,7 @@ struct PullClipboardControl: ControlWidget
{
var body: some ControlWidgetConfiguration
{
- StaticControlConfiguration(kind: "net.commilitia.cdrop.control.pull")
+ StaticControlConfiguration(kind: "net.commilitia.Commilitia-Drop.control.pull")
{
ControlWidgetButton(action: PullClipboardIntent())
{
diff --git a/ios/CDrop/Widgets/CloudClipboardWidget.swift b/ios/CDrop/Widgets/CloudClipboardWidget.swift
index be53d92..1ca805c 100644
--- a/ios/CDrop/Widgets/CloudClipboardWidget.swift
+++ b/ios/CDrop/Widgets/CloudClipboardWidget.swift
@@ -107,7 +107,7 @@ struct CloudClipboardWidget: Widget
{
var body: some WidgetConfiguration
{
- StaticConfiguration(kind: "net.commilitia.cdrop.widget.clipboard", provider: ClipboardWidgetProvider())
+ StaticConfiguration(kind: "net.commilitia.Commilitia-Drop.widget.clipboard", provider: ClipboardWidgetProvider())
{ entry in
ClipboardWidgetView(entry: entry)
}
diff --git a/ios/CDrop/project.yml b/ios/CDrop/project.yml
index 9b76237..ee699c5 100644
--- a/ios/CDrop/project.yml
+++ b/ios/CDrop/project.yml
@@ -1,13 +1,17 @@
-name: CDrop
+name: CommilitiaDrop
options:
bundleIdPrefix: net.commilitia
deploymentTarget:
iOS: "26.0"
+ macOS: "26.0"
createIntermediateGroups: true
+ # 源码以简体中文撰写;字符串目录承载 zh-Hant / en 翻译。语言跟随系统设置。
+ developmentLanguage: zh-Hans
# 原生数据面:iOS 走 libwebrtc(Safari 同款,与 iOS 网络栈原生集成)。预编译 xcframework 经
# stasel/WebRTC 以 SPM 分发,仅二进制 target,pin 精确版本避免上游 M 版跳变改 API。替换早先
# gomobile/pion 路径——pion 的 Go raw socket 不与 iOS Network framework 集成,真机确证不可靠
-# (见 desktop/NATIVE-TRANSFER.md §7 / cdrop-native-data-plane 记忆)。
+# (见 desktop/NATIVE-TRANSFER.md §7 / cdrop-native-data-plane 记忆)。libwebrtc 亦含 macOS 切片
+# (macos-x86_64_arm64 + maccatalyst),故同一 LibWebRtcEngine 可在原生 Mac target 复用。
packages:
WebRTC:
url: https://github.com/stasel/WebRTC
@@ -17,12 +21,12 @@ settings:
SWIFT_VERSION: "5.0"
# 模拟器用 ad-hoc 签名(身份 "-",无需 Apple 账号),使 App Group / Push 等 entitlement 在
# 模拟器实际生效(否则共享容器不创建、远程通知注册失败)。真机签名须付费 ADP 配
- # team / provisioning profile(账号门控,见 REALDEVICE.md)。
+ # team / provisioning profile(账号门控,见 REALDEVICE.md)。macOS 本地开发同走 ad-hoc。
CODE_SIGN_IDENTITY: "-"
CODE_SIGNING_REQUIRED: "NO"
CODE_SIGNING_ALLOWED: "YES"
targets:
- CDrop:
+ CommilitiaDrop:
type: application
platform: iOS
deploymentTarget: "26.0"
@@ -30,9 +34,9 @@ targets:
- path: Sources
- path: Shared
dependencies:
- - target: CDropShare
+ - target: CommilitiaDropShare
embed: true
- - target: CDropWidgets
+ - target: CommilitiaDropWidgets
embed: true
# 原生数据面引擎(libwebrtc):SPM 预编 xcframework,Xcode 自动嵌入 + 签名。仅主 app 链接——
# Share / 控件扩展不碰数据面,避免超扩展 120MB 内存限。见 LibWebRtcEngine.swift。
@@ -98,7 +102,7 @@ targets:
CODE_SIGN_ENTITLEMENTS: CDrop.entitlements
# Share Extension:抓分享文件 → App Group 收件箱 → 深链主 app 选设备发送(只交接、不跑引擎,
# 见 PLAN §I5)。只编 ShareViewController + 共享的 AppGroup,绝不拉主 app Sources(避超 120MB)。
- CDropShare:
+ CommilitiaDropShare:
type: app-extension
platform: iOS
deploymentTarget: "26.0"
@@ -129,7 +133,7 @@ targets:
CODE_SIGN_ENTITLEMENTS: Share/CDropShare.entitlements
# 控制中心剪贴板两控件(WidgetKit ControlWidget,iOS 18+,PLAN §I4)。纯原生 REST + 控件专用
# 设备会话(不跑引擎)。i18n JSON 一并打包使控件标签随设备语言(t() 经 no-subdir 回退读 bundle)。
- CDropWidgets:
+ CommilitiaDropWidgets:
type: app-extension
platform: iOS
deploymentTarget: "26.0"
@@ -150,30 +154,67 @@ targets:
CODE_SIGN_ENTITLEMENTS: Widgets/CDropWidgets.entitlements
# 单元 / 集成测试(模拟器,无需签名):原生数据面 libwebrtc 引擎的环回端到端测试——两个
# LibWebRtcEngine 在同进程内交叉连,跑完整线协议(offer/answer/ICE + meta/分片/done + ack +
- # 收尾)验证文件字节完整性。宿主即 CDrop app(@testable import 取内部类型 + 经 app 链接 WebRTC)。
- CDropTests:
+ # 收尾)验证文件字节完整性。宿主即主 app(@testable import 取内部类型 + 经 app 链接 WebRTC)。
+ CommilitiaDropTests:
type: bundle.unit-test
platform: iOS
deploymentTarget: "26.0"
sources:
- path: Tests
dependencies:
- - target: CDrop
+ - target: CommilitiaDrop
- package: WebRTC
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.commilitia.Commilitia-Drop.tests
- TEST_HOST: "$(BUILT_PRODUCTS_DIR)/CDrop.app/CDrop"
+ TEST_HOST: "$(BUILT_PRODUCTS_DIR)/CommilitiaDrop.app/CommilitiaDrop"
BUNDLE_LOADER: "$(TEST_HOST)"
GENERATE_INFOPLIST_FILE: "YES"
+ # 原生 macOS 客户端:桌面壳(MacApp/)替代 iOS 标签栏,@main 的 #if os(macOS) 分支驱动单窗口 +
+ # 菜单栏。与 iOS 同 bundle(net.commilitia.Commilitia-Drop,同 App Store 记录 / 同 App Group)。
+ # 当前为脚手架:仅编 MacApp/(导航骨架 + 菜单栏占位);引擎(LibWebRtcEngine + 离屏 WebView)与
+ # 复用视图随后续阶段并入。ARCHS arm64(本机 Apple Silicon);本地 ad-hoc 签名(base 继承)。
+ CommilitiaDropMac:
+ type: application
+ platform: macOS
+ deploymentTarget: "26.0"
+ sources:
+ - path: MacApp
+ info:
+ path: Support/macOS/App-Info.plist
+ properties:
+ CFBundleName: Commilitia Drop
+ CFBundleDisplayName: Commilitia Drop
+ LSMinimumSystemVersion: "26.0"
+ CFBundleDevelopmentRegion: zh-Hans
+ CFBundleLocalizations:
+ - zh-Hans
+ - zh-Hant
+ - en
+ settings:
+ base:
+ PRODUCT_BUNDLE_IDENTIFIER: net.commilitia.Commilitia-Drop
+ PRODUCT_NAME: CommilitiaDropMac
+ ARCHS: arm64
+ # App Group entitlement(Support/macOS/AppMac.entitlements)在 macOS 属受限能力,即便
+ # ad-hoc 签名也须 provisioning profile;脚手架阶段(本地免账号编译 / 自测)暂不挂,待桌面
+ # 剪贴板 / 小组件共享落地 + Developer ID 签名(Phase 6)再引用该文件。见 AppMac.entitlements。
schemes:
- CDrop:
+ CommilitiaDrop:
build:
targets:
- CDrop: all
+ CommilitiaDrop: all
test:
targets:
- - CDropTests
+ - CommilitiaDropTests
gatherCoverageData: false
run:
config: Debug
+ CommilitiaDropMac:
+ build:
+ targets:
+ CommilitiaDropMac: all
+ run:
+ config: Debug
+ archive:
+ config: Release