fix(ios,macos): address PR #26 review findings
- ios/Runner.xcodeproj/project.pbxproj: Update RunnerTests TEST_HOST paths from Runner.app/Runner to Chanora.app/Chanora (target was renamed in prior commit but test config still pointed at old paths, breaking xcodebuild test). - Cargo.toml: Move release DWARF flags from workspace [profile.release] into Apple-only podspec CARGO_PROFILE_RELEASE_* env vars so Android, Linux, Windows release builds stay lean (~10MB DWARF avoided). - ios/Runner/Info.plist + macos/Runner/Info.plist: Flip ITSAppUsesNonExemptEncryption from false to true (Chanora ships ChaCha20-Poly1305 local storage + tsclientlib ECDH/AES-EAX voice channel encryption, not exempt under Apple export-compliance rules). - scripts/verify_silero_exports.sh: Make slice-aware via lipo -archs loop + per-arch nm -arch invocation so universal macOS builds verify every architecture slice, not just whichever slice nm picks. - .gitignore: Drop .omo/ and .playwright-mcp/ entries (scope leak; unrelated tooling state, not part of PR #26 archive-symbol concern).
This commit is contained in:
@@ -136,6 +136,3 @@ Screenshot 2026-05-17 at 22.23.07.png
|
||||
# macOS release zip bundles produced by local release scripts
|
||||
/chanora-v*.zip
|
||||
|
||||
# Local agent / tooling state
|
||||
.omo/
|
||||
.playwright-mcp/
|
||||
|
||||
+11
-21
@@ -83,26 +83,16 @@ tsproto-types = { git = "https://github.com/EdisonJwa/tsclientlib.git", branch =
|
||||
[patch.crates-io]
|
||||
cmake = { git = "https://github.com/pr2502/cmake-rs", rev = "bdad5edc569d82151922c5c6c4685b1563f12aa1" }
|
||||
|
||||
# Emit DWARF debug info in release builds.
|
||||
# Apple-only DWARF emission for archive validation lives in the iOS and
|
||||
# macOS chanora_bridge podspecs (apps/chanora_flutter/{ios,macos}/
|
||||
# chanora_bridge.podspec) as per-build environment overrides:
|
||||
#
|
||||
# Apple's archive validator (and App Store Connect upload) require a
|
||||
# matching `.dSYM` for every embedded framework, keyed by the framework
|
||||
# binary's LC_UUID. The CocoaPods bridge podspecs copy the cargo-built
|
||||
# `libchanora_bridge.dylib` into `chanora_bridge.framework/chanora_bridge`
|
||||
# and then run `dsymutil` on it (see apps/chanora_flutter/ios and
|
||||
# apps/chanora_flutter/macos podspecs). `dsymutil` needs DWARF in the
|
||||
# input binary to produce a useful dSYM with symbol records; without
|
||||
# `debug = true` here we'd ship a stripped binary and an empty/unusable
|
||||
# dSYM and TestFlight crash reports would be unsymbolicated.
|
||||
# CARGO_PROFILE_RELEASE_DEBUG=true
|
||||
# CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off
|
||||
# CARGO_PROFILE_RELEASE_STRIP=false
|
||||
#
|
||||
# `split-debuginfo = "off"` keeps DWARF inside the dylib so install_name_tool
|
||||
# rewriting and the dsymutil pass both work without chasing per-object
|
||||
# `.o` files cargo would otherwise scatter under target/<triple>/release/deps.
|
||||
#
|
||||
# `strip = false` ensures cargo does not pre-strip the dylib before
|
||||
# dsymutil sees it. We strip the in-framework binary ourselves after the
|
||||
# dSYM is produced (handled in the podspec script phases).
|
||||
[profile.release]
|
||||
debug = true
|
||||
split-debuginfo = "off"
|
||||
strip = false
|
||||
# This keeps Android, Linux, and Windows release binaries on the cargo
|
||||
# default release profile (no DWARF, no extra ~10MB symbol payload).
|
||||
# Apple builds need the DWARF so dsymutil can emit a usable
|
||||
# chanora_bridge.framework.dSYM that the archive validator accepts.
|
||||
|
||||
|
||||
@@ -555,7 +555,7 @@
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Chanora.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Chanora";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -571,7 +571,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.chanora.chanoraFlutter.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Chanora.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Chanora";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -587,7 +587,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = app.chanora.chanoraFlutter.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Chanora.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Chanora";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
|
||||
@@ -102,6 +102,9 @@ Pod::Spec.new do |s|
|
||||
IPHONEOS_DEPLOYMENT_TARGET=16.0 \\
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \\
|
||||
CMAKE_OSX_DEPLOYMENT_TARGET=16.0 \\
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \\
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \\
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \\
|
||||
"$CARGO_BIN" build --release --target aarch64-apple-ios -p chanora_bridge
|
||||
|
||||
if [ ! -f "$BRIDGE" ]; then
|
||||
@@ -231,6 +234,9 @@ PLIST
|
||||
IPHONEOS_DEPLOYMENT_TARGET=16.0 \\
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \\
|
||||
CMAKE_OSX_DEPLOYMENT_TARGET=16.0 \\
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \\
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \\
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \\
|
||||
"$CARGO_BIN" build --release --target "$RUST_TARGET" -p chanora_bridge
|
||||
|
||||
cd "$REPO_ROOT/apps/chanora_flutter/ios"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -57,6 +57,9 @@ Pod::Spec.new do |s|
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \\
|
||||
LIBOPUS_STATIC=1 \\
|
||||
LIBOPUS_NO_PKG=1 \\
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \\
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \\
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \\
|
||||
cargo build --release --target aarch64-apple-darwin -p chanora_bridge
|
||||
|
||||
echo "[chanora_bridge.podspec] cargo build x86_64-apple-darwin"
|
||||
@@ -65,6 +68,9 @@ Pod::Spec.new do |s|
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \\
|
||||
LIBOPUS_STATIC=1 \\
|
||||
LIBOPUS_NO_PKG=1 \\
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \\
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \\
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \\
|
||||
cargo build --release --target x86_64-apple-darwin -p chanora_bridge
|
||||
|
||||
if [ ! -f "$BRIDGE_ARM64" ]; then
|
||||
@@ -158,6 +164,9 @@ PLIST
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
LIBOPUS_STATIC=1 \
|
||||
LIBOPUS_NO_PKG=1 \
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \
|
||||
cargo build --release --target aarch64-apple-darwin -p chanora_bridge
|
||||
|
||||
echo "[chanora_bridge script_phase] cargo build x86_64-apple-darwin"
|
||||
@@ -166,6 +175,9 @@ PLIST
|
||||
CMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
LIBOPUS_STATIC=1 \
|
||||
LIBOPUS_NO_PKG=1 \
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true \
|
||||
CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \
|
||||
CARGO_PROFILE_RELEASE_STRIP=false \
|
||||
cargo build --release --target x86_64-apple-darwin -p chanora_bridge
|
||||
|
||||
cd "$REPO_ROOT/apps/chanora_flutter/macos"
|
||||
|
||||
@@ -2,20 +2,23 @@
|
||||
# verify_silero_exports.sh
|
||||
#
|
||||
# Asserts that all six chanora_silero_vad_* C symbols that the Rust
|
||||
# chanora_bridge framework resolves via dlsym(RTLD_DEFAULT) are
|
||||
# present in the linked app binary's dynamic export table.
|
||||
# chanora_bridge framework resolves via dlsym(RTLD_DEFAULT) are present
|
||||
# in the linked app binary's dynamic export table — verified per
|
||||
# architecture slice for macOS universal builds, because `nm` on a
|
||||
# universal Mach-O without -arch will succeed if a symbol exists in ANY
|
||||
# slice, not every slice. A missing symbol in just the x86_64 slice
|
||||
# would silently break Intel Macs.
|
||||
#
|
||||
# Without this check, Xcode Archive's -dead_strip can silently
|
||||
# remove these Swift @_cdecl symbols because no Swift caller exists,
|
||||
# and CoreML VAD falls back to WebRTC on TestFlight/App Store with
|
||||
# no compile-time, link-time, or runtime warning. We hit that bug
|
||||
# once; this script ensures we never ship it again.
|
||||
# Without this check, Xcode Archive's -dead_strip can remove these
|
||||
# Swift @_cdecl symbols (no Swift caller exists) and CoreML VAD falls
|
||||
# back to WebRTC on TestFlight/App Store with no compile-time,
|
||||
# link-time, or runtime warning. We hit that bug once; this script
|
||||
# ensures we never ship it again.
|
||||
#
|
||||
# Runs as an Xcode build phase after Link Binary, on iOS and macOS.
|
||||
|
||||
set -e
|
||||
|
||||
# Xcode passes these. Outside Xcode, the caller must export them.
|
||||
if [ -z "${TARGET_BUILD_DIR}" ] || [ -z "${EXECUTABLE_PATH}" ]; then
|
||||
echo "error: verify_silero_exports.sh requires TARGET_BUILD_DIR and EXECUTABLE_PATH (run from Xcode build phase)" >&2
|
||||
exit 1
|
||||
@@ -37,20 +40,40 @@ _chanora_silero_vad_last_error
|
||||
_chanora_silero_vad_free_string
|
||||
"
|
||||
|
||||
EXPORTED=$(xcrun nm -gU "${BINARY}" 2>/dev/null | awk '{print $NF}')
|
||||
# Enumerate slices. `lipo -archs` prints arches space-separated for
|
||||
# universal Mach-O; for thin binaries it prints the single arch.
|
||||
ARCHS=$(xcrun lipo -archs "${BINARY}" 2>/dev/null || echo "")
|
||||
if [ -z "${ARCHS}" ]; then
|
||||
echo "error: xcrun lipo -archs failed for ${BINARY}; cannot enumerate slices" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MISSING=""
|
||||
for sym in ${REQUIRED_SYMBOLS}; do
|
||||
if ! echo "${EXPORTED}" | grep -qx "${sym}"; then
|
||||
MISSING="${MISSING} ${sym}"
|
||||
FAILED=0
|
||||
for arch in ${ARCHS}; do
|
||||
EXPORTED=$(xcrun nm -arch "${arch}" -gU "${BINARY}" 2>/dev/null | awk '{print $NF}')
|
||||
if [ -z "${EXPORTED}" ]; then
|
||||
echo "error: xcrun nm produced no output for arch=${arch} on ${BINARY}" >&2
|
||||
FAILED=1
|
||||
continue
|
||||
fi
|
||||
|
||||
MISSING=""
|
||||
for sym in ${REQUIRED_SYMBOLS}; do
|
||||
if ! echo "${EXPORTED}" | grep -qx "${sym}"; then
|
||||
MISSING="${MISSING} ${sym}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${MISSING}" ]; then
|
||||
echo "error: chanora_silero_vad exports missing from $(basename "${BINARY}") [arch=${arch}]:${MISSING}" >&2
|
||||
FAILED=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${MISSING}" ]; then
|
||||
echo "error: chanora_silero_vad exports missing from $(basename "${BINARY}"):${MISSING}" >&2
|
||||
if [ "${FAILED}" -ne 0 ]; then
|
||||
echo "error: Rust dlsym(RTLD_DEFAULT) resolution will fail and CoreML VAD will fall back to WebRTC." >&2
|
||||
echo "error: Check OTHER_LDFLAGS -exported_symbol entries in Flutter/*.xcconfig and the @_cdecl exports in Runner/SileroCoreMLBridge.swift." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "verify_silero_exports: all 6 chanora_silero_vad_* symbols present in $(basename "${BINARY}")"
|
||||
echo "verify_silero_exports: all 6 chanora_silero_vad_* symbols present in $(basename "${BINARY}") [arches: ${ARCHS}]"
|
||||
|
||||
Reference in New Issue
Block a user