diff --git a/clients/apple/iOS/VoiceCatBroadcast/Info.plist b/clients/apple/iOS/VoiceCatBroadcast/Info.plist
index fb2db3f..576a2fb 100644
--- a/clients/apple/iOS/VoiceCatBroadcast/Info.plist
+++ b/clients/apple/iOS/VoiceCatBroadcast/Info.plist
@@ -25,7 +25,7 @@
NSExtensionPrincipalClass
$(PRODUCT_MODULE_NAME).SampleHandler
RPBroadcastProcessMode
- BroadcastUpload
+ RPBroadcastProcessModeSampleBuffer
diff --git a/clients/apple/scripts/build-xcframework.sh b/clients/apple/scripts/build-xcframework.sh
index adf6992..93eda46 100755
--- a/clients/apple/scripts/build-xcframework.sh
+++ b/clients/apple/scripts/build-xcframework.sh
@@ -155,5 +155,20 @@ xcodebuild -create-xcframework "${args[@]}" -output "$OUTPUT"
# Clean up staged headers (the xcframework has its own copy now).
rm -rf "$STAGED_ROOT"
+# ── Code-sign ────────────────────────────────────────────────────────────────────
+# Xcode 15+ rejects unsigned binary XCFrameworks consumed as SwiftPM binary targets
+# ("The Framework VoiceCatCore.xcframework is unsigned."). Sign with CODESIGN_IDENTITY
+# if set, else the first "Apple Development" identity in the keychain, else ad-hoc ("-").
+# The .xcframework is a local build artifact (gitignored), so signing with the local
+# developer identity is fine and not committed.
+SIGN_ID="${CODESIGN_IDENTITY:-}"
+if [[ -z "$SIGN_ID" ]]; then
+ SIGN_ID="$(security find-identity -v -p codesigning 2>/dev/null \
+ | awk '/Apple Development/{print $2; exit}')"
+fi
+SIGN_ID="${SIGN_ID:--}" # fall back to ad-hoc
+codesign --force --timestamp=none --sign "$SIGN_ID" "$OUTPUT"
+echo "[build-xcframework] signed with identity: $SIGN_ID"
+
echo "[build-xcframework] done -> $OUTPUT"
xcodebuild -list -xcframework "$OUTPUT" 2>/dev/null || true