Files
readest/apps/readest-app/src-tauri/gen/apple/project.yml
T
Huang Xin 1d3dfd395f fix(ios): stop share extension hijacking shared .txt files (#4917)
The iOS share extension is a web-article URL clipper, but its activation
rule enabled NSExtensionActivationSupportsText. A .txt file is
public.plain-text (conforms to public.text), so that key made the
URL-only extension activate for plain-text files it cannot handle: the
share sheet hung instead of the file taking the main app's
CFBundleDocumentTypes "Copy to Readest" import path, which handles txt
fine (like EPUB and PDF, which never matched the extension).

Drop NSExtensionActivationSupportsText so the extension activates only
for web URLs. Shared .txt files now route to the working document-open
import path; sharing a web page URL from Safari or Chrome still works.

Add a regression guard asserting project.yml (the xcodegen source of
truth for the generated, skip-worktree Info.plist) never re-enables text
activation.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 04:05:15 +02:00

220 lines
9.5 KiB
YAML

name: Readest
options:
bundleIdPrefix: com.bilingify.readest
deploymentTarget:
iOS: 15.0
fileGroups: [../../src]
packages:
Sentry:
url: https://github.com/getsentry/sentry-cocoa
from: 8.0.0
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: SentrySupport
- 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:
- package: Sentry
product: Sentry
- 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:
# Web URLs only. Do NOT add NSExtensionActivationSupportsText: a
# .txt file is public.plain-text (conforms to public.text), so that
# key makes this article-URL clipper activate for plain-text FILES
# it can't handle (the share sheet hangs). Book files must fall
# through to the main app's CFBundleDocumentTypes import path.
NSExtensionActivationRule:
NSExtensionActivationSupportsWebURLWithMaxCount: 1
# 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