From b0dcd20dd7d31b04954f5fe39e44c1854015f27a Mon Sep 17 00:00:00 2001 From: "romain.gyh" <11901536+romaingyh@users.noreply.github.com> Date: Sun, 4 May 2025 19:54:25 +0200 Subject: [PATCH 1/6] feat(supabase_flutter): Adds support for SharedPreferencesAsync --- .../lib/src/local_storage.dart | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/supabase_flutter/lib/src/local_storage.dart b/packages/supabase_flutter/lib/src/local_storage.dart index d3622ea2..70f0de46 100644 --- a/packages/supabase_flutter/lib/src/local_storage.dart +++ b/packages/supabase_flutter/lib/src/local_storage.dart @@ -64,11 +64,19 @@ class EmptyLocalStorage extends LocalStorage { /// A [LocalStorage] implementation that implements SharedPreferences as the /// storage method. class SharedPreferencesLocalStorage extends LocalStorage { - late final SharedPreferences _prefs; + late final SharedPreferences _syncPrefs; + + late final SharedPreferencesAsync _asyncPrefs; - SharedPreferencesLocalStorage({required this.persistSessionKey}); + SharedPreferencesLocalStorage({ + required this.persistSessionKey, + this.useSharedPreferencesAsync = false, + }); final String persistSessionKey; + + final bool useSharedPreferencesAsync; + static const _useWebLocalStorage = kIsWeb && bool.fromEnvironment("dart.library.js_interop"); @@ -76,7 +84,12 @@ class SharedPreferencesLocalStorage extends LocalStorage { Future initialize() async { if (!_useWebLocalStorage) { WidgetsFlutterBinding.ensureInitialized(); - _prefs = await SharedPreferences.getInstance(); + + if (useSharedPreferencesAsync) { + _asyncPrefs = SharedPreferencesAsync(); + } else { + _syncPrefs = await SharedPreferences.getInstance(); + } } } @@ -85,7 +98,11 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.hasAccessToken(persistSessionKey); } - return _prefs.containsKey(persistSessionKey); + + return switch (useSharedPreferencesAsync) { + true => _asyncPrefs.containsKey(persistSessionKey), + false => Future.value(_syncPrefs.containsKey(persistSessionKey)), + }; } @override @@ -93,7 +110,11 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.accessToken(persistSessionKey); } - return _prefs.getString(persistSessionKey); + + return switch (useSharedPreferencesAsync) { + true => _asyncPrefs.getString(persistSessionKey), + false => Future.value(_syncPrefs.getString(persistSessionKey)), + }; } @override @@ -101,7 +122,12 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { web.removePersistedSession(persistSessionKey); } else { - await _prefs.remove(persistSessionKey); + switch (useSharedPreferencesAsync) { + case true: + await _asyncPrefs.remove(persistSessionKey); + case false: + await _syncPrefs.remove(persistSessionKey); + } } } @@ -110,7 +136,10 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.persistSession(persistSessionKey, persistSessionString); } - return _prefs.setString(persistSessionKey, persistSessionString); + return switch (useSharedPreferencesAsync) { + true => _asyncPrefs.setString(persistSessionKey, persistSessionString), + false => _syncPrefs.setString(persistSessionKey, persistSessionString), + }; } } From c729accdae80bacdac71534bc2c7a2b2d83ff6af Mon Sep 17 00:00:00 2001 From: Vinzent Date: Wed, 28 May 2025 16:07:06 +0200 Subject: [PATCH 2/6] chore: require min shared_preferences v2.3.0 --- packages/supabase_flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/supabase_flutter/pubspec.yaml b/packages/supabase_flutter/pubspec.yaml index 428d28f2..754de266 100644 --- a/packages/supabase_flutter/pubspec.yaml +++ b/packages/supabase_flutter/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: supabase: 2.7.0 url_launcher: ^6.1.2 path_provider: ^2.0.0 - shared_preferences: ^2.0.0 + shared_preferences: ^2.3.0 logging: ^1.2.0 web: '>=0.5.0 <2.0.0' From a50d74e3427a961421c74cf020f54c3a66cc2444 Mon Sep 17 00:00:00 2001 From: "romain.gyh" <11901536+romaingyh@users.noreply.github.com> Date: Wed, 28 May 2025 17:32:08 +0200 Subject: [PATCH 3/6] refactor: Split SharedPreferencesLocalStorage in two ditinct classes : SharedPreferencesLocalStorage & SharedPreferencesAsyncLocalStorage --- .../lib/src/local_storage.dart | 94 ++++++++++++------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/packages/supabase_flutter/lib/src/local_storage.dart b/packages/supabase_flutter/lib/src/local_storage.dart index 70f0de46..3068f4ea 100644 --- a/packages/supabase_flutter/lib/src/local_storage.dart +++ b/packages/supabase_flutter/lib/src/local_storage.dart @@ -64,19 +64,12 @@ class EmptyLocalStorage extends LocalStorage { /// A [LocalStorage] implementation that implements SharedPreferences as the /// storage method. class SharedPreferencesLocalStorage extends LocalStorage { - late final SharedPreferences _syncPrefs; - - late final SharedPreferencesAsync _asyncPrefs; + late final SharedPreferences _prefs; - SharedPreferencesLocalStorage({ - required this.persistSessionKey, - this.useSharedPreferencesAsync = false, - }); + SharedPreferencesLocalStorage({required this.persistSessionKey}); final String persistSessionKey; - final bool useSharedPreferencesAsync; - static const _useWebLocalStorage = kIsWeb && bool.fromEnvironment("dart.library.js_interop"); @@ -84,12 +77,7 @@ class SharedPreferencesLocalStorage extends LocalStorage { Future initialize() async { if (!_useWebLocalStorage) { WidgetsFlutterBinding.ensureInitialized(); - - if (useSharedPreferencesAsync) { - _asyncPrefs = SharedPreferencesAsync(); - } else { - _syncPrefs = await SharedPreferences.getInstance(); - } + _prefs = await SharedPreferences.getInstance(); } } @@ -98,11 +86,7 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.hasAccessToken(persistSessionKey); } - - return switch (useSharedPreferencesAsync) { - true => _asyncPrefs.containsKey(persistSessionKey), - false => Future.value(_syncPrefs.containsKey(persistSessionKey)), - }; + return _prefs.containsKey(persistSessionKey); } @override @@ -110,11 +94,61 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.accessToken(persistSessionKey); } + return _prefs.getString(persistSessionKey); + } + + @override + Future removePersistedSession() async { + if (_useWebLocalStorage) { + web.removePersistedSession(persistSessionKey); + } else { + await _prefs.remove(persistSessionKey); + } + } + + @override + Future persistSession(String persistSessionString) { + if (_useWebLocalStorage) { + return web.persistSession(persistSessionKey, persistSessionString); + } + return _prefs.setString(persistSessionKey, persistSessionString); + } +} + +/// A [LocalStorage] implementation that implements SharedPreferencesAsync as the +/// storage method. +class SharedPreferencesAsyncLocalStorage extends LocalStorage { + late final SharedPreferencesAsync _prefs; + + SharedPreferencesAsyncLocalStorage({required this.persistSessionKey}); - return switch (useSharedPreferencesAsync) { - true => _asyncPrefs.getString(persistSessionKey), - false => Future.value(_syncPrefs.getString(persistSessionKey)), - }; + final String persistSessionKey; + + static const _useWebLocalStorage = + kIsWeb && bool.fromEnvironment("dart.library.js_interop"); + + @override + Future initialize() async { + if (!_useWebLocalStorage) { + WidgetsFlutterBinding.ensureInitialized(); + _prefs = SharedPreferencesAsync(); + } + } + + @override + Future hasAccessToken() async { + if (_useWebLocalStorage) { + return web.hasAccessToken(persistSessionKey); + } + return _prefs.containsKey(persistSessionKey); + } + + @override + Future accessToken() async { + if (_useWebLocalStorage) { + return web.accessToken(persistSessionKey); + } + return _prefs.getString(persistSessionKey); } @override @@ -122,12 +156,7 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { web.removePersistedSession(persistSessionKey); } else { - switch (useSharedPreferencesAsync) { - case true: - await _asyncPrefs.remove(persistSessionKey); - case false: - await _syncPrefs.remove(persistSessionKey); - } + await _prefs.remove(persistSessionKey); } } @@ -136,10 +165,7 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (_useWebLocalStorage) { return web.persistSession(persistSessionKey, persistSessionString); } - return switch (useSharedPreferencesAsync) { - true => _asyncPrefs.setString(persistSessionKey, persistSessionString), - false => _syncPrefs.setString(persistSessionKey, persistSessionString), - }; + return _prefs.setString(persistSessionKey, persistSessionString); } } From d17deb8e0047d14f562347f77b703dcb4b6dd3d7 Mon Sep 17 00:00:00 2001 From: "romain.gyh" <11901536+romaingyh@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:04:33 +0200 Subject: [PATCH 4/6] chore: update min dart and flutter version to 3.4.0 & 3.22.0 --- packages/supabase_flutter/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/supabase_flutter/pubspec.yaml b/packages/supabase_flutter/pubspec.yaml index 754de266..bb7ef9b2 100644 --- a/packages/supabase_flutter/pubspec.yaml +++ b/packages/supabase_flutter/pubspec.yaml @@ -6,8 +6,8 @@ repository: 'https://github.com/supabase/supabase-flutter/tree/main/packages/sup documentation: 'https://supabase.com/docs/reference/dart/introduction' environment: - sdk: '>=3.3.0 <4.0.0' - flutter: '>=3.19.0' + sdk: '>=3.4.0 <4.0.0' + flutter: '>=3.22.0' dependencies: app_links: '>=3.5.0 <7.0.0' From 44719d055422b93e198299f559fd497ecb570599 Mon Sep 17 00:00:00 2001 From: "romain.gyh" <11901536+romaingyh@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:14:00 +0200 Subject: [PATCH 5/6] feat: Replace SharedPreferences with SharedPreferencesAsync --- .../lib/src/local_storage.dart | 58 +------------------ 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/packages/supabase_flutter/lib/src/local_storage.dart b/packages/supabase_flutter/lib/src/local_storage.dart index 3068f4ea..43f94f59 100644 --- a/packages/supabase_flutter/lib/src/local_storage.dart +++ b/packages/supabase_flutter/lib/src/local_storage.dart @@ -61,66 +61,12 @@ class EmptyLocalStorage extends LocalStorage { Future persistSession(persistSessionString) async {} } -/// A [LocalStorage] implementation that implements SharedPreferences as the -/// storage method. -class SharedPreferencesLocalStorage extends LocalStorage { - late final SharedPreferences _prefs; - - SharedPreferencesLocalStorage({required this.persistSessionKey}); - - final String persistSessionKey; - - static const _useWebLocalStorage = - kIsWeb && bool.fromEnvironment("dart.library.js_interop"); - - @override - Future initialize() async { - if (!_useWebLocalStorage) { - WidgetsFlutterBinding.ensureInitialized(); - _prefs = await SharedPreferences.getInstance(); - } - } - - @override - Future hasAccessToken() async { - if (_useWebLocalStorage) { - return web.hasAccessToken(persistSessionKey); - } - return _prefs.containsKey(persistSessionKey); - } - - @override - Future accessToken() async { - if (_useWebLocalStorage) { - return web.accessToken(persistSessionKey); - } - return _prefs.getString(persistSessionKey); - } - - @override - Future removePersistedSession() async { - if (_useWebLocalStorage) { - web.removePersistedSession(persistSessionKey); - } else { - await _prefs.remove(persistSessionKey); - } - } - - @override - Future persistSession(String persistSessionString) { - if (_useWebLocalStorage) { - return web.persistSession(persistSessionKey, persistSessionString); - } - return _prefs.setString(persistSessionKey, persistSessionString); - } -} - /// A [LocalStorage] implementation that implements SharedPreferencesAsync as the /// storage method. -class SharedPreferencesAsyncLocalStorage extends LocalStorage { +class SharedPreferencesLocalStorage extends LocalStorage { late final SharedPreferencesAsync _prefs; - SharedPreferencesAsyncLocalStorage({required this.persistSessionKey}); + SharedPreferencesLocalStorage({required this.persistSessionKey}); final String persistSessionKey; From ccbd41fc0f512d13081701be47958dde6d4412ff Mon Sep 17 00:00:00 2001 From: "romain.gyh" <11901536+romaingyh@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:16:12 +0200 Subject: [PATCH 6/6] feat: Implement access token migration from legacy SharedPreferences to new SharedPreferencesAsync --- .../supabase_flutter/lib/src/local_storage.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/supabase_flutter/lib/src/local_storage.dart b/packages/supabase_flutter/lib/src/local_storage.dart index 43f94f59..63b0ece0 100644 --- a/packages/supabase_flutter/lib/src/local_storage.dart +++ b/packages/supabase_flutter/lib/src/local_storage.dart @@ -78,6 +78,21 @@ class SharedPreferencesLocalStorage extends LocalStorage { if (!_useWebLocalStorage) { WidgetsFlutterBinding.ensureInitialized(); _prefs = SharedPreferencesAsync(); + + await _maybeMigrateAccessToken(); + } + } + + Future _maybeMigrateAccessToken() async { + final legacyPrefs = await SharedPreferences.getInstance(); + + if (legacyPrefs.containsKey(persistSessionKey)) { + final accessToken = legacyPrefs.getString(persistSessionKey); + + if (accessToken != null) { + await legacyPrefs.remove(persistSessionKey); + await _prefs.setString(persistSessionKey, accessToken); + } } }