Files
chanora/tools/macos-postbuild.sh
EdisonJwa e3d7017dd9 feat(macos,ios): entitlements + permission strings + bundle-glue script
macOS:
  * Runner/DebugProfile.entitlements + Release.entitlements: add
    com.apple.security.network.client (outbound TS3 server connect)
    and com.apple.security.device.audio-input (microphone capture).
    Debug keeps com.apple.security.network.server + cs.allow-jit
    (Flutter hot-reload needs both); Release drops them.
  * Runner/Info.plist: add NSMicrophoneUsageDescription and
    NSInputMonitoringUsageDescription so the macOS system prompts
    show a sensible explanation when Chanora first needs mic or
    Input Monitoring access. Input Monitoring is required by
    CGEventTapCreate (SDD-085).
  * Runner.xcodeproj/project.pbxproj: switch Debug/Release/Profile
    code-signing from Automatic + Apple Development to Manual +
    "Sign to Run Locally" (CODE_SIGN_IDENTITY = -). This lets
    `flutter build macos --release` work over SSH where the login
    keychain is locked. The owner re-enables the personal team
    locally in Xcode for physical-device iOS testing later.

iOS:
  * Runner/Info.plist: add NSMicrophoneUsageDescription and the
    UIBackgroundModes = ['audio'] entry so voice traffic continues
    when the app is backgrounded (TS3 servers drop clients on idle
    audio streams).

tools/macos-postbuild.sh: new script. flutter build macos --release
emits build/macos/Build/Products/Release/chanora_flutter.app but
does NOT bundle libchanora_bridge.dylib. FRB on macOS dlopen()s the
bridge as chanora_bridge.framework/chanora_bridge, not a plain
dylib. This script:

  1. Wraps target/release/libchanora_bridge.dylib in a proper
     chanora_bridge.framework (Versions/A layout, Info.plist,
     Resources, symlinks).
  2. Rewrites LC_ID_DYLIB to
     @rpath/chanora_bridge.framework/chanora_bridge.
  3. Ad-hoc codesigns the framework and the .app bundle.
  4. Verifies with codesign --verify --deep --strict.

macOS analogue of buildit.cmd on Windows. Auto-integration into
Xcode build phases via cargokit / corrosion is a P1 carryover.

Verified end-to-end on the M1 Mac:
  cargo build --release -p chanora_bridge          11.76 s
  flutter build macos --release                    ok (59.2 MB)
  tools/macos-postbuild.sh Release                 ok
  chanora_flutter.app launch via SSH               bridge initialised,
                                                   identity + bookmark
                                                   store initialised
                                                   (~5 s smoke).
  ~/Library/Logs/app.chanora.chanora_flutter/chanora.log captures
  the boot sequence cleanly.

DEC-025 reference: macOS desktop is officially in scope.
2026-05-16 14:26:13 +09:00

90 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Post-process the Flutter macOS Release bundle so it actually launches:
#
# 1. Wrap target/release/libchanora_bridge.dylib into a proper
# chanora_bridge.framework bundle (Versions/A layout, Info.plist,
# symlinks). FRB on macOS dlopen()s chanora_bridge.framework/
# chanora_bridge — not the plain dylib.
# 2. Rewrite the dylib's LC_ID_DYLIB so dyld resolves it as
# @rpath/chanora_bridge.framework/chanora_bridge.
# 3. Ad-hoc codesign the framework + the .app bundle.
#
# This is the macOS analogue of buildit.cmd on Windows. cocogkit /
# corrosion-style auto-integration into the Xcode project is a P1
# carryover — for now we run this script after `flutter build macos
# --release`.
#
# Usage:
# tools/macos-postbuild.sh [Release|Debug] (defaults to Release)
set -euo pipefail
CONFIG="${1:-Release}"
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
APP="$REPO_ROOT/apps/chanora_flutter/build/macos/Build/Products/$CONFIG/chanora_flutter.app"
DYLIB="$REPO_ROOT/target/release/libchanora_bridge.dylib"
FW="$APP/Contents/Frameworks/chanora_bridge.framework"
if [[ ! -d "$APP" ]]; then
echo "ERROR: app bundle not found at $APP" >&2
echo " run \`flutter build macos --$(echo "$CONFIG" | tr '[:upper:]' '[:lower:]')\` first" >&2
exit 1
fi
if [[ ! -f "$DYLIB" ]]; then
echo "ERROR: bridge dylib not found at $DYLIB" >&2
echo " run \`cargo build --release -p chanora_bridge\` first" >&2
exit 2
fi
# Step 1: build the chanora_bridge.framework layout.
echo "[postbuild] wrapping bridge into chanora_bridge.framework"
rm -rf "$FW"
mkdir -p "$FW/Versions/A/Resources"
cp "$DYLIB" "$FW/Versions/A/chanora_bridge"
cat > "$FW/Versions/A/Resources/Info.plist" << 'PLIST'
<?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>CFBundleExecutable</key>
<string>chanora_bridge</string>
<key>CFBundleIdentifier</key>
<string>app.chanora.bridge</string>
<key>CFBundleName</key>
<string>chanora_bridge</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
PLIST
ln -sf A "$FW/Versions/Current"
ln -sf Versions/Current/chanora_bridge "$FW/chanora_bridge"
ln -sf Versions/Current/Resources "$FW/Resources"
# Step 2: rewrite install_name so dyld finds the bundled copy.
echo "[postbuild] install_name_tool -id @rpath/chanora_bridge.framework/chanora_bridge"
install_name_tool \
-id "@rpath/chanora_bridge.framework/chanora_bridge" \
"$FW/Versions/A/chanora_bridge"
# Drop a stale plain dylib if a previous build left one alongside the
# framework.
rm -f "$APP/Contents/Frameworks/libchanora_bridge.dylib"
# Step 3: codesign. Ad-hoc identity ('-') is sufficient for local
# launches; replace with a real Developer ID when distributing.
echo "[postbuild] codesigning framework + app (ad-hoc)"
codesign --force -s - --timestamp=none "$FW/Versions/A/chanora_bridge"
codesign --force -s - --timestamp=none "$FW"
codesign --force --deep -s - --timestamp=none "$APP"
codesign --verify --deep --strict "$APP"
echo "[postbuild] OK: $APP is launchable"