fix(ios): keep App Group entitlement on widget/share extensions in App Store builds (#4891)
The App Store export re-sign (xcodebuild -exportArchive, automatic signing) stripped com.apple.security.application-groups from the ReadestWidget and ShareExtension binaries because both targets set CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION: YES. The provisioning profiles and source entitlements both grant the group, but the signed extension binaries did not, so the widget read an empty snapshot from the shared App Group container and showed only the placeholder book icon. Dev builds were unaffected. Remove the flag from both extension targets (the main app already ships the group correctly without it) so signing uses the exact CODE_SIGN_ENTITLEMENTS content. Add scripts/verify-ios-appstore-entitlements.sh and run it from release-ios-appstore.sh before upload so a stripped App Group fails the release instead of shipping a dead widget. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,10 @@ pnpm tauri ios build --export-method app-store-connect
|
||||
BUNDLE_DIR=src-tauri/gen/apple/build/arm64
|
||||
IPA_BUNDLE=$BUNDLE_DIR/Readest.ipa
|
||||
|
||||
# Guard: the App Store export re-sign must not strip the App Group entitlement
|
||||
# from the widget / share extensions, or the reading widget ships dead.
|
||||
bash scripts/verify-ios-appstore-entitlements.sh "$IPA_BUNDLE"
|
||||
|
||||
xcrun altool --upload-app --type ios --file $IPA_BUNDLE --apiKey $APPLE_API_KEY --apiIssuer $APPLE_API_ISSUER
|
||||
|
||||
echo "iOS build uploaded to App Store Connect."
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Verify the App Store IPA's app extensions carry the App Group entitlement.
|
||||
#
|
||||
# group.com.bilingify.readest is how the main app hands the reading-widget
|
||||
# snapshot (and the share extension its shared state) to its extensions via the
|
||||
# shared App Group container. Automatic App Store signing re-signs embedded
|
||||
# extensions during `xcodebuild -exportArchive`; if a target sets
|
||||
# CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YES, that re-sign silently strips
|
||||
# com.apple.security.application-groups from the extension binary even though
|
||||
# the provisioning profile and source .entitlements both grant it. The widget
|
||||
# then reads an empty snapshot and shows only a placeholder book icon, with no
|
||||
# build error. This guard fails the release before upload so it can't ship
|
||||
# broken again.
|
||||
set -euo pipefail
|
||||
|
||||
IPA="${1:-src-tauri/gen/apple/build/arm64/Readest.ipa}"
|
||||
GROUP="group.com.bilingify.readest"
|
||||
EXTS=(ReadestWidget ShareExtension)
|
||||
|
||||
if [ ! -f "$IPA" ]; then
|
||||
echo "verify-ios-appstore-entitlements: IPA not found at $IPA" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
unzip -q "$IPA" -d "$WORK"
|
||||
APP="$WORK/Payload/Readest.app"
|
||||
|
||||
fail=0
|
||||
for ext in "${EXTS[@]}"; do
|
||||
appex="$APP/PlugIns/$ext.appex"
|
||||
if codesign -d --entitlements :- "$appex" 2>/dev/null | grep -q "$GROUP"; then
|
||||
echo "OK $ext.appex carries $GROUP"
|
||||
else
|
||||
echo "FAIL $ext.appex is MISSING $GROUP (App Group access broken)"
|
||||
fail=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "" >&2
|
||||
echo "App Group entitlement missing from an extension binary. Do NOT set" >&2
|
||||
echo "CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION on extension targets in" >&2
|
||||
echo "src-tauri/gen/apple/project.yml." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All app extensions carry the App Group entitlement."
|
||||
@@ -153,16 +153,16 @@ targets:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.bilingify.readest.ShareExtension
|
||||
DEVELOPMENT_TEAM: J5W48D69VR
|
||||
CODE_SIGN_ENTITLEMENTS: ShareExtension/ShareExtension.entitlements
|
||||
# Permit Xcode's productPackagingUtility to write the auto-derived
|
||||
# signing entitlements (application-identifier, team-identifier,
|
||||
# get-task-allow) back to the source entitlements file at build
|
||||
# time. Without this, Xcode 16+ refuses the modification it
|
||||
# itself just performed and the build fails with:
|
||||
# "Entitlements file ... was modified during the build"
|
||||
# Safe for this target because the entitlements file is empty —
|
||||
# the only modifications Xcode performs are the team / app-id
|
||||
# auto-population every iOS extension target needs anyway.
|
||||
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION: YES
|
||||
# Do NOT set CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION here. This
|
||||
# entitlements file declares com.apple.security.application-groups
|
||||
# (group.com.bilingify.readest). With automatic App Store signing,
|
||||
# that flag lets `xcodebuild -exportArchive` overwrite the extension
|
||||
# entitlements with a minimal auto-derived set that DROPS the app
|
||||
# group — silently breaking App Group access in App Store builds
|
||||
# (dev builds are unaffected). The main app ships the group
|
||||
# correctly without this flag. If Xcode ever reports "Entitlements
|
||||
# file was modified during the build", fix it by adding the
|
||||
# auto-derived keys to the source file, not by re-enabling this flag.
|
||||
SWIFT_VERSION: "5.0"
|
||||
IPHONEOS_DEPLOYMENT_TARGET: 15.0
|
||||
ARCHS: [arm64]
|
||||
@@ -192,7 +192,10 @@ targets:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.bilingify.readest.ReadestWidget
|
||||
DEVELOPMENT_TEAM: J5W48D69VR
|
||||
CODE_SIGN_ENTITLEMENTS: ReadestWidget/ReadestWidget.entitlements
|
||||
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION: YES
|
||||
# CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION is intentionally omitted
|
||||
# (see ShareExtension): with it, the App Store export re-sign strips
|
||||
# com.apple.security.application-groups, so the widget reads an empty
|
||||
# snapshot from the App Group and shows only the placeholder book icon.
|
||||
SWIFT_VERSION: "5.0"
|
||||
IPHONEOS_DEPLOYMENT_TARGET: 15.0
|
||||
ARCHS: [arm64]
|
||||
|
||||
Reference in New Issue
Block a user