| | |
| | | # cd VoiceSnapGo |
| | | # ./scripts/build-appstore-macos.sh [arm64|x86_64] |
| | | # |
| | | # For local QA app refresh without creating a DMG: |
| | | # PRIVATEVOICE_APPSTORE_LOCAL_APP_ONLY=1 ./scripts/build-appstore-macos.sh arm64 |
| | | # |
| | | # Optional candidate version override: |
| | | # PRIVATEVOICE_APP_VERSION=2.2.3 PRIVATEVOICE_APP_BUILD=YYYYMMDD.HHMM |
| | | # |
| | | set -euo pipefail |
| | | |
| | | APP_NAME="PrivateVoice Dictation" |
| | | LOCAL_IDENTITY="${PRIVATEVOICE_LOCAL_SIGN_IDENTITY:-PrivateVoice Local Code Signing}" |
| | | LOCAL_IDENTITY="${PRIVATEVOICE_APPSTORE_LOCAL_SIGN_IDENTITY:-${PRIVATEVOICE_LOCAL_SIGN_IDENTITY:-}}" |
| | | FALLBACK_LOCAL_IDENTITY="PrivateVoice Local Code Signing" |
| | | KEYCHAIN="${PRIVATEVOICE_LOCAL_KEYCHAIN:-$HOME/Library/Keychains/login.keychain-db}" |
| | | APPSTORE_MIN_SYSTEM_VERSION="${PRIVATEVOICE_APPSTORE_MIN_SYSTEM_VERSION:-13.4}" |
| | | APP_ONLY="${PRIVATEVOICE_APPSTORE_LOCAL_APP_ONLY:-0}" |
| | | |
| | | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| | | PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" |
| | | |
| | | INFO_PLIST="$PROJECT_DIR/build/darwin/Info.plist" |
| | | ENTITLEMENTS="$PROJECT_DIR/build/darwin/entitlements-appstore.plist" |
| | | PRIVACY_MANIFEST="$PROJECT_DIR/build/darwin/PrivacyInfo.xcprivacy" |
| | | GOMODCACHE="$(go env GOMODCACHE)" |
| | | SHERPA_MACOS_MODULE_VERSION="$(cd "$PROJECT_DIR" && go list -m -f '{{.Version}}' github.com/k2-fsa/sherpa-onnx-go-macos)" |
| | | |
| | | VERSION="$(defaults read "$INFO_PLIST" CFBundleShortVersionString 2>/dev/null || echo "2.1.12")" |
| | | BUILD_ID="$(defaults read "$INFO_PLIST" CFBundleVersion 2>/dev/null || date +%Y%m%d.%H%M)" |
| | | VERSION="${PRIVATEVOICE_APP_VERSION:-$(defaults read "$INFO_PLIST" CFBundleShortVersionString 2>/dev/null || echo "2.1.12")}" |
| | | BUILD_ID="${PRIVATEVOICE_APP_BUILD:-$(defaults read "$INFO_PLIST" CFBundleVersion 2>/dev/null || date +%Y%m%d.%H%M)}" |
| | | |
| | | TARGET_ARCH="${1:-$(uname -m)}" |
| | | |
| | |
| | | fail() { |
| | | echo "ERROR: $1" >&2 |
| | | exit 1 |
| | | } |
| | | |
| | | resolve_signing_identity() { |
| | | if [[ -n "$LOCAL_IDENTITY" ]]; then |
| | | return |
| | | fi |
| | | |
| | | LOCAL_IDENTITY="$( |
| | | security find-identity -v -p codesigning "$KEYCHAIN" | |
| | | sed -n 's/.*"\(Apple Development:[^"]*\)".*/\1/p' | |
| | | head -n 1 |
| | | )" |
| | | |
| | | if [[ -z "$LOCAL_IDENTITY" ]]; then |
| | | LOCAL_IDENTITY="$FALLBACK_LOCAL_IDENTITY" |
| | | fi |
| | | } |
| | | |
| | | case "$TARGET_ARCH" in |
| | |
| | | "$item" |
| | | } |
| | | |
| | | fix_binary_rpaths() { |
| | | local binary="$1" |
| | | # The sherpa-onnx macOS module injects its cache lib directory as an LC_RPATH |
| | | # ahead of bundle Frameworks. In a sandboxed signed app, dyld may then load the |
| | | # module-cache dylib with a different signing identity and crash on launch. |
| | | install_name_tool -delete_rpath "$SHERPA_LIB_DIR" "$binary" 2>/dev/null || true |
| | | install_name_tool -add_rpath @executable_path/../Frameworks "$binary" 2>/dev/null || true |
| | | } |
| | | |
| | | step "Preflight checks" |
| | | [[ -f "$INFO_PLIST" ]] || fail "Info.plist not found at $INFO_PLIST" |
| | | [[ -f "$ENTITLEMENTS" ]] || fail "App Store entitlements not found at $ENTITLEMENTS" |
| | | [[ -f "$PRIVACY_MANIFEST" ]] || fail "PrivacyInfo.xcprivacy not found at $PRIVACY_MANIFEST" |
| | | [[ -f "$PROJECT_DIR/build/darwin/icon.icns" ]] || fail "icon.icns not found" |
| | | [[ -d "$SHERPA_LIB_DIR" ]] || fail "sherpa-onnx dylibs not found at $SHERPA_LIB_DIR" |
| | | ONNXRUNTIME_DYLIB="$(find "$SHERPA_LIB_DIR" -maxdepth 1 -type f -name 'libonnxruntime.*.dylib' | sort | tail -n 1)" |
| | | [[ -f "$ONNXRUNTIME_DYLIB" ]] || fail "onnxruntime dylib not found in $SHERPA_LIB_DIR" |
| | | ONNXRUNTIME_DYLIB_NAME="$(basename "$ONNXRUNTIME_DYLIB")" |
| | | resolve_signing_identity |
| | | security find-identity -v -p codesigning "$KEYCHAIN" | grep -Fq "$LOCAL_IDENTITY" || |
| | | fail "Local signing identity not found: $LOCAL_IDENTITY" |
| | | |
| | |
| | | MACOSX_DEPLOYMENT_TARGET="$APPSTORE_MIN_SYSTEM_VERSION" \ |
| | | CGO_CFLAGS="${CGO_CFLAGS:-} -mmacosx-version-min=$APPSTORE_MIN_SYSTEM_VERSION" \ |
| | | CGO_LDFLAGS="${CGO_LDFLAGS:-} -mmacosx-version-min=$APPSTORE_MIN_SYSTEM_VERSION" \ |
| | | go build -tags appstore -buildvcs=false -gcflags=all="-l" -ldflags="-s -w" \ |
| | | go build -tags appstore -buildvcs=false -gcflags=all="-l" \ |
| | | -ldflags="-s -w -X main.appVersion=$VERSION -X main.appBuild=$BUILD_ID" \ |
| | | -o "$BUILD_DIR/$APP_NAME" |
| | | |
| | | step "Assembling $APP_NAME.app" |
| | |
| | | mkdir -p "$APP_BUNDLE/Contents/Resources" |
| | | |
| | | cp "$INFO_PLIST" "$APP_BUNDLE/Contents/Info.plist" |
| | | /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" \ |
| | | "$APP_BUNDLE/Contents/Info.plist" |
| | | /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_ID" \ |
| | | "$APP_BUNDLE/Contents/Info.plist" |
| | | /usr/libexec/PlistBuddy -c "Set :LSMinimumSystemVersion $APPSTORE_MIN_SYSTEM_VERSION" \ |
| | | "$APP_BUNDLE/Contents/Info.plist" |
| | | cp "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/Contents/MacOS/$APP_NAME" |
| | | cp "$PROJECT_DIR/build/darwin/icon.icns" "$APP_BUNDLE/Contents/Resources/icon.icns" |
| | | cp "$PRIVACY_MANIFEST" "$APP_BUNDLE/Contents/Resources/PrivacyInfo.xcprivacy" |
| | | find "$PROJECT_DIR/build/darwin" -maxdepth 1 -type d -name "*.lproj" \ |
| | | -exec cp -R {} "$APP_BUNDLE/Contents/Resources/" \; |
| | | cp "$SHERPA_LIB_DIR/libsherpa-onnx-c-api.dylib" "$APP_BUNDLE/Contents/Frameworks/" |
| | |
| | | step "Fixing rpaths" |
| | | install_name_tool -add_rpath @executable_path/../Frameworks \ |
| | | "$APP_BUNDLE/Contents/MacOS/$APP_NAME" 2>/dev/null || true |
| | | fix_binary_rpaths "$APP_BUNDLE/Contents/MacOS/$APP_NAME" |
| | | install_name_tool -id @rpath/libsherpa-onnx-c-api.dylib \ |
| | | "$APP_BUNDLE/Contents/Frameworks/libsherpa-onnx-c-api.dylib" |
| | | install_name_tool -id "@rpath/$ONNXRUNTIME_DYLIB_NAME" \ |
| | |
| | | codesign -d --entitlements :- "$APP_BUNDLE" |
| | | |
| | | step "Creating POC DMG" |
| | | if [[ "$APP_ONLY" == "1" ]]; then |
| | | echo " Skipped because PRIVATEVOICE_APPSTORE_LOCAL_APP_ONLY=1" |
| | | else |
| | | DMG_TEMP="$BUILD_DIR/dmg-staging" |
| | | rm -rf "$DMG_TEMP" |
| | | mkdir -p "$DMG_TEMP" |
| | |
| | | -ov -format UDZO \ |
| | | "$DMG_PATH" |
| | | rm -rf "$DMG_TEMP" |
| | | fi |
| | | |
| | | step "App Sandbox POC build complete" |
| | | echo " App: $APP_BUNDLE" |
| | | if [[ "$APP_ONLY" == "1" ]]; then |
| | | echo " DMG: skipped" |
| | | else |
| | | echo " DMG: $DMG_PATH" |
| | | fi |
| | | echo " Signing identity: $LOCAL_IDENTITY" |