From 2babfce6dc976bd46f321f2057dc5fc8063cc4e4 Mon Sep 17 00:00:00 2001 From: Daniel Freiling Date: Thu, 27 Aug 2026 23:39:06 +0200 Subject: [PATCH 1/2] chore(ios): migrate example app to UIScene lifecycle UIScene lifecycle is required on iOS 27 and later; flutter_tools hard-fails to launch an unmigrated app there. Ran Flutter's own UIScene migrator, which adds UIApplicationSceneManifest to Info.plist and moves plugin registration from didFinishLaunchingWithOptions to didInitializeImplicitFlutterEngine. Uses FlutterSceneDelegate directly rather than adding an empty SceneDelegate subclass, matching the migrator's output. Co-Authored-By: Claude Opus 5 --- .../example/ios/Runner/AppDelegate.swift | 11 ++++-- flutter_readium/example/ios/Runner/Info.plist | 39 ++++++++++++++----- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/flutter_readium/example/ios/Runner/AppDelegate.swift b/flutter_readium/example/ios/Runner/AppDelegate.swift index 00ab16b9e..a6aa0f203 100644 --- a/flutter_readium/example/ios/Runner/AppDelegate.swift +++ b/flutter_readium/example/ios/Runner/AppDelegate.swift @@ -3,18 +3,21 @@ import UIKit import flutter_readium @main -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } - + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } + @objc func onCustomEditingAction() { debugPrint("AppDelegate.onCustomEditingAction") // TODO: Test if this works, it should trigger a custom action response. flutter_readium.FlutterReadiumPlugin.instance?.currentReaderView?.onCustomEditingAction() } -} +} \ No newline at end of file diff --git a/flutter_readium/example/ios/Runner/Info.plist b/flutter_readium/example/ios/Runner/Info.plist index a881aba78..457518397 100644 --- a/flutter_readium/example/ios/Runner/Info.plist +++ b/flutter_readium/example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,34 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + FlutterSceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,14 +71,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - From 9354c0abf5e0f66a7d8f3da15e44943f9d43f38e Mon Sep 17 00:00:00 2001 From: Daniel Freiling Date: Thu, 27 Aug 2026 23:39:13 +0200 Subject: [PATCH 2/2] feat(example): hint at missing fixtures on empty bookshelf Test fixtures are generated and gitignored, so a fresh checkout shows a blank shelf with no explanation. Point at bin/fetch_test_resources instead. Co-Authored-By: Claude Opus 5 --- .../example/lib/pages/bookshelf.page.dart | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/flutter_readium/example/lib/pages/bookshelf.page.dart b/flutter_readium/example/lib/pages/bookshelf.page.dart index dfd387c8e..37d12faee 100644 --- a/flutter_readium/example/lib/pages/bookshelf.page.dart +++ b/flutter_readium/example/lib/pages/bookshelf.page.dart @@ -151,6 +151,8 @@ class BookshelfPageState extends State { body: SafeArea( child: _isLoading ? Center(child: CircularProgressIndicator()) + : _testPublications.isEmpty + ? _buildEmptyState(context) : Column( children: [ Expanded( @@ -180,6 +182,36 @@ class BookshelfPageState extends State { ), ); + /// Test fixtures are generated and gitignored, so an empty shelf almost always + /// means `bin/fetch_test_resources` has not been run in this checkout. + Widget _buildEmptyState(final BuildContext context) => Center( + key: const ValueKey('bookshelf_empty_state'), + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.library_books_outlined, + size: 64, + color: Theme.of(context).colorScheme.outline, + ), + const SizedBox(height: 16), + Text('No publications found', style: Theme.of(context).textTheme.titleMedium), + const SizedBox(height: 8), + Text( + 'Test fixtures are generated, not committed. Run bin/fetch_test_resources ' + 'from the repo root, then restart the app.', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ); + // ignore: unused_element void _toast( final String text, {