feat(T-2.0): Xcode project scaffold — SwiftUI shell, SwiftTerm + Starscream SPM deps

- xcodegen project.yml: de.vpsj.pi-remote, team KNXX8R3648, iOS 17+
- SwiftTerm 1.13.0, Starscream 4.0.8 resolved
- App entry point + ContentView hello shell
- Push Notifications entitlement (aps-environment: development)
- pi-remote:// URL scheme registered
- NSCameraUsageDescription (QR pairing), NSFaceIDUsageDescription
- UIBackgroundModes: remote-notification
This commit is contained in:
Johannes Merz 2026-05-15 13:19:48 +02:00
commit aa010cf874
14 changed files with 974 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Xcode
build/
DerivedData/
*.xcuserstate
*.xcuserdatad/
*.xcworkspace/xcuserdata/
xcuserdata/
# SPM
.build/
.swiftpm/
*.resolved
# macOS
.DS_Store
# Credentials — never commit
*.p8
*.p12
*.cer
secrets/

59
README.md Normal file
View File

@ -0,0 +1,59 @@
# pi-remote iOS
Native iOS app for the [pi-remote-control](https://git.vpsj.de/jay/pi-remote-control) sidecar.
## Requirements
- Xcode 16.4+
- iOS 17.0+ device
- pi-remote-control sidecar running (Phase 1)
## Building
```bash
# Open in Xcode (first time: Xcode downloads device support files automatically)
open piRemote.xcodeproj
# Or via CLI (after first Xcode open with device connected):
xcodebuild build -project piRemote.xcodeproj -scheme piRemote \
-destination "platform=iOS,name=<YourPhone>" \
CODE_SIGNING_STYLE=Automatic DEVELOPMENT_TEAM=KNXX8R3648
```
## Project structure
```
Sources/
├── App/ — @main entry, ContentView, Assets
├── Core/
│ ├── Network/ — WebSocketClient, FrameCodec, ResumeCursor, TLS pinning
│ ├── Auth/ — Keychain, Pairing (QR exchange)
│ ├── Sessions/ — SessionRegistry, SessionConnection, PreConnectPool
│ ├── Push/ — APNs NotificationDelegate, DeviceTokenRegistrar
│ └── Persistence/ — ScrollbackCache, Preferences
└── UI/
├── Terminal/ — SwiftTerm wrapper, themes, fonts
├── Input/ — ModifierBar, sticky Ctrl, paste sheet
├── Status/ — StatusBar (pi state)
├── Sessions/ — SessionSwitcher
├── Pairing/ — QR scanner flow
└── Settings/ — Face-ID gate, sidecar info
```
## Dependencies (via SPM)
- [SwiftTerm](https://github.com/migueldeicaza/SwiftTerm) — terminal emulator
- [Starscream](https://github.com/daltoniam/Starscream) — WebSocket client
## Apple Developer setup (one-time)
1. In [Apple Developer Portal](https://developer.apple.com/account):
- Create App ID: `de.vpsj.pi-remote`, enable **Push Notifications**
- Generate an **APNs Auth Key** (`.p8`) — *download once, keep safe*
- Note your **Key ID** and **Team ID** (`KNXX8R3648`)
2. Copy `.p8` key to `~/.local/share/pi-remote/apns/AuthKey_<KeyID>.p8`
3. Update `[apns]` section in pi-remote-control config
## Status
Phase 2 — in development. See `pi-remote-control/docs/PHASE-2-ios-mvp.md`.

View File

@ -0,0 +1,4 @@
{
"colors": [{"idiom": "universal"}],
"info": { "author": "xcode", "version": 1 }
}

View File

@ -0,0 +1 @@
{ "images": [], "info": { "author": "xcode", "version": 1 } }

View File

@ -0,0 +1 @@
{ "info": { "author": "xcode", "version": 1 } }

View File

@ -0,0 +1,22 @@
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 16) {
Image(systemName: "terminal")
.imageScale(.large)
.font(.system(size: 60))
.foregroundStyle(.green)
Text("pi remote")
.font(.largeTitle.monospaced())
Text("Phase 2 — in development")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding()
}
}
#Preview {
ContentView()
}

50
Sources/App/Info.plist Normal file
View File

@ -0,0 +1,50 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>pi-remote</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSCameraUsageDescription</key>
<string>Used to scan QR codes for pairing.</string>
<key>NSFaceIDUsageDescription</key>
<string>Protects access to your pi sessions.</string>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchScreen</key>
<dict>
<key>UIColorName</key>
<string></string>
</dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1 @@
{ "info": { "author": "xcode", "version": 1 } }

View File

@ -0,0 +1,5 @@
<?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/>
</plist>

View File

@ -0,0 +1,10 @@
import SwiftUI
@main
struct piRemoteApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

View File

@ -0,0 +1,605 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D747BC787A24B4E225B142 /* piRemoteApp.swift */; };
56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFF032BC30D513204211ADA5 /* Assets.xcassets */; };
873DC9D5342E8F4AF2C5BEE9 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = CCBD990EEA7AD9DCF714DF97 /* Starscream */; };
D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */; };
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188683139B863ED1AC03A1BB /* ContentView.swift */; };
FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = D095700C52C60FDA2CB38679 /* SwiftTerm */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
B301DDFED8092F66145718E3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B5A2356AA5371FBA25136FA6 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4910ACCEB67B73CBA3440774;
remoteInfo = piRemote;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0E401DECD467A1D3AB030610 /* piRemote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = piRemote.entitlements; sourceTree = "<group>"; };
188683139B863ED1AC03A1BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
2E2370A3190FDC144C822FF6 /* piRemote.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = piRemote.app; sourceTree = BUILT_PRODUCTS_DIR; };
658CB2FCA96A8913B1753B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
73D747BC787A24B4E225B142 /* piRemoteApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = piRemoteApp.swift; sourceTree = "<group>"; };
AFF032BC30D513204211ADA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C346201325F7F2939EB7A792 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */,
873DC9D5342E8F4AF2C5BEE9 /* Starscream in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
161D89B853288EC766A0767D /* Products */ = {
isa = PBXGroup;
children = (
2E2370A3190FDC144C822FF6 /* piRemote.app */,
CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
1909DBD374F6922644BF6B4D /* Sessions */ = {
isa = PBXGroup;
children = (
);
path = Sessions;
sourceTree = "<group>";
};
35A8DD31F76D71B8CDCDDC8D /* Core */ = {
isa = PBXGroup;
children = (
ED7AFC5C0EF365C5831C7245 /* Auth */,
DCF268D44CD471E86B6192B0 /* Network */,
D484C43F0BAEF3990BB88D8F /* Persistence */,
8E5B4A1E4AE8D09F6E581E02 /* Push */,
1909DBD374F6922644BF6B4D /* Sessions */,
);
path = Core;
sourceTree = "<group>";
};
35F24B7F065B257F93810E5B /* Sessions */ = {
isa = PBXGroup;
children = (
);
path = Sessions;
sourceTree = "<group>";
};
49209A78102230A37C0FF8D0 /* Terminal */ = {
isa = PBXGroup;
children = (
);
path = Terminal;
sourceTree = "<group>";
};
58E55A616A534D72FF9D4299 /* Preview Content */ = {
isa = PBXGroup;
children = (
6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
69990A9885FB5B354E73AB90 /* Tests */ = {
isa = PBXGroup;
children = (
C06242078CD1DD2BD7C7A4FA /* CoreTests */,
);
path = Tests;
sourceTree = "<group>";
};
8A477F7D38B42EEB3F70323F /* Pairing */ = {
isa = PBXGroup;
children = (
);
path = Pairing;
sourceTree = "<group>";
};
8E5B4A1E4AE8D09F6E581E02 /* Push */ = {
isa = PBXGroup;
children = (
);
path = Push;
sourceTree = "<group>";
};
9B44B95A69D3C0C00BCF32FB = {
isa = PBXGroup;
children = (
C8D95B3C16FEE9C9FBE38FDE /* Sources */,
69990A9885FB5B354E73AB90 /* Tests */,
161D89B853288EC766A0767D /* Products */,
);
sourceTree = "<group>";
};
9DF960DFB90BF425282C35D0 /* Input */ = {
isa = PBXGroup;
children = (
);
path = Input;
sourceTree = "<group>";
};
C06242078CD1DD2BD7C7A4FA /* CoreTests */ = {
isa = PBXGroup;
children = (
);
path = CoreTests;
sourceTree = "<group>";
};
C7FBB3C467939760D2971070 /* Status */ = {
isa = PBXGroup;
children = (
);
path = Status;
sourceTree = "<group>";
};
C8D95B3C16FEE9C9FBE38FDE /* Sources */ = {
isa = PBXGroup;
children = (
ECEA8716C9698DDD14367AC9 /* App */,
35A8DD31F76D71B8CDCDDC8D /* Core */,
E68CFF24811DAA2A2ACE2EB3 /* UI */,
);
path = Sources;
sourceTree = "<group>";
};
D484C43F0BAEF3990BB88D8F /* Persistence */ = {
isa = PBXGroup;
children = (
);
path = Persistence;
sourceTree = "<group>";
};
DCF268D44CD471E86B6192B0 /* Network */ = {
isa = PBXGroup;
children = (
);
path = Network;
sourceTree = "<group>";
};
E68CFF24811DAA2A2ACE2EB3 /* UI */ = {
isa = PBXGroup;
children = (
9DF960DFB90BF425282C35D0 /* Input */,
8A477F7D38B42EEB3F70323F /* Pairing */,
35F24B7F065B257F93810E5B /* Sessions */,
F681ED5F43C5283558361FAC /* Settings */,
C7FBB3C467939760D2971070 /* Status */,
49209A78102230A37C0FF8D0 /* Terminal */,
);
path = UI;
sourceTree = "<group>";
};
ECEA8716C9698DDD14367AC9 /* App */ = {
isa = PBXGroup;
children = (
AFF032BC30D513204211ADA5 /* Assets.xcassets */,
188683139B863ED1AC03A1BB /* ContentView.swift */,
658CB2FCA96A8913B1753B1C /* Info.plist */,
0E401DECD467A1D3AB030610 /* piRemote.entitlements */,
73D747BC787A24B4E225B142 /* piRemoteApp.swift */,
58E55A616A534D72FF9D4299 /* Preview Content */,
);
path = App;
sourceTree = "<group>";
};
ED7AFC5C0EF365C5831C7245 /* Auth */ = {
isa = PBXGroup;
children = (
);
path = Auth;
sourceTree = "<group>";
};
F681ED5F43C5283558361FAC /* Settings */ = {
isa = PBXGroup;
children = (
);
path = Settings;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */;
buildPhases = (
6DDDB771E08071591D668B0A /* Sources */,
);
buildRules = (
);
dependencies = (
2965A47833122165B123DA9B /* PBXTargetDependency */,
);
name = piRemoteTests;
packageProductDependencies = (
);
productName = piRemoteTests;
productReference = CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
4910ACCEB67B73CBA3440774 /* piRemote */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7D4FC8D9F69801EED9D13DA7 /* Build configuration list for PBXNativeTarget "piRemote" */;
buildPhases = (
26E05B31335CA4B7811BD0F7 /* Sources */,
31D09DC5D7BBE74682559B5C /* Resources */,
C346201325F7F2939EB7A792 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = piRemote;
packageProductDependencies = (
D095700C52C60FDA2CB38679 /* SwiftTerm */,
CCBD990EEA7AD9DCF714DF97 /* Starscream */,
);
productName = piRemote;
productReference = 2E2370A3190FDC144C822FF6 /* piRemote.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
B5A2356AA5371FBA25136FA6 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1640;
TargetAttributes = {
2C3DD20A67B90DDE04FDEE41 = {
DevelopmentTeam = KNXX8R3648;
ProvisioningStyle = Automatic;
};
4910ACCEB67B73CBA3440774 = {
DevelopmentTeam = KNXX8R3648;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 193C24354F678E5C0C3CC4D1 /* Build configuration list for PBXProject "piRemote" */;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Base,
en,
);
mainGroup = 9B44B95A69D3C0C00BCF32FB;
minimizedProjectReferenceProxies = 1;
packageReferences = (
310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */,
D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 161D89B853288EC766A0767D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
4910ACCEB67B73CBA3440774 /* piRemote */,
2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
31D09DC5D7BBE74682559B5C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */,
D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
26E05B31335CA4B7811BD0F7 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */,
30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
6DDDB771E08071591D668B0A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
2965A47833122165B123DA9B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4910ACCEB67B73CBA3440774 /* piRemote */;
targetProxy = B301DDFED8092F66145718E3 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
0E6C5BC837AB6537852A7F92 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.vpsj.piRemoteTests;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/piRemote.app/piRemote";
};
name = Debug;
};
2E146A9E4FCF9F393A9D41C0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Sources/App/piRemote.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = Sources/App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
30909A3060849FE14F196221 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = KNXX8R3648;
ENABLE_BITCODE = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"DEBUG=1",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
MARKETING_VERSION = 0.1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 6.0;
};
name = Debug;
};
3C99CD7AE03C725305B787EA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = KNXX8R3648;
ENABLE_BITCODE = NO;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
MARKETING_VERSION = 0.1.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 6.0;
};
name = Release;
};
BCA8D933602A624F296AC6AB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Sources/App/piRemote.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = Sources/App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
BCD063DCDE72A18833A2C42B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.vpsj.piRemoteTests;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/piRemote.app/piRemote";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
193C24354F678E5C0C3CC4D1 /* Build configuration list for PBXProject "piRemote" */ = {
isa = XCConfigurationList;
buildConfigurations = (
30909A3060849FE14F196221 /* Debug */,
3C99CD7AE03C725305B787EA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
7D4FC8D9F69801EED9D13DA7 /* Build configuration list for PBXNativeTarget "piRemote" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BCA8D933602A624F296AC6AB /* Debug */,
2E146A9E4FCF9F393A9D41C0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0E6C5BC837AB6537852A7F92 /* Debug */,
BCD063DCDE72A18833A2C42B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/daltoniam/Starscream";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.0.0;
};
};
D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/migueldeicaza/SwiftTerm";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.2.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
CCBD990EEA7AD9DCF714DF97 /* Starscream */ = {
isa = XCSwiftPackageProductDependency;
package = 310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */;
productName = Starscream;
};
D095700C52C60FDA2CB38679 /* SwiftTerm */ = {
isa = XCSwiftPackageProductDependency;
package = D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */;
productName = SwiftTerm;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = B5A2356AA5371FBA25136FA6 /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1640"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4910ACCEB67B73CBA3440774"
BuildableName = "piRemote.app"
BlueprintName = "piRemote"
ReferencedContainer = "container:piRemote.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
onlyGenerateCoverageForSpecifiedTargets = "NO">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4910ACCEB67B73CBA3440774"
BuildableName = "piRemote.app"
BlueprintName = "piRemote"
ReferencedContainer = "container:piRemote.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2C3DD20A67B90DDE04FDEE41"
BuildableName = "piRemoteTests.xctest"
BlueprintName = "piRemoteTests"
ReferencedContainer = "container:piRemote.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<CommandLineArguments>
</CommandLineArguments>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4910ACCEB67B73CBA3440774"
BuildableName = "piRemote.app"
BlueprintName = "piRemote"
ReferencedContainer = "container:piRemote.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4910ACCEB67B73CBA3440774"
BuildableName = "piRemote.app"
BlueprintName = "piRemote"
ReferencedContainer = "container:piRemote.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

84
project.yml Normal file
View File

@ -0,0 +1,84 @@
name: piRemote
options:
bundleIdPrefix: de.vpsj
deploymentTarget:
iOS: "17.0"
xcodeVersion: "16.4"
generateEmptyDirectories: true
createIntermediateGroups: true
settings:
base:
SWIFT_VERSION: 6.0
MARKETING_VERSION: 0.1.0
CURRENT_PROJECT_VERSION: 1
DEVELOPMENT_TEAM: KNXX8R3648
CODE_SIGN_STYLE: Automatic
ENABLE_BITCODE: NO
packages:
SwiftTerm:
url: https://github.com/migueldeicaza/SwiftTerm
from: 1.2.0
Starscream:
url: https://github.com/daltoniam/Starscream
from: 4.0.0
schemes:
piRemote:
build:
targets:
piRemote: all
run:
config: Debug
test:
config: Debug
targets:
- piRemoteTests
archive:
config: Release
targets:
piRemote:
type: application
platform: iOS
deploymentTarget: "17.0"
sources:
- path: Sources
resources:
- path: Sources/App/Assets.xcassets
- path: Sources/App/Preview Content
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: de.vpsj.pi-remote
INFOPLIST_FILE: Sources/App/Info.plist
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
entitlements:
path: Sources/App/piRemote.entitlements
dependencies:
- package: SwiftTerm
- package: Starscream
info:
path: Sources/App/Info.plist
properties:
UILaunchScreen:
UIColorName: ""
UISupportedInterfaceOrientations:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
NSCameraUsageDescription: "Used to scan QR codes for pairing."
NSFaceIDUsageDescription: "Protects access to your pi sessions."
UIBackgroundModes:
- remote-notification
CFBundleURLTypes:
- CFBundleURLSchemes:
- pi-remote
piRemoteTests:
type: bundle.unit-test
platform: iOS
sources:
- path: Tests/CoreTests
dependencies:
- target: piRemote