Files
readest/apps/readest-app/src-tauri/gen/apple/project.yml
T
Huang Xin 7da41a65ad feat(widget): add mobile home-screen reading widgets (#1602) (#4842)
Add a resizable home-screen widget on iOS and Android showing recent
in-progress books with cover, reading progress, and tap-to-open.

- One responsive widget: Android resizable 1x1 to 4x3 (one book per
  column, up to 3); iOS Small/Medium/Large families. Covers are cropped,
  rounded, with a percent badge and a progress bar (baked into the bitmap
  on Android, SwiftUI overlays on iOS).
- TTS controls (previous, play-pause, next) appear in 2+ row sizes when
  TTS is active, wired to the existing media session. Reading progress
  stays live during background TTS via a fraction computed from the baked
  offline locations.
- Publishes a snapshot plus downsized cover thumbnails to the iOS App
  Group and Android SharedPreferences through a new update_reading_widget
  native-bridge command; refresh is debounced and driven by library and
  progress changes, TTS, and app backgrounding.
- Tapping a cover opens readest://book/{hash}, switching the reader in
  place when one is already open.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:03:16 +02:00

206 lines
8.7 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
# 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
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: YES
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