81802a7c72
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>
209 lines
9.0 KiB
YAML
209 lines
9.0 KiB
YAML
name: Readest
|
|
options:
|
|
bundleIdPrefix: com.bilingify.readest
|
|
deploymentTarget:
|
|
iOS: 15.0
|
|
fileGroups: [../../src]
|
|
configs:
|
|
debug: debug
|
|
release: release
|
|
settingGroups:
|
|
app:
|
|
base:
|
|
PRODUCT_NAME: Readest
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.bilingify.readest
|
|
DEVELOPMENT_TEAM: J5W48D69VR
|
|
targetTemplates:
|
|
app:
|
|
type: application
|
|
sources:
|
|
- path: Sources
|
|
scheme:
|
|
environmentVariables:
|
|
RUST_BACKTRACE: full
|
|
RUST_LOG: info
|
|
settings:
|
|
groups: [app]
|
|
targets:
|
|
Readest_iOS:
|
|
type: application
|
|
platform: iOS
|
|
# NOTE on In-App Purchase capability
|
|
# ----------------------------------
|
|
# IAP is enabled at three layers:
|
|
# 1. App ID `com.bilingify.readest` services (Apple Developer
|
|
# portal) — must have "In-App Purchase" service ON.
|
|
# 2. Provisioning profile — pulled automatically by Xcode when
|
|
# DEVELOPMENT_TEAM is set; inherits IAP from the App ID.
|
|
# 3. StoreKit framework — linked transitively by the
|
|
# tauri-plugin-native-bridge plugin's iap_* commands.
|
|
# The `SystemCapabilities` pbxproj entry that Xcode writes when you
|
|
# add IAP via Signing & Capabilities is informational only; it
|
|
# doesn't gate the actual capability. xcodegen 2.45 can't
|
|
# round-trip nested dictionaries into pbxproj attributes (it
|
|
# serializes them as quoted strings), so we omit the entry rather
|
|
# than ship a malformed one. IAP works without it.
|
|
sources:
|
|
- path: Sources
|
|
- path: Assets.xcassets
|
|
# Only reference Externals as a file group (no compile/resource
|
|
# phases) — the actual libapp.a lookup happens via the
|
|
# `framework: libapp.a` dependency + LIBRARY_SEARCH_PATHS pointing
|
|
# at `Externals/arm64/$(CONFIGURATION)`. Listing the whole folder
|
|
# as a source caused xcodegen to add copy-resource phases for
|
|
# both `debug/libapp.a` and `release/libapp.a`, conflicting at
|
|
# build time:
|
|
# "Multiple commands produce Readest.app/libapp.a"
|
|
- path: Externals
|
|
buildPhase: none
|
|
- path: Readest_iOS
|
|
- path: assets
|
|
buildPhase: resources
|
|
type: folder
|
|
- path: LaunchScreen.storyboard
|
|
# Info.plist and entitlements live on disk with hand-tuned content
|
|
# (CFBundleDocumentTypes, UTExportedTypeDeclarations, locales,
|
|
# CFBundleURLTypes for readest://, com.apple.developer.applesignin,
|
|
# associated-domains for Universal Links). Reference them via
|
|
# INFOPLIST_FILE / CODE_SIGN_ENTITLEMENTS instead of `info:` /
|
|
# `entitlements:` so xcodegen treats them as opaque inputs and
|
|
# doesn't rewrite them on regeneration.
|
|
scheme:
|
|
environmentVariables:
|
|
RUST_BACKTRACE: full
|
|
RUST_LOG: info
|
|
settings:
|
|
base:
|
|
INFOPLIST_FILE: Readest_iOS/Info.plist
|
|
CODE_SIGN_ENTITLEMENTS: Readest_iOS/Readest_iOS.entitlements
|
|
ENABLE_BITCODE: false
|
|
ARCHS: [arm64]
|
|
VALID_ARCHS: arm64
|
|
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
|
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
|
|
# Tell Xcode the app embeds Swift code (the new ShareExtension
|
|
# is a Swift app-extension target). Without this the
|
|
# swift-stdlib-tool phase that copies libswiftCore.dylib +
|
|
# friends into Readest.app/Frameworks runs incorrectly under
|
|
# Xcode 26 — the app launches and immediately dyld-fails with
|
|
# "libswiftCore.dylib: no such file".
|
|
EMBEDDED_CONTENT_CONTAINS_SWIFT_CODE: YES
|
|
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
|
groups: [app]
|
|
dependencies:
|
|
- framework: libapp.a
|
|
embed: false
|
|
- target: ShareExtension
|
|
embed: true
|
|
codeSign: true
|
|
- target: ReadestWidget
|
|
embed: true
|
|
codeSign: true
|
|
- sdk: CoreGraphics.framework
|
|
- sdk: Metal.framework
|
|
- sdk: MetalKit.framework
|
|
- sdk: QuartzCore.framework
|
|
- sdk: Security.framework
|
|
- sdk: UIKit.framework
|
|
- sdk: WebKit.framework
|
|
- sdk: WidgetKit.framework
|
|
preBuildScripts:
|
|
- script: pnpm tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}
|
|
name: Build Rust Code
|
|
basedOnDependencyAnalysis: false
|
|
outputFiles:
|
|
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
|
|
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
|
|
|
|
# Share-sheet extension that lets users send article URLs from Safari /
|
|
# Chrome / etc. directly to Readest. The extension grabs the URL via
|
|
# NSExtensionContext, encodes it into `readest://share?url=...`, and
|
|
# opens the main app — which catches the deep-link via
|
|
# `tauri-plugin-deep-link` and runs the clip-and-import pipeline.
|
|
ShareExtension:
|
|
type: app-extension
|
|
platform: iOS
|
|
# The Share Extension uses iOS-system-localized bar button items
|
|
# (`barButtonSystemItem: .cancel` / `.save`) plus a JS-supplied
|
|
# "Default" group name (passed through the App Group), so the target
|
|
# carries no per-locale `.strings` files — no `.lproj` directories
|
|
# to wire up.
|
|
sources:
|
|
- path: ShareExtension
|
|
info:
|
|
path: ShareExtension/Info.plist
|
|
properties:
|
|
CFBundleDisplayName: Readest
|
|
NSExtension:
|
|
NSExtensionPointIdentifier: com.apple.share-services
|
|
NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ShareViewController
|
|
NSExtensionAttributes:
|
|
NSExtensionActivationRule:
|
|
NSExtensionActivationSupportsWebURLWithMaxCount: 1
|
|
NSExtensionActivationSupportsText: true
|
|
# Entitlements referenced via CODE_SIGN_ENTITLEMENTS build setting
|
|
# rather than xcodegen's `entitlements:` block — otherwise xcodegen
|
|
# may overwrite the file (even with no properties declared) during
|
|
# regeneration, and Xcode rejects the build with
|
|
# "Entitlements file ... was modified during the build"
|
|
settings:
|
|
base:
|
|
PRODUCT_NAME: ShareExtension
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.bilingify.readest.ShareExtension
|
|
DEVELOPMENT_TEAM: J5W48D69VR
|
|
CODE_SIGN_ENTITLEMENTS: ShareExtension/ShareExtension.entitlements
|
|
# 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]
|
|
VALID_ARCHS: arm64
|
|
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
|
ENABLE_BITCODE: false
|
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: false
|
|
SKIP_INSTALL: true
|
|
|
|
# WidgetKit extension that surfaces the user's current reading progress
|
|
# on the iOS home screen / Today view. Reads from the App Group suite
|
|
# written by the main app's useReadingWidget hook (Task 7).
|
|
ReadestWidget:
|
|
type: app-extension
|
|
platform: iOS
|
|
sources:
|
|
- path: ReadestWidget
|
|
info:
|
|
path: ReadestWidget/Info.plist
|
|
properties:
|
|
CFBundleDisplayName: Readest
|
|
NSExtension:
|
|
NSExtensionPointIdentifier: com.apple.widgetkit-extension
|
|
settings:
|
|
base:
|
|
PRODUCT_NAME: ReadestWidget
|
|
PRODUCT_BUNDLE_IDENTIFIER: com.bilingify.readest.ReadestWidget
|
|
DEVELOPMENT_TEAM: J5W48D69VR
|
|
CODE_SIGN_ENTITLEMENTS: ReadestWidget/ReadestWidget.entitlements
|
|
# 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]
|
|
VALID_ARCHS: arm64
|
|
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
|
ENABLE_BITCODE: false
|
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: false
|
|
SKIP_INSTALL: true
|
|
dependencies:
|
|
- sdk: WidgetKit.framework
|