diff --git a/.gitignore b/.gitignore index 904f3ae..6c039d8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ dist/ clients/apple/.build/ clients/apple/PunktfunkCore.xcframework/ clients/apple/.swiftpm/ +# Xcode per-user state +xcuserdata/ diff --git a/clients/apple/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/clients/apple/App/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..c1c91e5 --- /dev/null +++ b/clients/apple/App/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, + { "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, + { "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, + { "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, + { "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, + { "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, + { "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, + { "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, + { "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, + { "idiom" : "mac", "scale" : "2x", "size" : "512x512" } + ], + "info" : { "author" : "xcode", "version" : 1 } +} diff --git a/clients/apple/App/Assets.xcassets/Contents.json b/clients/apple/App/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/clients/apple/App/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/clients/apple/Punktfunk.xcodeproj/project.pbxproj b/clients/apple/Punktfunk.xcodeproj/project.pbxproj new file mode 100644 index 0000000..898379d --- /dev/null +++ b/clients/apple/Punktfunk.xcodeproj/project.pbxproj @@ -0,0 +1,265 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + AA0000000000000000000005 /* PunktfunkKit in Frameworks */ = {isa = PBXBuildFile; productRef = AA0000000000000000000006 /* PunktfunkKit */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + AA0000000000000000000001 /* Punktfunk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Punktfunk.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + AA0000000000000000000002 /* App */ = {isa = PBXFileSystemSynchronizedRootGroup; path = App; sourceTree = ""; }; + AA0000000000000000000003 /* PunktfunkClient */ = {isa = PBXFileSystemSynchronizedRootGroup; path = Sources/PunktfunkClient; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + AA0000000000000000000004 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AA0000000000000000000005 /* PunktfunkKit in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + AA0000000000000000000007 = { + isa = PBXGroup; + children = ( + AA0000000000000000000002 /* App */, + AA0000000000000000000003 /* PunktfunkClient */, + AA0000000000000000000008 /* Products */, + ); + sourceTree = ""; + }; + AA0000000000000000000008 /* Products */ = { + isa = PBXGroup; + children = ( + AA0000000000000000000001 /* Punktfunk.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + AA0000000000000000000009 /* Punktfunk */ = { + isa = PBXNativeTarget; + buildConfigurationList = AA000000000000000000000A /* Build configuration list for PBXNativeTarget "Punktfunk" */; + buildPhases = ( + AA000000000000000000000B /* Sources */, + AA0000000000000000000004 /* Frameworks */, + AA000000000000000000000C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + AA0000000000000000000002 /* App */, + AA0000000000000000000003 /* PunktfunkClient */, + ); + name = Punktfunk; + packageProductDependencies = ( + AA0000000000000000000006 /* PunktfunkKit */, + ); + productName = Punktfunk; + productReference = AA0000000000000000000001 /* Punktfunk.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + AA000000000000000000000D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 2600; + TargetAttributes = { + AA0000000000000000000009 = { + CreatedOnToolsVersion = 26.0; + }; + }; + }; + buildConfigurationList = AA000000000000000000000E /* Build configuration list for PBXProject "Punktfunk" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = AA0000000000000000000007; + packageReferences = ( + AA000000000000000000000F /* XCLocalSwiftPackageReference "." */, + ); + preferredProjectObjectVersion = 77; + productRefGroup = AA0000000000000000000008 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + AA0000000000000000000009 /* Punktfunk */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + AA000000000000000000000C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + AA000000000000000000000B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + AA0000000000000000000010 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + MACOSX_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + AA0000000000000000000011 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + AA0000000000000000000012 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 0.1; + PRODUCT_BUNDLE_IDENTIFIER = io.unom.punktfunk; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + AA0000000000000000000013 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = NSApplication; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 0.1; + PRODUCT_BUNDLE_IDENTIFIER = io.unom.punktfunk; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + AA000000000000000000000A /* Build configuration list for PBXNativeTarget "Punktfunk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AA0000000000000000000012 /* Debug */, + AA0000000000000000000013 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AA000000000000000000000E /* Build configuration list for PBXProject "Punktfunk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AA0000000000000000000010 /* Debug */, + AA0000000000000000000011 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + AA000000000000000000000F /* XCLocalSwiftPackageReference "." */ = { + isa = XCLocalSwiftPackageReference; + relativePath = "."; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + AA0000000000000000000006 /* PunktfunkKit */ = { + isa = XCSwiftPackageProductDependency; + productName = PunktfunkKit; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = AA000000000000000000000D /* Project object */; +} diff --git a/clients/apple/Punktfunk.xcodeproj/xcshareddata/xcschemes/Punktfunk.xcscheme b/clients/apple/Punktfunk.xcodeproj/xcshareddata/xcschemes/Punktfunk.xcscheme new file mode 100644 index 0000000..d947e69 --- /dev/null +++ b/clients/apple/Punktfunk.xcodeproj/xcshareddata/xcschemes/Punktfunk.xcscheme @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clients/apple/README.md b/clients/apple/README.md index 4687983..e9e375d 100644 --- a/clients/apple/README.md +++ b/clients/apple/README.md @@ -54,7 +54,8 @@ rustup target add aarch64-apple-darwin x86_64-apple-darwin bash scripts/build-xcframework.sh # → clients/apple/PunktfunkCore.xcframework cd clients/apple swift build && swift test # loopback/remote tests self-skip without a host -swift run PunktfunkClient # the app; or open Package.swift in Xcode +swift run PunktfunkClient # the unbundled dev shell (CLI) +open Punktfunk.xcodeproj # the real app: ⌘R builds + runs Punktfunk.app bash test-loopback.sh # full loopback proof: builds punktfunk-host # (synthetic source — runs on macOS), streams @@ -68,6 +69,24 @@ PUNKTFUNK_REMOTE_HOST= swift test --filter RemoteFirstLightTests # hea PUNKTFUNK_AUTOCONNECT= PUNKTFUNK_MODE=1280x720x60 swift run PunktfunkClient # on glass ``` +## Xcode project (`Punktfunk.xcodeproj`) + +The app target **Punktfunk** wraps the same sources as the `swift run` shell +(`Sources/PunktfunkClient`, a synchronized folder — no duplication) plus `App/` (asset +catalog) and links `PunktfunkKit` from the local package. Generated Info.plist, ad-hoc +signing, bundle id `io.unom.punktfunk`. Notes: + +- **App icon**: `App/Assets.xcassets` ships an empty `AppIcon` slot. For an Icon Composer + `.icon`: add the file to the project (target Punktfunk), set it as the App Icon in the + target's General tab, and delete the placeholder `AppIcon.appiconset`. Heads-up: CLI + `actool` (Xcode 26.5) crashed compiling `punktfunk_Logo.icon` — if Xcode does the same, + suspect the icon bundle (it has a duplicate-named layer, "…Layer-3 2.svg"), not the + project. +- **Tests from Xcode**: the package tests run with `swift test`; to get them on ⌘U, add + `PunktfunkKitTests` once via Edit Scheme → Test → + (Xcode persists it into the shared + scheme — a hand-written package-test reference doesn't resolve headlessly). +- `xcodebuild -project Punktfunk.xcodeproj -scheme Punktfunk build` works headlessly. + ## Notes for whoever picks this up next 1. **cbindgen import quirk** (the predicted "small compile fixes", now fixed): the