| | |
| | | # PRIVATEVOICE_SIGNING_KEYCHAIN |
| | | # PRIVATEVOICE_APPSTORE_MIN_SYSTEM_VERSION (default: 13.4) |
| | | # PRIVATEVOICE_MACAPPSTORE_BUILD_ROOT (default: build/macappstore) |
| | | # PRIVATEVOICE_APP_VERSION (default: build/darwin/Info.plist CFBundleShortVersionString) |
| | | # PRIVATEVOICE_APP_BUILD (default: build/darwin/Info.plist CFBundleVersion) |
| | | # |
| | | # Usage: |
| | | # cd privatevoice.src |
| | |
| | | APPSTORE_PROVISIONING_PROFILE="${PRIVATEVOICE_APPSTORE_PROVISIONING_PROFILE:-}" |
| | | SIGNING_KEYCHAIN="${PRIVATEVOICE_SIGNING_KEYCHAIN:-}" |
| | | APPSTORE_MIN_SYSTEM_VERSION="${PRIVATEVOICE_APPSTORE_MIN_SYSTEM_VERSION:-13.4}" |
| | | APPSTORE_APP_SIGN_IDENTITY="" |
| | | |
| | | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| | | PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" |
| | |
| | | |
| | | INFO_PLIST="$PROJECT_DIR/build/darwin/Info.plist" |
| | | BASE_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.0")" |
| | | BUILD_ID="$(defaults read "$INFO_PLIST" CFBundleVersion 2>/dev/null || date +%Y%m%d.%H%M)" |
| | | BUNDLE_ID="$(defaults read "$INFO_PLIST" CFBundleIdentifier 2>/dev/null || echo "")" |
| | | VERSION="${PRIVATEVOICE_APP_VERSION:-$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$INFO_PLIST" 2>/dev/null || echo "2.1.0")}" |
| | | BUILD_ID="${PRIVATEVOICE_APP_BUILD:-$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$INFO_PLIST" 2>/dev/null || date +%Y%m%d.%H%M)}" |
| | | BUNDLE_ID="$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST" 2>/dev/null || echo "")" |
| | | |
| | | step() { |
| | | echo "" |
| | |
| | | else |
| | | security find-identity -v |
| | | fi |
| | | } |
| | | |
| | | normalize_sha1() { |
| | | tr '[:lower:]' '[:upper:]' | tr -d ':[:space:]' |
| | | } |
| | | |
| | | is_sha1_fingerprint() { |
| | | [[ "$1" =~ ^[0-9A-Fa-f]{40}$ ]] |
| | | } |
| | | |
| | | resolve_codesigning_identity_sha1() { |
| | | local requested="$1" |
| | | local requested_sha1="" |
| | | local matches=() |
| | | local line hash name |
| | | |
| | | if is_sha1_fingerprint "$requested"; then |
| | | requested_sha1="$(printf "%s" "$requested" | normalize_sha1)" |
| | | fi |
| | | |
| | | while IFS= read -r line; do |
| | | hash="$(awk '{print $2}' <<<"$line")" |
| | | [[ "$hash" =~ ^[0-9A-Fa-f]{40}$ ]] || continue |
| | | name="${line#*\"}" |
| | | name="${name%\"*}" |
| | | |
| | | if [[ -n "$requested_sha1" ]]; then |
| | | [[ "$(printf "%s" "$hash" | normalize_sha1)" == "$requested_sha1" ]] && |
| | | matches+=("$(printf "%s" "$hash" | normalize_sha1)") |
| | | elif [[ "$name" == "$requested" ]]; then |
| | | matches+=("$(printf "%s" "$hash" | normalize_sha1)") |
| | | fi |
| | | done < <(security_find_code_identities) |
| | | |
| | | case "${#matches[@]}" in |
| | | 0) |
| | | fail "App Store app signing identity not found: $requested" |
| | | ;; |
| | | 1) |
| | | printf "%s\n" "${matches[0]}" |
| | | ;; |
| | | *) |
| | | fail "App Store app signing identity is ambiguous: $requested. Use the 40-character SHA1 fingerprint." |
| | | ;; |
| | | esac |
| | | } |
| | | |
| | | profile_developer_certificate_sha1s() { |
| | | local profile_plist="$1" |
| | | local index=0 |
| | | local cert_der cert_sha1 |
| | | local found=0 |
| | | |
| | | while :; do |
| | | cert_der="$(mktemp)" |
| | | if ! /usr/libexec/PlistBuddy -c "Print :DeveloperCertificates:$index" "$profile_plist" >"$cert_der" 2>/dev/null; then |
| | | rm -f "$cert_der" |
| | | break |
| | | fi |
| | | cert_sha1="$(openssl x509 -inform der -in "$cert_der" -noout -fingerprint -sha1 | |
| | | sed 's/^.*=//' | normalize_sha1)" |
| | | rm -f "$cert_der" |
| | | [[ -n "$cert_sha1" ]] || fail "Unable to read DeveloperCertificates:$index SHA1 from provisioning profile" |
| | | printf "%s\n" "$cert_sha1" |
| | | found=1 |
| | | index=$((index + 1)) |
| | | done |
| | | |
| | | [[ "$found" -eq 1 ]] || fail "Provisioning profile has no DeveloperCertificates" |
| | | } |
| | | |
| | | resolve_arch() { |
| | |
| | | codesign --force \ |
| | | --options runtime \ |
| | | --timestamp \ |
| | | --sign "$APPSTORE_APP_IDENTITY" \ |
| | | --sign "$APPSTORE_APP_SIGN_IDENTITY" \ |
| | | "$item" |
| | | } |
| | | |
| | |
| | | --options runtime \ |
| | | --timestamp \ |
| | | --entitlements "$SIGNING_ENTITLEMENTS" \ |
| | | --sign "$APPSTORE_APP_IDENTITY" \ |
| | | --sign "$APPSTORE_APP_SIGN_IDENTITY" \ |
| | | "$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. MAS candidates must load bundled dylibs. |
| | | 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 |
| | | } |
| | | |
| | | plist_set_string() { |
| | |
| | | [[ -f "$INFO_PLIST" ]] || fail "Info.plist not found at $INFO_PLIST" |
| | | [[ -n "$BUNDLE_ID" ]] || fail "CFBundleIdentifier is missing from $INFO_PLIST" |
| | | [[ -f "$BASE_ENTITLEMENTS" ]] || fail "App Store entitlements not found at $BASE_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")" |
| | | security_find_code_identities | grep -Fq "$APPSTORE_APP_IDENTITY" || |
| | | fail "App Store app signing identity not found: $APPSTORE_APP_IDENTITY" |
| | | APPSTORE_APP_SIGN_IDENTITY="$(resolve_codesigning_identity_sha1 "$APPSTORE_APP_IDENTITY")" |
| | | security_find_installer_identities | grep -Fq "$APPSTORE_INSTALLER_IDENTITY" || |
| | | fail "App Store installer signing identity not found: $APPSTORE_INSTALLER_IDENTITY" |
| | | command -v productbuild >/dev/null || fail "productbuild not found" |
| | |
| | | PROFILE_APP_IDENTIFIER="$(/usr/libexec/PlistBuddy -c "Print :Entitlements:com.apple.application-identifier" "$PROFILE_PLIST" 2>/dev/null || true)" |
| | | PROFILE_TEAM_IDENTIFIER="$(/usr/libexec/PlistBuddy -c "Print :Entitlements:com.apple.developer.team-identifier" "$PROFILE_PLIST" 2>/dev/null || true)" |
| | | PROFILE_KEYCHAIN_GROUP="$(/usr/libexec/PlistBuddy -c "Print :Entitlements:keychain-access-groups:0" "$PROFILE_PLIST" 2>/dev/null || true)" |
| | | PROFILE_DEVELOPER_CERT_SHA1S="$(profile_developer_certificate_sha1s "$PROFILE_PLIST")" |
| | | PROFILE_BUNDLE_ID="${PROFILE_APP_IDENTIFIER#*.}" |
| | | [[ "$PROFILE_BUNDLE_ID" == "$BUNDLE_ID" ]] || |
| | | fail "Provisioning profile bundle ID mismatch: profile has $PROFILE_BUNDLE_ID, app has $BUNDLE_ID" |
| | | [[ -n "$PROFILE_TEAM_IDENTIFIER" ]] || fail "Provisioning profile missing com.apple.developer.team-identifier entitlement" |
| | | if ! grep -Fxq "$APPSTORE_APP_SIGN_IDENTITY" <<<"$PROFILE_DEVELOPER_CERT_SHA1S"; then |
| | | fail "App Store app signing identity certificate mismatch: identity SHA1 $APPSTORE_APP_SIGN_IDENTITY is not present in provisioning profile DeveloperCertificates: $(tr '\n' ',' <<<"$PROFILE_DEVELOPER_CERT_SHA1S" | sed 's/,$//')" |
| | | fi |
| | | |
| | | cp "$BASE_ENTITLEMENTS" "$SIGNING_ENTITLEMENTS" |
| | | plist_set_string "$SIGNING_ENTITLEMENTS" "com.apple.application-identifier" "$PROFILE_APP_IDENTIFIER" |
| | |
| | | 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" |
| | | plist_set_string "$APP_BUNDLE/Contents/Info.plist" "CFBundleShortVersionString" "$VERSION" |
| | | plist_set_string "$APP_BUNDLE/Contents/Info.plist" "CFBundleVersion" "$BUILD_ID" |
| | | /usr/libexec/PlistBuddy -c "Set :LSMinimumSystemVersion $APPSTORE_MIN_SYSTEM_VERSION" \ |
| | | "$APP_BUNDLE/Contents/Info.plist" |
| | | cp "$APPSTORE_PROVISIONING_PROFILE" "$APP_BUNDLE/Contents/embedded.provisionprofile" |
| | | 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" \ |
| | |
| | | step "Mac App Store package complete" |
| | | echo " App: $APP_BUNDLE" |
| | | echo " PKG: $PKG_PATH" |
| | | echo " App signing identity: $APPSTORE_APP_IDENTITY" |
| | | echo " App signing identity: $APPSTORE_APP_IDENTITY ($APPSTORE_APP_SIGN_IDENTITY)" |
| | | echo " Installer signing identity: $APPSTORE_INSTALLER_IDENTITY" |