From 8a4ca223e98cd846ba1e81652eca1735cd5d0dc2 Mon Sep 17 00:00:00 2001 From: Thomas SharedInbox Date: Sat, 23 May 2026 10:08:04 +0200 Subject: [PATCH] fix: retry path_provider on PlatformException at database open (#153, #157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Android versions the path_provider Pigeon channel ('dev.flutter.pigeon.path_provider_android.PathProviderApi.getApplicationSupportPath') is not ready when initDatabasePath() runs before runApp(). The existing code already catches PlatformException there, leaving _dbPath null — but the LazyDatabase callback called getApplicationSupportDirectory() a second time without any protection, causing an unhandled crash on those devices. Fix: extract _resolveDatabasePath() which retries three times with back-off (100 ms → 300 ms → 600 ms) before re-throwing with a descriptive error message. By the time the database is first accessed (after runApp()), the channel is almost always available; if it still isn't, the CrashScreen is shown with a clear explanation. Co-Authored-By: Claude Sonnet 4.6 --- lib/data/db/database.dart | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index 47a5924..e9abf31 100644 --- a/lib/data/db/database.dart +++ b/lib/data/db/database.dart @@ -591,15 +591,32 @@ Future initDatabasePath() async { } } +/// Resolve the application support path, retrying on PlatformException to +/// survive a race where the path_provider Pigeon channel isn't ready yet. +Future _resolveDatabasePath() async { + if (_dbPath != null) return _dbPath!; + // initDatabasePath() failed (channel not ready before runApp). Retry now + // that the engine is fully initialised, with brief back-off. + const delays = [100, 300, 600]; + for (final ms in delays) { + try { + final dir = await getApplicationSupportDirectory(); + _dbPath = p.join(dir.path, 'sharedinbox.db'); + return _dbPath!; + } on PlatformException { + await Future.delayed(Duration(milliseconds: ms)); + } + } + throw PlatformException( + code: 'channel-error', + message: 'path_provider unavailable after ${delays.length + 1} attempts — ' + 'cannot open database.', + ); +} + LazyDatabase _openConnection() { return LazyDatabase(() async { - final file = File( - _dbPath ?? - p.join( - (await getApplicationSupportDirectory()).path, - 'sharedinbox.db', - ), - ); + final file = File(await _resolveDatabasePath()); return NativeDatabase.createInBackground( file, setup: (db) {