commit e058e0e2215fa7753671ec009c863fc0a0162e3a
parent f112a7c07d44ca85cdb7eb3a929663ed7b4d1796
Author: triesap <tyson@radroots.org>
Date: Sat, 8 Aug 2026 03:40:36 +0000
feat(ios): publish deterministic app package
- Export the app module with an external-consumer API contract.
- Pin public dependencies and validate privacy, version, and FFI locks.
- Route SwiftPM and Xcode outputs through reproducible extbuild lanes.
- Prove standalone bootstrap, offline tests, and bounded cleanup.
Diffstat:
30 files changed, 697 insertions(+), 349 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -18,7 +18,6 @@
**/*.rs.bk
# Generated artifacts
-Radroots/radroots.git.xcconfig
RadrootsKit/Artifacts/
RadrootsKit/Sources/RadrootsKit/Generated/
Radroots/Frameworks/RadrootsFFI.xcframework/
diff --git a/Makefile b/Makefile
@@ -1,9 +1,68 @@
+SHELL := /bin/bash
+.SHELLFLAGS := -eu -o pipefail -c
+
FFI_ROOT := RadrootsFFI
+SIMULATOR_NAME ?= iPhone 17 Pro
+SIMULATOR_DESTINATION := platform=iOS Simulator,name=$(SIMULATOR_NAME)
+
+.NOTPARALLEL:
+
+.PHONY: all bootstrap ffi-bootstrap artifact-check package-contract-check \
+ package-resolve package-build package-test project xcodegen xcode-resolve \
+ xcode-build-debug xcode-build-release unit-test ui-test api-snapshot-write \
+ api-snapshot-check verify clean distclean
+
+all: verify
+
+ffi-bootstrap:
+ cargo extbuild run -- $(MAKE) -C $(FFI_ROOT) verify
-.PHONY: all clean distclean sync-source build generate package install api-snapshot-write api-snapshot-check provenance verify print-config project xcodegen
+artifact-check:
+ cargo extbuild run -- $(FFI_ROOT)/scripts/verify-installed-artifacts.sh
-all clean distclean sync-source build generate package install api-snapshot-write api-snapshot-check provenance verify print-config:
- cargo extbuild run -- $(MAKE) -C $(FFI_ROOT) $@
+package-contract-check:
+ cargo extbuild run -- scripts/verify-package-contract.sh
+
+package-resolve: artifact-check package-contract-check
+ cargo extbuild run -- scripts/swift-package.sh resolve
project xcodegen:
- cargo extbuild run -- xcodegen generate --spec project.yml
+ cargo extbuild run -- scripts/generate-project.sh
+
+xcode-resolve: artifact-check project
+ cargo extbuild run -- scripts/xcode.sh resolve
+
+bootstrap: ffi-bootstrap package-resolve xcode-resolve
+
+package-build: artifact-check package-contract-check
+ cargo extbuild run -- scripts/xcode.sh package-build
+
+package-test: artifact-check package-contract-check
+ cargo extbuild run -- scripts/xcode.sh package-test '$(SIMULATOR_DESTINATION)'
+
+xcode-build-debug: artifact-check package-contract-check project
+ cargo extbuild run -- scripts/xcode.sh project-build Debug
+
+xcode-build-release: artifact-check package-contract-check project
+ cargo extbuild run -- scripts/xcode.sh project-build Release
+
+unit-test: artifact-check package-contract-check project
+ cargo extbuild run -- scripts/xcode.sh project-test '$(SIMULATOR_DESTINATION)' RadrootsTests
+
+ui-test: artifact-check package-contract-check project
+ cargo extbuild run -- scripts/xcode.sh project-test '$(SIMULATOR_DESTINATION)' RadrootsUITests
+
+api-snapshot-write: package-build
+ cargo extbuild run -- scripts/app-api-snapshot.sh write
+
+api-snapshot-check: package-build
+ cargo extbuild run -- scripts/app-api-snapshot.sh check
+
+verify: artifact-check package-contract-check package-build package-test \
+ xcode-build-debug xcode-build-release unit-test ui-test api-snapshot-check
+
+clean:
+ cargo extbuild run -- $(MAKE) -C $(FFI_ROOT) clean
+
+distclean:
+ cargo extbuild run -- $(MAKE) -C $(FFI_ROOT) distclean
diff --git a/Package.resolved b/Package.resolved
@@ -0,0 +1,22 @@
+{
+ "originHash" : "0a61041d0e86aa3523400309ba62b6cb333fffd0d0e2b52fba38a8554689bff0",
+ "pins" : [
+ {
+ "identity" : "apple_kit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/radrootslabs/apple_kit.git",
+ "state" : {
+ "revision" : "af6047761cd445e8861e11b7df15b1fc52c1fbbf"
+ }
+ },
+ {
+ "identity" : "swift-secp256k1",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/21-DOT-DEV/swift-secp256k1.git",
+ "state" : {
+ "revision" : "e70a10e036a55fffea31568f0af92d69b6d449cd"
+ }
+ }
+ ],
+ "version" : 3
+}
diff --git a/Package.swift b/Package.swift
@@ -0,0 +1,85 @@
+// swift-tools-version: 6.0
+
+import PackageDescription
+
+let package = Package(
+ name: "radroots_ios_app",
+ platforms: [
+ .iOS(.v18),
+ ],
+ products: [
+ .library(name: "RadrootsApp", targets: ["RadrootsApp"]),
+ ],
+ dependencies: [
+ .package(
+ url: "https://github.com/radrootslabs/apple_kit.git",
+ revision: "af6047761cd445e8861e11b7df15b1fc52c1fbbf"
+ ),
+ ],
+ targets: [
+ .binaryTarget(
+ name: "RadrootsFFI",
+ path: "Radroots/Frameworks/RadrootsFFI.xcframework"
+ ),
+ .target(
+ name: "RadrootsKitBindings",
+ dependencies: ["RadrootsFFI"],
+ path: "Radroots/Generated",
+ swiftSettings: [
+ .swiftLanguageMode(.v5),
+ ]
+ ),
+ .target(
+ name: "RadrootsApp",
+ dependencies: [
+ "RadrootsKitBindings",
+ .product(name: "RadrootsKit", package: "apple_kit"),
+ ],
+ path: "Radroots",
+ exclude: [
+ "App/App.swift",
+ "Config",
+ "Frameworks",
+ "Generated",
+ "Info.plist",
+ "radroots.xcconfig",
+ ],
+ sources: [
+ "App/AppEntry.swift",
+ "App/RadrootsAppDelegate.swift",
+ "App/RadrootsAppModel.swift",
+ "App/RadrootsProvider.swift",
+ "App/RadrootsRootShell.swift",
+ "Runtime/RadrootsAddMediaCoordinator.swift",
+ "Runtime/RadrootsGeneratedRuntimeBackend.swift",
+ "Runtime/RadrootsLifecycleCoordinator.swift",
+ "Runtime/RadrootsRuntimeClient.swift",
+ "Runtime/RadrootsRuntimeModels.swift",
+ "State/RadrootsAddStore.swift",
+ "State/RadrootsConfigurationStore.swift",
+ "State/RadrootsIdentityStore.swift",
+ "State/RadrootsSessionStore.swift",
+ "State/RadrootsSupportingStores.swift",
+ "State/RadrootsTodayStore.swift",
+ "Views/RadrootsAddView.swift",
+ "Views/RadrootsSupportingViews.swift",
+ "Views/RadrootsTodayView.swift",
+ "Views/RuntimeStatusView.swift",
+ ],
+ resources: [
+ .process("Resources/PrivacyInfo.xcprivacy"),
+ ]
+ ),
+ .testTarget(
+ name: "RadrootsAppTests",
+ dependencies: ["RadrootsApp"],
+ path: "RadrootsTests"
+ ),
+ .testTarget(
+ name: "RadrootsAppPublicAPITests",
+ dependencies: ["RadrootsApp"],
+ path: "RadrootsPublicAPITests"
+ ),
+ ],
+ swiftLanguageModes: [.v6]
+)
diff --git a/README.md b/README.md
@@ -0,0 +1,50 @@
+# Radroots iOS App
+
+Radroots is a public iOS 18 app for discovering and publishing local farm
+updates, asks, in-person events, and food listings over Nostr. The product has
+exactly two bottom tabs: Today for discovery and Add for authored operations.
+
+The current public release is `0.1.0-alpha`.
+
+## Requirements
+
+- macOS with Xcode and an iOS 18-or-newer simulator
+- XcodeGen
+- Rust `1.97.1-aarch64-apple-darwin` with the iOS device and simulator targets
+- `cargo-extbuild` configured for the checkout
+
+## Bootstrap and verify
+
+The first bootstrap requires network access. It checks out the exact Rust
+source revision, builds the deterministic UniFFI XCFramework and Swift
+bindings, resolves exact Swift package revisions, and generates the Xcode
+project:
+
+```sh
+cargo extbuild doctor
+make bootstrap
+```
+
+After bootstrap, the complete package and Xcode build/test lane uses the
+resolved revisions without automatic dependency updates:
+
+```sh
+make verify
+```
+
+Use `SIMULATOR_NAME="Device Name" make verify` when the default simulator is
+not installed. `make clean` removes only rebuildable external build output and
+the ignored XCFramework; it preserves tracked generated bindings, locks,
+snapshots, project sources, and user files.
+
+## Package surface
+
+`Package.swift` publishes the `RadrootsApp` library used by the generated Xcode
+application wrapper. It pins AppleKit by exact HTTPS Git revision and consumes
+the locally bootstrapped `RadrootsFFI.xcframework`. Ordinary Xcode compilation
+never writes repository source: a read-only preflight rejects missing or stale
+FFI artifacts and directs the developer to run `make bootstrap`.
+
+The Rust source lock, generated bindings, XCFramework hashes, provenance, Swift
+package locks, privacy manifests, and public API snapshots are checked as part
+of the release lane.
diff --git a/Radroots.xcodeproj/project.pbxproj b/Radroots.xcodeproj/project.pbxproj
@@ -7,51 +7,23 @@
objects = {
/* Begin PBXBuildFile section */
- 0486BFE6223D0FF0ACFA4249 /* RadrootsAddStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E3E5B1D1A0E1A32A83100 /* RadrootsAddStore.swift */; };
+ 0376BB3ECA35B44625702BFE /* RadrootsApp in Frameworks */ = {isa = PBXBuildFile; productRef = E17BA8C6979DF56FB5F385B8 /* RadrootsApp */; };
27B7FB991398E2BE7034C72E /* RadrootsAddStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C296DF1E35100FE59C04D3 /* RadrootsAddStoreTests.swift */; };
- 27F796571E92A6589E0111E3 /* RadrootsKitBindings.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF8CEF5491290B1218ACFCE7 /* RadrootsKitBindings.framework */; };
- 3233513A881D056514142457 /* RadrootsAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3D78A3EDB345DB46C8E547 /* RadrootsAppDelegate.swift */; };
3BCAFE2B1A96BBE5D741D8FC /* RadrootsSupportingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41B94CEAFD958CE92D6B9265 /* RadrootsSupportingStoreTests.swift */; };
- 3C16EC0B109F76EEE8D3031A /* RadrootsSupportingStores.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478127DF070D6065A282C44A /* RadrootsSupportingStores.swift */; };
- 41B5CB28ACA51221A1BA59D5 /* RadrootsSessionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76F84D4706216F743E373F2A /* RadrootsSessionStore.swift */; };
- 47D9564F81A5E7CEA86B759C /* RadrootsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C4A7EB045E43F109C4DCA1 /* RadrootsProvider.swift */; };
- 499BCC8FC845FDD77E74FD99 /* RadrootsTodayStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6A6D1850A21E5516060E5E /* RadrootsTodayStore.swift */; };
- 509FF909EFFD7FD9BAEC537C /* RadrootsRootShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF529B919921D63157110E44 /* RadrootsRootShell.swift */; };
51FE0A95B71A5D4EDCEB0748 /* RadrootsStateMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26D512B6CBD1A9BE4780682 /* RadrootsStateMigrationTests.swift */; };
- 5DAE76BBC71E4A192E029785 /* RadrootsGeneratedRuntimeBackend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B14CE9958D4C71AFB41D2DD /* RadrootsGeneratedRuntimeBackend.swift */; };
- 69326B7DA05C115D0055AD13 /* RadrootsKitBindings.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FF8CEF5491290B1218ACFCE7 /* RadrootsKitBindings.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- 74082509C257766A166662FA /* RadrootsAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 343F115F383EB9C8A796AC9C /* RadrootsAppModel.swift */; };
- 75275CDCE16FB99248793AB4 /* RadrootsSupportingViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29DD502141AA86FD5C948618 /* RadrootsSupportingViews.swift */; };
+ 60B853393C8DF4FDF2C01CAF /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 81E991EAE0A0EAB4853747C6 /* PrivacyInfo.xcprivacy */; };
75C044403AF08F7230DE9485 /* RadrootsRootShellUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF484F988B3D1D3D81880388 /* RadrootsRootShellUITests.swift */; };
- 7A1131CC1E9308706ECE4B7B /* RadrootsLifecycleCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DAAFF0BC944ECC04D0BDF41 /* RadrootsLifecycleCoordinator.swift */; };
7CF6D05AC3F7C8CAD56E3A91 /* RadrootsRootShellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F89E4B3A775E88F661B891 /* RadrootsRootShellTests.swift */; };
- 86DF51D41F92E1A695D83205 /* RadrootsTodayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78F57CD1A43D46EE8CB35591 /* RadrootsTodayView.swift */; };
- AA7D80A73CD6C22ED5080781 /* RadrootsKitBindings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879C89400666972D90996AE5 /* RadrootsKitBindings.swift */; };
- B356719A54375706DBBDC118 /* RadrootsRuntimeModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDB24124BB8917DBB49EC2C /* RadrootsRuntimeModels.swift */; };
- BB932CEEA2713588E14AC3ED /* RadrootsAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0C073F20D8716C60FCCF2C /* RadrootsAddView.swift */; };
C356F2A068722087ED91256C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 298DA81B0A000E307098C840 /* Assets.xcassets */; };
- CA827A410369AC55B0FEE305 /* RuntimeStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9469790A906080D90F8735CB /* RuntimeStatusView.swift */; };
- CAD7B38817DC65AAF19576F7 /* RadrootsFFI.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD7B47A576C4D5CE9318D3E6 /* RadrootsFFI.xcframework */; };
CD88BB6222151E0B8242F84A /* RadrootsLifecycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D95CB1F4A964D87D2256DA9C /* RadrootsLifecycleTests.swift */; };
CEED5B97CB1F94445162D662 /* RadrootsRuntimeClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0451E8A8521D320172FFA35 /* RadrootsRuntimeClientTests.swift */; };
- D03C81CCF4FBC6D7D5634D35 /* RadrootsConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF9FBA655BDA52E08FB62EED /* RadrootsConfigurationStore.swift */; };
+ D86E464EADF0C7904AB2FF90 /* RadrootsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 54C7F50B545852A8B313DAA7 /* RadrootsKit */; };
E236CCF8D8F8AC12AF59932E /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397ED29DF8E9BF73B4BBFDEC /* App.swift */; };
- ED326EC0067A550727A1680D /* AppEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0D9C4E6CAE584304521D08 /* AppEntry.swift */; };
- F3E40E5A76B4EA19AC7603D2 /* RadrootsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2DAD90EBF8EB00ACDD7611CD /* RadrootsKit */; };
- F6F36A06BD77BCFA64FC3541 /* RadrootsIdentityStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D0BC5AE5000DE34D9303379 /* RadrootsIdentityStore.swift */; };
- F7EEF54776B037D98F389AD6 /* RadrootsRuntimeClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F5216F7C18E2EE21B8528A /* RadrootsRuntimeClient.swift */; };
- F9EA6E6935307271FF920B7D /* RadrootsAddMediaCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7098C419BAC4E8E058A2B3C2 /* RadrootsAddMediaCoordinator.swift */; };
+ F3E40E5A76B4EA19AC7603D2 /* RadrootsApp in Frameworks */ = {isa = PBXBuildFile; productRef = 5EB99D569A31C7F8987A9440 /* RadrootsApp */; };
FE9376121B0780485673EC06 /* RadrootsTodayStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D91770F919A06DB39186281B /* RadrootsTodayStoreTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 51F4BD021D143679140FF35F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 572C41532B5066EC7641561C /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 1C22115E511334B291A71594;
- remoteInfo = RadrootsKitBindings;
- };
5B242C3EC56D6F3216103D77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 572C41532B5066EC7641561C /* Project object */;
@@ -68,76 +40,41 @@
};
/* End PBXContainerItemProxy section */
-/* Begin PBXCopyFilesBuildPhase section */
- 271D40E26A903BC9F058633E /* Embed Frameworks */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 10;
- files = (
- 69326B7DA05C115D0055AD13 /* RadrootsKitBindings.framework in Embed Frameworks */,
- );
- name = "Embed Frameworks";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
/* Begin PBXFileReference section */
298DA81B0A000E307098C840 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
- 29DD502141AA86FD5C948618 /* RadrootsSupportingViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsSupportingViews.swift; sourceTree = "<group>"; };
- 2A6A6D1850A21E5516060E5E /* RadrootsTodayStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsTodayStore.swift; sourceTree = "<group>"; };
- 2D0BC5AE5000DE34D9303379 /* RadrootsIdentityStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsIdentityStore.swift; sourceTree = "<group>"; };
30A8A8321A8A261F6D1B480D /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
318804462AADCA05FB04ACD9 /* RadrootsTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = RadrootsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 343F115F383EB9C8A796AC9C /* RadrootsAppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAppModel.swift; sourceTree = "<group>"; };
397ED29DF8E9BF73B4BBFDEC /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
- 3DDB24124BB8917DBB49EC2C /* RadrootsRuntimeModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRuntimeModels.swift; sourceTree = "<group>"; };
41B94CEAFD958CE92D6B9265 /* RadrootsSupportingStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsSupportingStoreTests.swift; sourceTree = "<group>"; };
42C296DF1E35100FE59C04D3 /* RadrootsAddStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAddStoreTests.swift; sourceTree = "<group>"; };
43B0EA447E213CD1B96846D6 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
- 478127DF070D6065A282C44A /* RadrootsSupportingStores.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsSupportingStores.swift; sourceTree = "<group>"; };
- 4E0D9C4E6CAE584304521D08 /* AppEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEntry.swift; sourceTree = "<group>"; };
- 57C4A7EB045E43F109C4DCA1 /* RadrootsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsProvider.swift; sourceTree = "<group>"; };
- 57F5216F7C18E2EE21B8528A /* RadrootsRuntimeClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRuntimeClient.swift; sourceTree = "<group>"; };
- 5B14CE9958D4C71AFB41D2DD /* RadrootsGeneratedRuntimeBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsGeneratedRuntimeBackend.swift; sourceTree = "<group>"; };
- 7098C419BAC4E8E058A2B3C2 /* RadrootsAddMediaCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAddMediaCoordinator.swift; sourceTree = "<group>"; };
- 76F84D4706216F743E373F2A /* RadrootsSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsSessionStore.swift; sourceTree = "<group>"; };
- 78F57CD1A43D46EE8CB35591 /* RadrootsTodayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsTodayView.swift; sourceTree = "<group>"; };
- 879C89400666972D90996AE5 /* RadrootsKitBindings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsKitBindings.swift; sourceTree = "<group>"; };
- 8DAAFF0BC944ECC04D0BDF41 /* RadrootsLifecycleCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsLifecycleCoordinator.swift; sourceTree = "<group>"; };
+ 81E991EAE0A0EAB4853747C6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
93AA285819DD1269C3EAD80A /* Radroots.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Radroots.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 9469790A906080D90F8735CB /* RuntimeStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeStatusView.swift; sourceTree = "<group>"; };
+ 9F54FC4930051FC4611B37D3 /* ios_app */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ios_app; path = .; sourceTree = SOURCE_ROOT; };
B8F89E4B3A775E88F661B891 /* RadrootsRootShellTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRootShellTests.swift; sourceTree = "<group>"; };
- BD7B47A576C4D5CE9318D3E6 /* RadrootsFFI.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RadrootsFFI.xcframework; path = Radroots/Frameworks/RadrootsFFI.xcframework; sourceTree = "<group>"; };
C26D512B6CBD1A9BE4780682 /* RadrootsStateMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsStateMigrationTests.swift; sourceTree = "<group>"; };
CAD74320A58874A7F7370505 /* RadrootsUITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = RadrootsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- CE0C073F20D8716C60FCCF2C /* RadrootsAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAddView.swift; sourceTree = "<group>"; };
CF484F988B3D1D3D81880388 /* RadrootsRootShellUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRootShellUITests.swift; sourceTree = "<group>"; };
- CF529B919921D63157110E44 /* RadrootsRootShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRootShell.swift; sourceTree = "<group>"; };
D0451E8A8521D320172FFA35 /* RadrootsRuntimeClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsRuntimeClientTests.swift; sourceTree = "<group>"; };
D91770F919A06DB39186281B /* RadrootsTodayStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsTodayStoreTests.swift; sourceTree = "<group>"; };
D95CB1F4A964D87D2256DA9C /* RadrootsLifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsLifecycleTests.swift; sourceTree = "<group>"; };
- DA2E3E5B1D1A0E1A32A83100 /* RadrootsAddStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAddStore.swift; sourceTree = "<group>"; };
- DF9FBA655BDA52E08FB62EED /* RadrootsConfigurationStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsConfigurationStore.swift; sourceTree = "<group>"; };
- EE3D78A3EDB345DB46C8E547 /* RadrootsAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadrootsAppDelegate.swift; sourceTree = "<group>"; };
- FF8CEF5491290B1218ACFCE7 /* RadrootsKitBindings.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RadrootsKitBindings.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
- 044C68780F358BC2C58657B8 /* Frameworks */ = {
+ 1384F9BE8BB29250A1B4A26A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- CAD7B38817DC65AAF19576F7 /* RadrootsFFI.xcframework in Frameworks */,
+ F3E40E5A76B4EA19AC7603D2 /* RadrootsApp in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 1384F9BE8BB29250A1B4A26A /* Frameworks */ = {
+ ACCF9244C9199579A4D93444 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 27F796571E92A6589E0111E3 /* RadrootsKitBindings.framework in Frameworks */,
- F3E40E5A76B4EA19AC7603D2 /* RadrootsKit in Frameworks */,
+ 0376BB3ECA35B44625702BFE /* RadrootsApp in Frameworks */,
+ D86E464EADF0C7904AB2FF90 /* RadrootsKit in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -172,66 +109,34 @@
isa = PBXGroup;
children = (
93AA285819DD1269C3EAD80A /* Radroots.app */,
- FF8CEF5491290B1218ACFCE7 /* RadrootsKitBindings.framework */,
318804462AADCA05FB04ACD9 /* RadrootsTests.xctest */,
CAD74320A58874A7F7370505 /* RadrootsUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
- 64C889EFCEB42611797110F7 /* Runtime */ = {
+ 9458C318B571871852A3FD1B /* Packages */ = {
isa = PBXGroup;
children = (
- 7098C419BAC4E8E058A2B3C2 /* RadrootsAddMediaCoordinator.swift */,
- 5B14CE9958D4C71AFB41D2DD /* RadrootsGeneratedRuntimeBackend.swift */,
- 8DAAFF0BC944ECC04D0BDF41 /* RadrootsLifecycleCoordinator.swift */,
- 57F5216F7C18E2EE21B8528A /* RadrootsRuntimeClient.swift */,
- 3DDB24124BB8917DBB49EC2C /* RadrootsRuntimeModels.swift */,
- );
- name = Runtime;
- path = Radroots/Runtime;
+ 9F54FC4930051FC4611B37D3 /* ios_app */,
+ );
+ name = Packages;
sourceTree = "<group>";
};
94F94915631E6DC54AAB0B89 /* Resources */ = {
isa = PBXGroup;
children = (
298DA81B0A000E307098C840 /* Assets.xcassets */,
+ 81E991EAE0A0EAB4853747C6 /* PrivacyInfo.xcprivacy */,
);
name = Resources;
path = Radroots/Resources;
sourceTree = "<group>";
};
- 97FA23F0FD7E25C1AF2585FB /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- BD7B47A576C4D5CE9318D3E6 /* RadrootsFFI.xcframework */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- A2DE5BE1D645F19DA46B3FC5 /* State */ = {
- isa = PBXGroup;
- children = (
- DA2E3E5B1D1A0E1A32A83100 /* RadrootsAddStore.swift */,
- DF9FBA655BDA52E08FB62EED /* RadrootsConfigurationStore.swift */,
- 2D0BC5AE5000DE34D9303379 /* RadrootsIdentityStore.swift */,
- 76F84D4706216F743E373F2A /* RadrootsSessionStore.swift */,
- 478127DF070D6065A282C44A /* RadrootsSupportingStores.swift */,
- 2A6A6D1850A21E5516060E5E /* RadrootsTodayStore.swift */,
- );
- name = State;
- path = Radroots/State;
- sourceTree = "<group>";
- };
C22A3ECCB9E9AF9E57B74576 /* App */ = {
isa = PBXGroup;
children = (
397ED29DF8E9BF73B4BBFDEC /* App.swift */,
- 4E0D9C4E6CAE584304521D08 /* AppEntry.swift */,
- EE3D78A3EDB345DB46C8E547 /* RadrootsAppDelegate.swift */,
- 343F115F383EB9C8A796AC9C /* RadrootsAppModel.swift */,
- 57C4A7EB045E43F109C4DCA1 /* RadrootsProvider.swift */,
- CF529B919921D63157110E44 /* RadrootsRootShell.swift */,
);
name = App;
path = Radroots/App;
@@ -242,39 +147,14 @@
children = (
C22A3ECCB9E9AF9E57B74576 /* App */,
401A3C62BEECB8BD5C500756 /* Config */,
- D17ED36BEBE689794F31C2BB /* Generated */,
+ 9458C318B571871852A3FD1B /* Packages */,
31C88176C5674CFF5F9CFBEA /* RadrootsTests */,
FD341F0384225E202A0845B1 /* RadrootsUITests */,
94F94915631E6DC54AAB0B89 /* Resources */,
- 64C889EFCEB42611797110F7 /* Runtime */,
- A2DE5BE1D645F19DA46B3FC5 /* State */,
- E05061D0ADB560FA929B4D9A /* Views */,
- 97FA23F0FD7E25C1AF2585FB /* Frameworks */,
6240123423927396E47D6B3E /* Products */,
);
sourceTree = "<group>";
};
- D17ED36BEBE689794F31C2BB /* Generated */ = {
- isa = PBXGroup;
- children = (
- 879C89400666972D90996AE5 /* RadrootsKitBindings.swift */,
- );
- name = Generated;
- path = Radroots/Generated;
- sourceTree = "<group>";
- };
- E05061D0ADB560FA929B4D9A /* Views */ = {
- isa = PBXGroup;
- children = (
- CE0C073F20D8716C60FCCF2C /* RadrootsAddView.swift */,
- 29DD502141AA86FD5C948618 /* RadrootsSupportingViews.swift */,
- 78F57CD1A43D46EE8CB35591 /* RadrootsTodayView.swift */,
- 9469790A906080D90F8735CB /* RuntimeStatusView.swift */,
- );
- name = Views;
- path = Radroots/Views;
- sourceTree = "<group>";
- };
FD341F0384225E202A0845B1 /* RadrootsUITests */ = {
isa = PBXGroup;
children = (
@@ -283,52 +163,25 @@
path = RadrootsUITests;
sourceTree = "<group>";
};
- "TEMP_C9716F76-7D47-4886-AA36-A6BB8236F43C" /* Localizations */ = {
- isa = PBXGroup;
- children = (
- );
- path = Localizations;
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- 1C22115E511334B291A71594 /* RadrootsKitBindings */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 4709AFBD0CA5DE7FC73BFC95 /* Build configuration list for PBXNativeTarget "RadrootsKitBindings" */;
- buildPhases = (
- 21C962D4AD2665D5ED66E70F /* Sources */,
- 044C68780F358BC2C58657B8 /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = RadrootsKitBindings;
- packageProductDependencies = (
- );
- productName = RadrootsKitBindings;
- productReference = FF8CEF5491290B1218ACFCE7 /* RadrootsKitBindings.framework */;
- productType = "com.apple.product-type.framework";
- };
469EC50C49E7266DF1C2000B /* Radroots */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2513910CE2A2ED545A78A163 /* Build configuration list for PBXNativeTarget "Radroots" */;
buildPhases = (
- 1687531B35A5B613B89DA261 /* Generate git SHA xcconfig */,
+ 7C10FB7358EE7DB857A84E7B /* Verify installed FFI artifacts */,
78F7810CC77628CB591F8CD2 /* Sources */,
0FB0BFB846269AC353E4AD0E /* Resources */,
1384F9BE8BB29250A1B4A26A /* Frameworks */,
- 271D40E26A903BC9F058633E /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
- 3AF61EED138E0994701CAA79 /* PBXTargetDependency */,
);
name = Radroots;
packageProductDependencies = (
- 2DAD90EBF8EB00ACDD7611CD /* RadrootsKit */,
+ 5EB99D569A31C7F8987A9440 /* RadrootsApp */,
);
productName = Radroots;
productReference = 93AA285819DD1269C3EAD80A /* Radroots.app */;
@@ -339,6 +192,7 @@
buildConfigurationList = DCDE79513C7AE684F9540473 /* Build configuration list for PBXNativeTarget "RadrootsTests" */;
buildPhases = (
4948BBB44D48B961DE81F508 /* Sources */,
+ ACCF9244C9199579A4D93444 /* Frameworks */,
);
buildRules = (
);
@@ -347,6 +201,8 @@
);
name = RadrootsTests;
packageProductDependencies = (
+ E17BA8C6979DF56FB5F385B8 /* RadrootsApp */,
+ 54C7F50B545852A8B313DAA7 /* RadrootsKit */,
);
productName = RadrootsTests;
productReference = 318804462AADCA05FB04ACD9 /* RadrootsTests.xctest */;
@@ -395,13 +251,13 @@
minimizedProjectReferenceProxies = 1;
packageReferences = (
5696E24009739E3BD13D6580 /* XCRemoteSwiftPackageReference "apple_kit" */,
+ 03D9E5A7B556A6CD41FCF80D /* XCLocalSwiftPackageReference "." */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 6240123423927396E47D6B3E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
- 1C22115E511334B291A71594 /* RadrootsKitBindings */,
469EC50C49E7266DF1C2000B /* Radroots */,
67B2EF8D69F6CEA9BE5A8B04 /* RadrootsTests */,
D87D8771FD63904A45FAFB4D /* RadrootsUITests */,
@@ -415,13 +271,14 @@
buildActionMask = 2147483647;
files = (
C356F2A068722087ED91256C /* Assets.xcassets in Resources */,
+ 60B853393C8DF4FDF2C01CAF /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 1687531B35A5B613B89DA261 /* Generate git SHA xcconfig */ = {
+ 7C10FB7358EE7DB857A84E7B /* Verify installed FFI artifacts */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
@@ -431,14 +288,14 @@
);
inputPaths = (
);
- name = "Generate git SHA xcconfig";
+ name = "Verify installed FFI artifacts";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "GIT_SHA=$(git rev-parse --short HEAD || echo \"unknown\")\necho \"GIT_SHA = $GIT_SHA\" > \"$SRCROOT/Radroots/radroots.git.xcconfig\"\n";
+ shellScript = "\"$SRCROOT/RadrootsFFI/scripts/verify-installed-artifacts.sh\"\n";
};
/* End PBXShellScriptBuildPhase section */
@@ -451,14 +308,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 21C962D4AD2665D5ED66E70F /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- AA7D80A73CD6C22ED5080781 /* RadrootsKitBindings.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
4948BBB44D48B961DE81F508 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -478,37 +327,12 @@
buildActionMask = 2147483647;
files = (
E236CCF8D8F8AC12AF59932E /* App.swift in Sources */,
- ED326EC0067A550727A1680D /* AppEntry.swift in Sources */,
- F9EA6E6935307271FF920B7D /* RadrootsAddMediaCoordinator.swift in Sources */,
- 0486BFE6223D0FF0ACFA4249 /* RadrootsAddStore.swift in Sources */,
- BB932CEEA2713588E14AC3ED /* RadrootsAddView.swift in Sources */,
- 3233513A881D056514142457 /* RadrootsAppDelegate.swift in Sources */,
- 74082509C257766A166662FA /* RadrootsAppModel.swift in Sources */,
- D03C81CCF4FBC6D7D5634D35 /* RadrootsConfigurationStore.swift in Sources */,
- 5DAE76BBC71E4A192E029785 /* RadrootsGeneratedRuntimeBackend.swift in Sources */,
- F6F36A06BD77BCFA64FC3541 /* RadrootsIdentityStore.swift in Sources */,
- 7A1131CC1E9308706ECE4B7B /* RadrootsLifecycleCoordinator.swift in Sources */,
- 47D9564F81A5E7CEA86B759C /* RadrootsProvider.swift in Sources */,
- 509FF909EFFD7FD9BAEC537C /* RadrootsRootShell.swift in Sources */,
- F7EEF54776B037D98F389AD6 /* RadrootsRuntimeClient.swift in Sources */,
- B356719A54375706DBBDC118 /* RadrootsRuntimeModels.swift in Sources */,
- 41B5CB28ACA51221A1BA59D5 /* RadrootsSessionStore.swift in Sources */,
- 3C16EC0B109F76EEE8D3031A /* RadrootsSupportingStores.swift in Sources */,
- 75275CDCE16FB99248793AB4 /* RadrootsSupportingViews.swift in Sources */,
- 499BCC8FC845FDD77E74FD99 /* RadrootsTodayStore.swift in Sources */,
- 86DF51D41F92E1A695D83205 /* RadrootsTodayView.swift in Sources */,
- CA827A410369AC55B0FEE305 /* RuntimeStatusView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 3AF61EED138E0994701CAA79 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 1C22115E511334B291A71594 /* RadrootsKitBindings */;
- targetProxy = 51F4BD021D143679140FF35F /* PBXContainerItemProxy */;
- };
54F8C314CE8A0D06346F56DE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 469EC50C49E7266DF1C2000B /* Radroots */;
@@ -522,37 +346,6 @@
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
- 065194E2B92BBDACF3D27647 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_IDENTITY = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "\"Radroots/Frameworks\"",
- );
- GENERATE_INFOPLIST_FILE = YES;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 18.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = org.radroots.RadrootsKitBindings;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_STRICT_CONCURRENCY = minimal;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Release;
- };
5486087B252C6EA76ADD9BB8 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 30A8A8321A8A261F6D1B480D /* Debug.xcconfig */;
@@ -572,37 +365,6 @@
};
name = Debug;
};
- 762521A89ECC390CEE5533D2 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_IDENTITY = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "\"Radroots/Frameworks\"",
- );
- GENERATE_INFOPLIST_FILE = YES;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 18.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = org.radroots.RadrootsKitBindings;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_STRICT_CONCURRENCY = minimal;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Debug;
- };
8113D02CF1312FB10249F707 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -829,15 +591,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
- 4709AFBD0CA5DE7FC73BFC95 /* Build configuration list for PBXNativeTarget "RadrootsKitBindings" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 762521A89ECC390CEE5533D2 /* Debug */,
- 065194E2B92BBDACF3D27647 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
B3DDD079CA522503021BDB85 /* Build configuration list for PBXNativeTarget "RadrootsUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -867,23 +620,38 @@
};
/* End XCConfigurationList section */
+/* Begin XCLocalSwiftPackageReference section */
+ 03D9E5A7B556A6CD41FCF80D /* XCLocalSwiftPackageReference "." */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = .;
+ };
+/* End XCLocalSwiftPackageReference section */
+
/* Begin XCRemoteSwiftPackageReference section */
5696E24009739E3BD13D6580 /* XCRemoteSwiftPackageReference "apple_kit" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/radrootslabs/apple_kit.git";
requirement = {
kind = revision;
- revision = 265015fc537bfe507f12d801b9765be9764fbc95;
+ revision = af6047761cd445e8861e11b7df15b1fc52c1fbbf;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
- 2DAD90EBF8EB00ACDD7611CD /* RadrootsKit */ = {
+ 54C7F50B545852A8B313DAA7 /* RadrootsKit */ = {
isa = XCSwiftPackageProductDependency;
package = 5696E24009739E3BD13D6580 /* XCRemoteSwiftPackageReference "apple_kit" */;
productName = RadrootsKit;
};
+ 5EB99D569A31C7F8987A9440 /* RadrootsApp */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = RadrootsApp;
+ };
+ E17BA8C6979DF56FB5F385B8 /* RadrootsApp */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = RadrootsApp;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 572C41532B5066EC7641561C /* Project object */;
diff --git a/Radroots.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Radroots.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,12 +1,12 @@
{
- "originHash" : "7d8372bdb86640cb80ede08ccb1cc767f2f406a11d037ca50a3b404cd7bd96f2",
+ "originHash" : "eee4aa714e42372e2c603bbeff5ceec11e88161ceda9eac253b2c2683f9873dc",
"pins" : [
{
"identity" : "apple_kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/radrootslabs/apple_kit.git",
"state" : {
- "revision" : "265015fc537bfe507f12d801b9765be9764fbc95"
+ "revision" : "af6047761cd445e8861e11b7df15b1fc52c1fbbf"
}
},
{
diff --git a/Radroots/App/App.swift b/Radroots/App/App.swift
@@ -1,3 +1,4 @@
+import RadrootsApp
import SwiftUI
@main
@@ -6,9 +7,7 @@ struct RadrootsApp: App {
var body: some Scene {
WindowGroup {
- RadrootsProvider {
- AppEntry()
- }
+ RadrootsAppView()
}
}
}
diff --git a/Radroots/App/AppEntry.swift b/Radroots/App/AppEntry.swift
@@ -1,5 +1,19 @@
import SwiftUI
+public enum RadrootsAppRelease: Sendable {
+ public static let version = "0.1.0-alpha"
+}
+
+public struct RadrootsAppView: View {
+ public init() {}
+
+ public var body: some View {
+ RadrootsProvider {
+ AppEntry()
+ }
+ }
+}
+
struct AppEntry: View {
@EnvironmentObject private var appModel: RadrootsAppModel
diff --git a/Radroots/App/RadrootsAppDelegate.swift b/Radroots/App/RadrootsAppDelegate.swift
@@ -1,7 +1,11 @@
import UIKit
-final class RadrootsAppDelegate: NSObject, UIApplicationDelegate {
- func application(
+public final class RadrootsAppDelegate: NSObject, UIApplicationDelegate {
+ override public init() {
+ super.init()
+ }
+
+ public func application(
_: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void
@@ -15,7 +19,7 @@ final class RadrootsAppDelegate: NSObject, UIApplicationDelegate {
}
}
- func applicationWillTerminate(_: UIApplication) {
+ public func applicationWillTerminate(_: UIApplication) {
Task {
await RadrootsLifecycleBridge.shared.requestShutdown()
}
diff --git a/Radroots/Info.plist b/Radroots/Info.plist
@@ -26,9 +26,6 @@
<string>Radroots accesses only the photos you choose for a farm update, ask, event, or food post.</string>
<key>NSFaceIDUsageDescription</key>
<string>Radroots uses Face ID only to unlock the local Nostr identity or approve a post or media upload you choose to sign.</string>
- <key>GIT_SHA</key>
- <string>$(GIT_SHA)</string>
-
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
diff --git a/Radroots/Resources/PrivacyInfo.xcprivacy b/Radroots/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,23 @@
+<?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>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>CA92.1</string>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/Radroots/radroots.xcconfig b/Radroots/radroots.xcconfig
@@ -1,3 +1 @@
PRODUCT_BUNDLE_IDENTIFIER = org.radroots.field-ios
-
-#include? "radroots.git.xcconfig"
diff --git a/RadrootsFFI/Makefile b/RadrootsFFI/Makefile
@@ -90,9 +90,6 @@ print-config:
clean:
rm -rf $(TARGET_DIR) $(OUT_DIR) $(ARTIFACTS_DIR)/$(FFI_OUTPUT_NAME).xcframework
- if [ -d $(GENERATED_SWIFT_DIR) ]; then \
- find $(GENERATED_SWIFT_DIR) -maxdepth 1 -type f -name '*.swift' -delete; \
- fi
distclean: clean
rm -rf $(SOURCE_ROOT)
diff --git a/RadrootsFFI/scripts/verify-installed-artifacts.sh b/RadrootsFFI/scripts/verify-installed-artifacts.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+set -eu
+
+script_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
+ios_root=$(CDPATH='' cd -- "$script_dir/../.." && pwd)
+lock_file="$ios_root/RadrootsFFI/source.lock"
+
+lock_value() {
+ key=$1
+ awk -v key="$key" '$2 == key && $3 == ":=" { print $4 }' "$lock_file"
+}
+
+require_sha256() {
+ path=$1
+ expected=$2
+ label=$3
+ if [ ! -f "$path" ]; then
+ echo "error: missing $label; run 'make bootstrap' from $ios_root" >&2
+ exit 1
+ fi
+ actual=$(shasum -a 256 "$path" | awk '{print $1}')
+ if [ "$actual" != "$expected" ]; then
+ echo "error: stale $label; run 'make bootstrap' from $ios_root" >&2
+ exit 1
+ fi
+}
+
+framework="$ios_root/Radroots/Frameworks/RadrootsFFI.xcframework"
+if [ ! -d "$framework" ]; then
+ echo "error: missing RadrootsFFI.xcframework; run 'make bootstrap' from $ios_root" >&2
+ exit 1
+fi
+
+require_sha256 \
+ "$framework/ios-arm64/libradroots_mobile_ffi.a" \
+ "$(lock_value RADROOTS_FIELD_FFI_DEVICE_SHA256)" \
+ "device FFI library"
+require_sha256 \
+ "$framework/ios-arm64-simulator/libradroots_mobile_ffi.a" \
+ "$(lock_value RADROOTS_FIELD_FFI_SIMULATOR_SHA256)" \
+ "simulator FFI library"
+require_sha256 \
+ "$ios_root/Radroots/Generated/RadrootsKitBindings.swift" \
+ "$(lock_value RADROOTS_FIELD_FFI_SWIFT_SHA256)" \
+ "generated Swift bindings"
+require_sha256 \
+ "$framework/ios-arm64-simulator/Headers/RadrootsFFI.h" \
+ "$(lock_value RADROOTS_FIELD_FFI_HEADER_SHA256)" \
+ "FFI header"
+require_sha256 \
+ "$framework/ios-arm64-simulator/Headers/module.modulemap" \
+ "$(lock_value RADROOTS_FIELD_FFI_MODULEMAP_SHA256)" \
+ "FFI module map"
+require_sha256 \
+ "$ios_root/RadrootsFFI/api/RadrootsKitBindings.symbols.json" \
+ "$(lock_value RADROOTS_FIELD_FFI_API_SHA256)" \
+ "generated bindings API snapshot"
+
+framework_sha256=$(
+ cd "$ios_root/Radroots/Frameworks"
+ find RadrootsFFI.xcframework -type f -print | LC_ALL=C sort | while IFS= read -r file; do
+ shasum -a 256 "$file"
+ done | shasum -a 256 | awk '{print $1}'
+)
+if [ "$framework_sha256" != "$(lock_value RADROOTS_FIELD_FFI_XCFRAMEWORK_SHA256)" ]; then
+ echo "error: stale XCFramework aggregate; run 'make bootstrap' from $ios_root" >&2
+ exit 1
+fi
+
+expected_revision=$(lock_value RADROOTS_FIELD_LIB_GIT_REV)
+expected_version=$(lock_value RADROOTS_FIELD_FFI_CRATE_VERSION)
+if ! grep -Fq "\"revision\": \"$expected_revision\"" "$ios_root/RadrootsFFI/provenance.json"; then
+ echo "error: stale FFI provenance revision; run 'make bootstrap' from $ios_root" >&2
+ exit 1
+fi
+if ! grep -Fq "version = \"$expected_version\"" "$ios_root/radroots.lib.source-lock.v1.toml"; then
+ echo "error: source-lock version differs from FFI source.lock" >&2
+ exit 1
+fi
+
+echo "installed FFI artifacts match source.lock"
diff --git a/RadrootsPublicAPITests/RadrootsAppPublicAPITests.swift b/RadrootsPublicAPITests/RadrootsAppPublicAPITests.swift
@@ -0,0 +1,15 @@
+import RadrootsApp
+import SwiftUI
+import UIKit
+import XCTest
+
+final class RadrootsAppPublicAPITests: XCTestCase {
+ @MainActor
+ func testSupportedPublicSurfaceCompilesForAnExternalConsumer() {
+ XCTAssertEqual(RadrootsAppRelease.version, "0.1.0-alpha")
+ let appView: any View = RadrootsAppView()
+ let appDelegate: any UIApplicationDelegate = RadrootsAppDelegate()
+ _ = appView
+ _ = appDelegate
+ }
+}
diff --git a/RadrootsTests/RadrootsAddStoreTests.swift b/RadrootsTests/RadrootsAddStoreTests.swift
@@ -1,4 +1,4 @@
-@testable import Radroots
+@testable import RadrootsApp
import XCTest
final class RadrootsAddStoreTests: XCTestCase {
diff --git a/RadrootsTests/RadrootsLifecycleTests.swift b/RadrootsTests/RadrootsLifecycleTests.swift
@@ -1,5 +1,5 @@
import Foundation
-@testable import Radroots
+@testable import RadrootsApp
import RadrootsKit
import XCTest
diff --git a/RadrootsTests/RadrootsRootShellTests.swift b/RadrootsTests/RadrootsRootShellTests.swift
@@ -1,4 +1,4 @@
-@testable import Radroots
+@testable import RadrootsApp
import XCTest
final class RadrootsRootShellTests: XCTestCase {
diff --git a/RadrootsTests/RadrootsRuntimeClientTests.swift b/RadrootsTests/RadrootsRuntimeClientTests.swift
@@ -1,4 +1,4 @@
-@testable import Radroots
+@testable import RadrootsApp
import XCTest
final class RadrootsRuntimeClientTests: XCTestCase {
diff --git a/RadrootsTests/RadrootsStateMigrationTests.swift b/RadrootsTests/RadrootsStateMigrationTests.swift
@@ -1,5 +1,5 @@
import Foundation
-@testable import Radroots
+@testable import RadrootsApp
import RadrootsKit
import XCTest
diff --git a/RadrootsTests/RadrootsSupportingStoreTests.swift b/RadrootsTests/RadrootsSupportingStoreTests.swift
@@ -1,4 +1,4 @@
-@testable import Radroots
+@testable import RadrootsApp
import XCTest
final class RadrootsSupportingStoreTests: XCTestCase {
diff --git a/RadrootsTests/RadrootsTodayStoreTests.swift b/RadrootsTests/RadrootsTodayStoreTests.swift
@@ -1,4 +1,4 @@
-@testable import Radroots
+@testable import RadrootsApp
import XCTest
final class RadrootsTodayStoreTests: XCTestCase {
@@ -182,7 +182,7 @@ final class RadrootsTodayStoreTests: XCTestCase {
@MainActor
private func startedClient(backend: TodayBackend) async throws -> RadrootsRuntimeClient {
let client = RadrootsRuntimeClient { _ in
- RadrootsRuntimeBackendStart(backend: backend, snapshot: await backend.snapshot())
+ await RadrootsRuntimeBackendStart(backend: backend, snapshot: backend.snapshot())
}
_ = try await client.start(configuration: makeConfiguration())
return client
diff --git a/api/RadrootsApp.symbols.json b/api/RadrootsApp.symbols.json
@@ -0,0 +1 @@
+{"module":{"name":"RadrootsApp","platform":{"architecture":"arm64","environment":"simulator","operatingSystem":{"minimumVersion":{"major":18,"minor":0},"name":"ios"},"vendor":"apple"}},"relationships":[{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"c:objc(pl)NSObject"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"c:objc(pl)UIApplicationDelegate"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:SH"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:SQ"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:s16SendableMetatypeP"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:s23CustomStringConvertibleP"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:s28CustomDebugStringConvertibleP"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:s7CVarArgP"},{"kind":"conformsTo","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"s:s8SendableP"},{"kind":"conformsTo","source":"s:11RadrootsApp0aB4ViewV","target":"s:7SwiftUI4ViewP"},{"kind":"conformsTo","source":"s:11RadrootsApp0aB4ViewV","target":"s:s16SendableMetatypeP"},{"kind":"conformsTo","source":"s:11RadrootsApp0aB4ViewV","target":"s:s8SendableP"},{"kind":"conformsTo","source":"s:11RadrootsApp0aB7ReleaseO","target":"s:s16SendableMetatypeP"},{"kind":"conformsTo","source":"s:11RadrootsApp0aB7ReleaseO","target":"s:s8SendableP"},{"kind":"inheritsFrom","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate","target":"c:objc(cs)NSObject"},{"kind":"memberOf","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)application:handleEventsForBackgroundURLSession:completionHandler:","target":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate"},{"kind":"memberOf","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)applicationWillTerminate:","target":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate"},{"kind":"memberOf","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)init","target":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate"},{"kind":"memberOf","source":"s:11RadrootsApp0aB4ViewV4bodyQrvp","target":"s:11RadrootsApp0aB4ViewV"},{"kind":"memberOf","source":"s:11RadrootsApp0aB4ViewVACycfc","target":"s:11RadrootsApp0aB4ViewV"},{"kind":"memberOf","source":"s:11RadrootsApp0aB7ReleaseO7versionSSvpZ","target":"s:11RadrootsApp0aB7ReleaseO"},{"kind":"overrides","source":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)init","target":"c:objc(cs)NSObject(im)init"}],"schema":"radroots.swift-api-snapshot.v1","symbols":[{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"final"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"RadrootsAppDelegate"}],"kind":"swift.class","path":["RadrootsAppDelegate"],"precise":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"application"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","preciseIdentifier":"c:objc(cs)UIApplication","spelling":"UIApplication"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"handleEventsForBackgroundURLSession"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"identifier"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","preciseIdentifier":"s:SS","spelling":"String"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"completionHandler"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@escaping "},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","preciseIdentifier":"s:s4Voida","spelling":"Void"},{"kind":"text","spelling":")"}],"kind":"swift.method","path":["RadrootsAppDelegate","application(_:handleEventsForBackgroundURLSession:completionHandler:)"],"precise":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)application:handleEventsForBackgroundURLSession:completionHandler:"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"applicationWillTerminate"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","preciseIdentifier":"c:objc(cs)UIApplication","spelling":"UIApplication"},{"kind":"text","spelling":")"}],"kind":"swift.method","path":["RadrootsAppDelegate","applicationWillTerminate(_:)"],"precise":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)applicationWillTerminate:"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"override"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"kind":"swift.init","path":["RadrootsAppDelegate","init()"],"precise":"c:@M@RadrootsApp@objc(cs)RadrootsAppDelegate(im)init"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"RadrootsAppView"}],"kind":"swift.struct","path":["RadrootsAppView"],"precise":"s:11RadrootsApp0aB4ViewV"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"body"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"some"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","preciseIdentifier":"s:7SwiftUI4ViewP","spelling":"View"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"kind":"swift.property","path":["RadrootsAppView","body"],"precise":"s:11RadrootsApp0aB4ViewV4bodyQrvp"},{"access":"public","declaration":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","preciseIdentifier":"s:ScM","spelling":"MainActor"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"kind":"swift.init","path":["RadrootsAppView","init()"],"precise":"s:11RadrootsApp0aB4ViewVACycfc"},{"access":"public","declaration":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"RadrootsAppRelease"}],"kind":"swift.enum","path":["RadrootsAppRelease"],"precise":"s:11RadrootsApp0aB7ReleaseO"},{"access":"public","declaration":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"version"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","preciseIdentifier":"s:SS","spelling":"String"}],"kind":"swift.type.property","path":["RadrootsAppRelease","version"],"precise":"s:11RadrootsApp0aB7ReleaseO7versionSSvpZ"}]}
diff --git a/project.yml b/project.yml
@@ -9,54 +9,21 @@ configs:
Release: release
packages:
+ RadrootsApp:
+ path: .
RadrootsKit:
url: https://github.com/radrootslabs/apple_kit.git
- revision: 265015fc537bfe507f12d801b9765be9764fbc95
+ revision: af6047761cd445e8861e11b7df15b1fc52c1fbbf
targets:
- RadrootsKitBindings:
- type: framework
- platform: iOS
- deploymentTarget: "18.0"
- sources:
- - path: Radroots/Generated/RadrootsKitBindings.swift
- settings:
- base:
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]": x86_64
- GENERATE_INFOPLIST_FILE: true
- PRODUCT_BUNDLE_IDENTIFIER: org.radroots.RadrootsKitBindings
- SWIFT_VERSION: 5.0
- SWIFT_STRICT_CONCURRENCY: minimal
- dependencies:
- - framework: Radroots/Frameworks/RadrootsFFI.xcframework
- embed: false
Radroots:
type: application
platform: iOS
deploymentTarget: "18.0"
sources:
- path: Radroots/App/App.swift
- - path: Radroots/App/RadrootsAppDelegate.swift
- - path: Radroots/App/AppEntry.swift
- - path: Radroots/App/RadrootsAppModel.swift
- - path: Radroots/App/RadrootsProvider.swift
- - path: Radroots/App/RadrootsRootShell.swift
- - path: Radroots/Runtime/RadrootsGeneratedRuntimeBackend.swift
- - path: Radroots/Runtime/RadrootsAddMediaCoordinator.swift
- - path: Radroots/Runtime/RadrootsLifecycleCoordinator.swift
- - path: Radroots/Runtime/RadrootsRuntimeClient.swift
- - path: Radroots/Runtime/RadrootsRuntimeModels.swift
- - path: Radroots/State/RadrootsConfigurationStore.swift
- - path: Radroots/State/RadrootsAddStore.swift
- - path: Radroots/State/RadrootsIdentityStore.swift
- - path: Radroots/State/RadrootsSessionStore.swift
- - path: Radroots/State/RadrootsSupportingStores.swift
- - path: Radroots/State/RadrootsTodayStore.swift
- - path: Radroots/Views/RadrootsTodayView.swift
- - path: Radroots/Views/RadrootsAddView.swift
- - path: Radroots/Views/RadrootsSupportingViews.swift
- - path: Radroots/Views/RuntimeStatusView.swift
- - path: Radroots/Resources
+ - path: Radroots/Resources/Assets.xcassets
+ - path: Radroots/Resources/PrivacyInfo.xcprivacy
settings:
base:
"EXCLUDED_ARCHS[sdk=iphonesimulator*]": x86_64
@@ -66,15 +33,12 @@ targets:
Debug: Radroots/Config/Debug.xcconfig
Release: Radroots/Config/Release.xcconfig
dependencies:
- - target: RadrootsKitBindings
- embed: true
- - package: RadrootsKit
+ - package: RadrootsApp
preBuildScripts:
- - name: Generate git SHA xcconfig
+ - name: Verify installed FFI artifacts
basedOnDependencyAnalysis: false
script: |
- GIT_SHA=$(git rev-parse --short HEAD || echo "unknown")
- echo "GIT_SHA = $GIT_SHA" > "$SRCROOT/Radroots/radroots.git.xcconfig"
+ "$SRCROOT/RadrootsFFI/scripts/verify-installed-artifacts.sh"
RadrootsTests:
type: bundle.unit-test
platform: iOS
@@ -94,6 +58,8 @@ targets:
GENERATE_INFOPLIST_FILE: true
dependencies:
- target: Radroots
+ - package: RadrootsApp
+ - package: RadrootsKit
RadrootsUITests:
type: bundle.ui-testing
platform: iOS
diff --git a/scripts/app-api-snapshot.sh b/scripts/app-api-snapshot.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+set -euo pipefail
+
+operation=${1:-}
+case "$operation" in
+ write|check) ;;
+ *) echo "usage: $0 {write|check}" >&2; exit 64 ;;
+esac
+
+for variable in XCODE_DERIVED_DATA XCODE_SOURCE_PACKAGES; do
+ if [[ -z "${!variable:-}" ]]; then
+ echo "error: $variable is required; run this command through cargo extbuild" >&2
+ exit 1
+ fi
+done
+
+repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
+work_dir="$XCODE_DERIVED_DATA/radroots-app-api"
+symbol_dir="$work_dir/symbols"
+rendered="$work_dir/RadrootsApp.symbols.json"
+snapshot="$repo_root/api/RadrootsApp.symbols.json"
+products="$XCODE_DERIVED_DATA/Build/Products/Debug-iphonesimulator"
+generated_module_maps="$XCODE_DERIVED_DATA/Build/Intermediates.noindex/GeneratedModuleMaps-iphonesimulator"
+secp_headers="$XCODE_SOURCE_PACKAGES/checkouts/swift-secp256k1/Sources/libsecp256k1/include"
+ffi_headers="$repo_root/Radroots/Frameworks/RadrootsFFI.xcframework/ios-arm64-simulator/Headers"
+sdk=$(xcrun --sdk iphonesimulator --show-sdk-path)
+
+rm -rf "$work_dir"
+mkdir -p "$symbol_dir"
+xcrun swift-symbolgraph-extract \
+ -module-name RadrootsApp \
+ -target arm64-apple-ios18.0-simulator \
+ -sdk "$sdk" \
+ -I "$products" \
+ -I "$ffi_headers" \
+ -F "$products" \
+ -Xcc "-fmodule-map-file=$generated_module_maps/libsecp256k1.modulemap" \
+ -Xcc "-I$secp_headers" \
+ -minimum-access-level public \
+ -skip-inherited-docs \
+ -skip-synthesized-members \
+ -output-dir "$symbol_dir"
+
+jq -cS \
+ '{schema:"radroots.swift-api-snapshot.v1",module:.module,symbols:(.symbols | map({kind:.kind.identifier,precise:.identifier.precise,path:.pathComponents,access:.accessLevel,declaration:.declarationFragments}) | sort_by(.precise)),relationships:(.relationships | map({kind,source,target}) | sort_by(.kind,.source,.target))}' \
+ "$symbol_dir/RadrootsApp.symbols.json" > "$rendered"
+
+if [[ "$operation" == write ]]; then
+ mkdir -p "$(dirname -- "$snapshot")"
+ cp "$rendered" "$snapshot"
+else
+ if [[ ! -f "$snapshot" ]]; then
+ echo "error: missing public API snapshot; run 'make api-snapshot-write'" >&2
+ exit 1
+ fi
+ cmp "$rendered" "$snapshot"
+fi
+
+echo "RadrootsApp public API snapshot $operation succeeded"
diff --git a/scripts/generate-project.sh b/scripts/generate-project.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+set -eu
+
+project_file=Radroots.xcodeproj/project.pbxproj
+localizations_id=A11CE10CA11A710A00000001
+
+xcodegen generate --spec project.yml
+
+temporary_count=$(grep -Ec '"TEMP_[0-9A-F-]+" /\* Localizations \*/' "$project_file" || true)
+case "$temporary_count" in
+ 0) ;;
+ 1)
+ perl -0pi -e \
+ 's/"TEMP_[0-9A-F-]+"( \/\* Localizations \*\/)/A11CE10CA11A710A00000001$1/g' \
+ "$project_file"
+ ;;
+ *)
+ echo "error: unexpected XcodeGen Localizations group inventory" >&2
+ exit 1
+ ;;
+esac
+
+if grep -Eq '"TEMP_[0-9A-F-]+" /\* Localizations \*/' "$project_file"; then
+ echo "error: XcodeGen temporary Localizations identifier remains" >&2
+ exit 1
+fi
+deterministic_count=$(grep -Ec "$localizations_id /\* Localizations \*/" "$project_file" || true)
+if [ "$deterministic_count" -gt 1 ]; then
+ echo "error: deterministic Localizations identifier is duplicated" >&2
+ exit 1
+fi
diff --git a/scripts/swift-package.sh b/scripts/swift-package.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+set -eu
+
+for variable in SWIFTPM_SCRATCH SWIFTPM_CACHE; do
+ case "$variable" in
+ SWIFTPM_SCRATCH) value=${SWIFTPM_SCRATCH:-} ;;
+ SWIFTPM_CACHE) value=${SWIFTPM_CACHE:-} ;;
+ esac
+ if [ -z "$value" ]; then
+ echo "error: $variable is required; run this command through cargo extbuild" >&2
+ exit 1
+ fi
+done
+
+operation=${1:-}
+case "$operation" in
+ resolve)
+ exec swift package \
+ --scratch-path "$SWIFTPM_SCRATCH" \
+ --cache-path "$SWIFTPM_CACHE" \
+ --disable-sandbox \
+ resolve
+ ;;
+ *)
+ echo "usage: $0 resolve" >&2
+ exit 64
+ ;;
+esac
diff --git a/scripts/verify-package-contract.sh b/scripts/verify-package-contract.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+set -eu
+
+repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
+package="$repo_root/Package.swift"
+source_lock="$repo_root/RadrootsFFI/source.lock"
+consumer_lock="$repo_root/radroots.lib.source-lock.v1.toml"
+
+make_value() {
+ key=$1
+ awk -v key="$key" '$2 == key && $3 == ":=" { print $4 }' "$source_lock"
+}
+
+release_version=$(make_value RADROOTS_FIELD_FFI_CRATE_VERSION)
+lib_revision=$(make_value RADROOTS_FIELD_LIB_GIT_REV)
+apple_revision=$(sed -n '/url: "https:\/\/github.com\/radrootslabs\/apple_kit.git"/{n;s/.*revision: "\([0-9a-f]*\)".*/\1/p;}' "$package")
+
+if ! printf '%s\n' "$apple_revision" | grep -Eq '^[0-9a-f]{40}$'; then
+ echo "error: apple_kit must use an exact 40-character Git revision" >&2
+ exit 1
+fi
+
+grep -Fq "repository = \"https://github.com/radrootslabs/lib\"" "$consumer_lock"
+grep -Fq "revision = \"$lib_revision\"" "$consumer_lock"
+grep -Fq "version = \"$release_version\"" "$consumer_lock"
+grep -Fq "public static let version = \"$release_version\"" "$repo_root/Radroots/App/AppEntry.swift"
+grep -Fq "revision: $apple_revision" "$repo_root/project.yml"
+grep -Fq "XCTAssertEqual(RadrootsAppRelease.version, \"$release_version\")" \
+ "$repo_root/RadrootsPublicAPITests/RadrootsAppPublicAPITests.swift"
+grep -Fq "NSPrivacyAccessedAPICategoryUserDefaults" \
+ "$repo_root/Radroots/Resources/PrivacyInfo.xcprivacy"
+grep -Fq "CA92.1" "$repo_root/Radroots/Resources/PrivacyInfo.xcprivacy"
+plutil -lint "$repo_root/Radroots/Resources/PrivacyInfo.xcprivacy" >/dev/null
+
+for resolved in \
+ "$repo_root/Package.resolved" \
+ "$repo_root/Radroots.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved"
+do
+ if [ ! -f "$resolved" ]; then
+ echo "error: missing Swift package lock: $resolved" >&2
+ exit 1
+ fi
+ jq -e --arg apple_revision "$apple_revision" '
+ (.version == 3) and
+ (.pins | length == 2) and
+ (all(.pins[];
+ (.kind == "remoteSourceControl") and
+ (.location | startswith("https://")) and
+ (.state.revision | test("^[0-9a-f]{40}$")))) and
+ (any(.pins[];
+ .location == "https://github.com/radrootslabs/apple_kit.git" and
+ .state.revision == $apple_revision)) and
+ (any(.pins[];
+ .location == "https://github.com/21-DOT-DEV/swift-secp256k1.git" and
+ .state.revision == "e70a10e036a55fffea31568f0af92d69b6d449cd"))
+ ' "$resolved" >/dev/null
+done
+
+package_pins=$(jq -cS '.pins | sort_by(.identity)' "$repo_root/Package.resolved")
+project_pins=$(jq -cS '.pins | sort_by(.identity)' \
+ "$repo_root/Radroots.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved")
+if [ "$package_pins" != "$project_pins" ]; then
+ echo "error: Swift package and Xcode project locks disagree" >&2
+ exit 1
+fi
+
+echo "package contracts agree at $release_version; apple_kit@$apple_revision"
diff --git a/scripts/xcode.sh b/scripts/xcode.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+set -euo pipefail
+
+for variable in XCODE_DERIVED_DATA XCODE_SOURCE_PACKAGES XCODE_PACKAGE_CACHE; do
+ if [[ -z "${!variable:-}" ]]; then
+ echo "error: $variable is required; run this command through cargo extbuild" >&2
+ exit 1
+ fi
+done
+
+output_args=(
+ -quiet
+ -derivedDataPath "$XCODE_DERIVED_DATA"
+ -clonedSourcePackagesDirPath "$XCODE_SOURCE_PACKAGES"
+ -packageCachePath "$XCODE_PACKAGE_CACHE"
+)
+offline_args=(
+ -disableAutomaticPackageResolution
+ -onlyUsePackageVersionsFromResolvedFile
+ -skipPackagePluginValidation
+)
+
+operation=${1:-}
+case "$operation" in
+ resolve)
+ exec xcodebuild \
+ -resolvePackageDependencies \
+ -project Radroots.xcodeproj \
+ -scheme Radroots \
+ "${output_args[@]}"
+ ;;
+ package-build)
+ exec xcodebuild \
+ -scheme RadrootsApp \
+ -destination 'generic/platform=iOS Simulator' \
+ "${output_args[@]}" \
+ "${offline_args[@]}" \
+ ARCHS=arm64 \
+ build
+ ;;
+ package-test)
+ destination=${2:?package-test requires a simulator destination}
+ exec xcodebuild \
+ -scheme RadrootsAppPublicAPITests \
+ -destination "$destination" \
+ "${output_args[@]}" \
+ "${offline_args[@]}" \
+ test
+ ;;
+ project-build)
+ configuration=${2:?project-build requires a configuration}
+ case "$configuration" in
+ Debug|Release) ;;
+ *) echo "error: unsupported configuration: $configuration" >&2; exit 1 ;;
+ esac
+ exec xcodebuild \
+ -project Radroots.xcodeproj \
+ -scheme Radroots \
+ -configuration "$configuration" \
+ -destination 'generic/platform=iOS Simulator' \
+ "${output_args[@]}" \
+ "${offline_args[@]}" \
+ build
+ ;;
+ project-test)
+ destination=${2:?project-test requires a simulator destination}
+ test_target=${3:?project-test requires a test target}
+ case "$test_target" in
+ RadrootsTests|RadrootsUITests) ;;
+ *) echo "error: unsupported test target: $test_target" >&2; exit 1 ;;
+ esac
+ exec xcodebuild \
+ -project Radroots.xcodeproj \
+ -scheme Radroots \
+ -destination "$destination" \
+ "${output_args[@]}" \
+ "${offline_args[@]}" \
+ "-only-testing:$test_target" \
+ test
+ ;;
+ *)
+ echo "usage: $0 {resolve|package-build|package-test|project-build|project-test}" >&2
+ exit 64
+ ;;
+esac