diff --git a/App/BlurtiOS/BlurtiOS/Sources/AudioSource.swift b/App/BlurtiOS/BlurtiOS/Sources/AudioSource.swift index 17f1a7aa..f252db6d 100644 --- a/App/BlurtiOS/BlurtiOS/Sources/AudioSource.swift +++ b/App/BlurtiOS/BlurtiOS/Sources/AudioSource.swift @@ -31,10 +31,10 @@ nonisolated final class WindowedAudioSource: NSObject, ListeningSource, @uncheck private let session = AVCaptureSession() private let output = AVCaptureAudioDataOutput() /// Serial, so the converter below needs no lock. - private let deliveryQueue = DispatchQueue(label: "com.assemblyai.blurt.ios.capture") + private let deliveryQueue = DispatchQueue(label: "com.assemblyai.blurt.iphone.capture") /// Where the session is started and stopped — both block for a while on a /// phone — so the main actor never waits on the capture stack. - private let controlQueue = DispatchQueue(label: "com.assemblyai.blurt.ios.capture.control") + private let controlQueue = DispatchQueue(label: "com.assemblyai.blurt.iphone.capture.control") private nonisolated(unsafe) var converter: PCMConverter? var levels: AsyncStream { feed.levels } diff --git a/App/BlurtiOS/BlurtiOS/Sources/BlurtiOSApp.swift b/App/BlurtiOS/BlurtiOS/Sources/BlurtiOSApp.swift index a9d2d686..bf26f6f6 100644 --- a/App/BlurtiOS/BlurtiOS/Sources/BlurtiOSApp.swift +++ b/App/BlurtiOS/BlurtiOS/Sources/BlurtiOSApp.swift @@ -17,7 +17,7 @@ struct BlurtiOSApp: App { HostIdentity.configure( HostIdentity( productName: "Blurt", - subsystem: "com.assemblyai.blurt.ios", + subsystem: "com.assemblyai.blurt.iphone", keychainService: "blurt-ios", defaultsPrefix: "Blurt", logDirectoryName: "Blurt")) diff --git a/App/BlurtiOS/BlurtiOSCore/SharedState.swift b/App/BlurtiOS/BlurtiOSCore/SharedState.swift index 4cc64740..3d5b046f 100644 --- a/App/BlurtiOS/BlurtiOSCore/SharedState.swift +++ b/App/BlurtiOS/BlurtiOSCore/SharedState.swift @@ -14,7 +14,7 @@ package nonisolated enum BlurtShared { /// The App Group both targets declare. A placeholder namespace inherited from /// the Mac app; an org-owned id replaces it before the App Store, and the app /// and the keyboard must change together. - package static let appGroup = "group.com.assemblyai.blurt.ios" + package static let appGroup = "group.com.assemblyai.blurt.iphone" /// The URL the keyboard opens to bring the app forward (`blurt://start`) — /// the one moment iOS insists on before the microphone may open. package static let urlScheme = "blurt" @@ -48,10 +48,10 @@ package nonisolated enum BlurtShared { /// Darwin notification names. Reverse-DNS so they can't collide with another /// app's on the same device. package nonisolated enum Signal { - package static let command = "com.assemblyai.blurt.ios.command" - package static let phase = "com.assemblyai.blurt.ios.phase" - package static let result = "com.assemblyai.blurt.ios.result" - package static let lexicon = "com.assemblyai.blurt.ios.lexicon" + package static let command = "com.assemblyai.blurt.iphone.command" + package static let phase = "com.assemblyai.blurt.iphone.phase" + package static let result = "com.assemblyai.blurt.iphone.result" + package static let lexicon = "com.assemblyai.blurt.iphone.lexicon" } } diff --git a/App/BlurtiOS/README.md b/App/BlurtiOS/README.md index b972a953..0ff411fb 100644 --- a/App/BlurtiOS/README.md +++ b/App/BlurtiOS/README.md @@ -34,8 +34,8 @@ Mac with only the Command Line Tools — no iOS SDK — `scripts/ios-typecheck.s typechecks both targets against the Mac Catalyst frameworks with the same flags, which catches the Swift 6 isolation errors before CI does. Running on a phone needs Xcode with a team that can provision the App Group. The ids in -`project.yml` (`com.assemblyai.blurt.ios`, `com.assemblyai.blurt.ios.keyboard`, -`group.com.assemblyai.blurt.ios`) are AssemblyAI's, so they register under the AssemblyAI team; +`project.yml` (`com.assemblyai.blurt.iphone`, `com.assemblyai.blurt.iphone.keyboard`, +`group.com.assemblyai.blurt.iphone`) are AssemblyAI's, so they register under the AssemblyAI team; anyone building under another team changes them locally (see Testing on a phone). ## Design @@ -130,8 +130,8 @@ shows its console. characters after the team's name). The App Group needs a paid team — a free Personal Team cannot register one, so use the org's team, not your own. 3. `cd App/BlurtiOS && BLURT_TEAM= xcodegen generate && open BlurtiOS.xcodeproj`. - Automatic signing registers `com.assemblyai.blurt.ios`, `com.assemblyai.blurt.ios.keyboard` and - `group.com.assemblyai.blurt.ios` under that team on the first build; it fails if another team already + Automatic signing registers `com.assemblyai.blurt.iphone`, `com.assemblyai.blurt.iphone.keyboard` and + `group.com.assemblyai.blurt.iphone` under that team on the first build; it fails if another team already owns them. 4. Plug the phone in (Developer Mode on: Settings → Privacy & Security), pick it as the run destination, run the `BlurtiOS` scheme. On the phone, trust the developer app (Settings → diff --git a/App/BlurtiOS/project.yml b/App/BlurtiOS/project.yml index 699907b9..a62ce6b8 100644 --- a/App/BlurtiOS/project.yml +++ b/App/BlurtiOS/project.yml @@ -9,11 +9,17 @@ # # Two processes, one App Group. iOS lets no keyboard use the microphone, so the # app records and talks to AssemblyAI while the keyboard is a remote control that -# inserts the result; they share `group.com.assemblyai.blurt.ios` (see +# inserts the result; they share `group.com.assemblyai.blurt.iphone` (see # BlurtiOSCore/SharedState.swift). Every id is AssemblyAI-owned -# (`com.assemblyai.blurt.ios…`); the team comes from $BLURT_TEAM, never this +# (`com.assemblyai.blurt.iphone…`); the team comes from $BLURT_TEAM, never this # file. The Mac app keeps its own `dev.alex.blurt` ids: changing them would # orphan its Sparkle updates and its granted Accessibility permission. +# +# Not `com.assemblyai.blurt.ios`: that one went to a personal team's App Store +# Connect record before the AssemblyAI organization existed, and a bundle id a +# build was uploaded under can never be reused, or transferred until the app +# is released. `.iphone` also leaves `com.assemblyai.blurt` for a Mac app that +# might one day move off `dev.alex.blurt`. name: BlurtiOS options: bundleIdPrefix: com.assemblyai @@ -63,7 +69,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios.core + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone.core GENERATE_INFOPLIST_FILE: YES SWIFT_TREAT_WARNINGS_AS_ERRORS: YES SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor @@ -89,7 +95,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios.design + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone.design GENERATE_INFOPLIST_FILE: YES SWIFT_TREAT_WARNINGS_AS_ERRORS: YES SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor @@ -122,7 +128,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon # The app-level accent, from the catalog, so system-drawn chrome and our # views agree (see the Mac's project.yml and BlurtBrand). @@ -162,7 +168,7 @@ targets: # `blurt://start` — what the keyboard opens to bring the app forward, the # one moment iOS insists on before the microphone may open. CFBundleURLTypes: - - CFBundleURLName: com.assemblyai.blurt.ios + - CFBundleURLName: com.assemblyai.blurt.iphone CFBundleURLSchemes: [blurt] # A shared key-term list (`.blurtterms`, JSON): declared so a tap on # one in Messages offers Blurt, which opens it as an import. @@ -185,7 +191,8 @@ targets: entitlements: path: BlurtiOS/BlurtiOS.entitlements properties: - com.apple.security.application-groups: [group.com.assemblyai.blurt.ios] + com.apple.security.application-groups: + [group.com.assemblyai.blurt.iphone] dependencies: - package: BlurtEngine product: BlurtEngine @@ -207,7 +214,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios.keyboard + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone.keyboard SWIFT_TREAT_WARNINGS_AS_ERRORS: YES SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor APPLICATION_EXTENSION_API_ONLY: YES @@ -228,7 +235,8 @@ targets: entitlements: path: BlurtKeyboard/BlurtKeyboard.entitlements properties: - com.apple.security.application-groups: [group.com.assemblyai.blurt.ios] + com.apple.security.application-groups: + [group.com.assemblyai.blurt.iphone] dependencies: - package: BlurtEngine product: BlurtEngine @@ -260,7 +268,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios.tests + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone.tests GENERATE_INFOPLIST_FILE: YES SWIFT_TREAT_WARNINGS_AS_ERRORS: YES SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor @@ -279,7 +287,7 @@ targets: settings: base: TARGETED_DEVICE_FAMILY: "1" - PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.ios.probe + PRODUCT_BUNDLE_IDENTIFIER: com.assemblyai.blurt.iphone.probe TEST_TARGET_NAME: BlurtiOS GENERATE_INFOPLIST_FILE: YES SWIFT_TREAT_WARNINGS_AS_ERRORS: YES diff --git a/scripts/ios-keyboard-flows.sh b/scripts/ios-keyboard-flows.sh index 0029b694..a9ff42d0 100755 --- a/scripts/ios-keyboard-flows.sh +++ b/scripts/ios-keyboard-flows.sh @@ -69,7 +69,7 @@ ios_wait_booted "$UDID" xcodebuild build -project "$REPO_ROOT/App/BlurtiOS/BlurtiOS.xcodeproj" -scheme BlurtiOS \ -destination "platform=iOS Simulator,id=$UDID" -derivedDataPath "$DERIVED" "${IOS_SIM_SIGNING[@]}" -quiet xcrun simctl install "$UDID" "$DERIVED/Build/Products/Debug-iphonesimulator/BlurtiOS.app" -xcrun simctl privacy "$UDID" grant microphone com.assemblyai.blurt.ios +xcrun simctl privacy "$UDID" grant microphone com.assemblyai.blurt.iphone for face in $FACES; do xcrun simctl ui "$UDID" appearance "$face" @@ -131,9 +131,9 @@ echo "ios-keyboard-flows: screenshots in $OUT" # back through the simulator's own defaults daemon (a plist edit alone is # not seen until cfprefsd reloads). if [ -n "$ALIGN" ]; then - GROUP="$(xcrun simctl get_app_container "$UDID" com.assemblyai.blurt.ios groups 2>/dev/null | awk -F'\t' '/group.com.assemblyai.blurt.ios/ {print $2}')" + GROUP="$(xcrun simctl get_app_container "$UDID" com.assemblyai.blurt.iphone groups 2>/dev/null | awk -F'\t' '/group.com.assemblyai.blurt.iphone/ {print $2}')" if [ -n "$GROUP" ]; then - xcrun simctl spawn "$UDID" defaults write "$GROUP/Library/Preferences/group.com.assemblyai.blurt.ios" micAlignment center + xcrun simctl spawn "$UDID" defaults write "$GROUP/Library/Preferences/group.com.assemblyai.blurt.iphone" micAlignment center echo "ios-keyboard-flows: mic alignment back to the middle" fi fi diff --git a/scripts/ios-record.sh b/scripts/ios-record.sh index 2112bbb8..60d5207e 100755 --- a/scripts/ios-record.sh +++ b/scripts/ios-record.sh @@ -75,7 +75,7 @@ read -r CROP_W CROP_H CROP_X CROP_Y < <(swift scripts/design-diff.swift crop "$r } ios_require_device ios-record -BUNDLE_ID=com.assemblyai.blurt.ios +BUNDLE_ID=com.assemblyai.blurt.iphone echo "==> recording $name (two cycles)" xcrun simctl terminate "$UDID" "$BUNDLE_ID" 2>/dev/null || true diff --git a/scripts/ios-sim.sh b/scripts/ios-sim.sh index 807aa250..d3be545d 100755 --- a/scripts/ios-sim.sh +++ b/scripts/ios-sim.sh @@ -23,7 +23,7 @@ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" source "$REPO_ROOT/scripts/ios-lib.sh" DERIVED="$IOS_DERIVED" # PRODUCT_BUNDLE_IDENTIFIER in App/BlurtiOS/project.yml. -BUNDLE_ID=com.assemblyai.blurt.ios +BUNDLE_ID=com.assemblyai.blurt.iphone SHOT="" BUILD=1 while [ $# -gt 0 ]; do