fix: retry path_provider on PlatformException at database open (#153, #157)

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 <noreply@anthropic.com>
This commit is contained in:
Thomas SharedInbox
2026-05-23 10:08:04 +02:00
co-authored by Claude Sonnet 4.6
parent 1a7b585dd4
commit 8a4ca223e9
+24 -7
View File
@@ -591,15 +591,32 @@ Future<void> 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<String> _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<void>.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) {