Skip to content

Commit

Permalink
[shared_preferences] Fixes get-all when suite name is used (#7335)
Browse files Browse the repository at this point in the history
In shared_preferences_foundation, fixes getting all preferences when suite name is used. Bug was reading only the standard user defaults. The fix uses suite name when available.

Issues fixed by this PR:
- flutter/flutter#153042
  • Loading branch information
fertrig authored Aug 12, 2024
1 parent 970ba7a commit c0109e2
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.5.2

* Fixes getting all preferences when suite name is used.

## 2.5.1

* Fixes `getStringList` returning immutable list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class RunnerTests: XCTestCase {
// Async system tests.

let emptyOptions = SharedPreferencesPigeonOptions()
let optionsWithSuiteName = SharedPreferencesPigeonOptions(
suiteName: "group.example.sharedPreferencesFoundationExample")

func testAsyncSetAndGet() throws {
let plugin = SharedPreferencesPlugin()
Expand Down Expand Up @@ -154,6 +156,19 @@ class RunnerTests: XCTestCase {

}

func testAsyncGetAllWithAndWithoutSuiteName() throws {
let plugin = SharedPreferencesPlugin()

try plugin.set(key: "aKey", value: "hello world", options: emptyOptions)
try plugin.set(key: "aKeySuite", value: "hello world with suite", options: optionsWithSuiteName)

let storedValues = try plugin.getAll(allowList: nil, options: emptyOptions)
XCTAssertEqual(storedValues["aKey"] as? String, "hello world")

let storedValuesWithGroup = try plugin.getAll(allowList: nil, options: optionsWithSuiteName)
XCTAssertEqual(storedValuesWithGroup["aKeySuite"] as? String, "hello world with suite")
}

func testAsyncGetAllWithAllowList() throws {
let plugin = SharedPreferencesPlugin()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,13 @@ public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
var filteredPrefs: [String: Any] = [:]
var compatiblePrefs: [String: Any] = [:]
let allowSet = allowList.map { Set($0) }
if let appDomain = Bundle.main.bundleIdentifier,

// Since `getUserDefaults` is initialized with the suite name, it seems redundant to call
// `persistentDomain` with the suite name again. However, it is necessary because
// `dictionaryRepresentation` returns keys from the global domain.
// Also, Apple's docs on `persistentDomain` are incorrect,
// see: https://github.com/feedback-assistant/reports/issues/165
if let appDomain = options.suiteName ?? Bundle.main.bundleIdentifier,
let prefs = try getUserDefaults(options: options).persistentDomain(forName: appDomain)
{
if let allowSet = allowSet {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ void main() {
group('shared_preferences_async', () {
final SharedPreferencesAsyncFoundationOptions emptyOptions =
SharedPreferencesAsyncFoundationOptions();
final SharedPreferencesAsyncFoundationOptions optionsWithSuiteName =
SharedPreferencesAsyncFoundationOptions(
suiteName: 'group.example.sharedPreferencesFoundation');

const String stringKey = 'testString';
const String boolKey = 'testBool';
Expand All @@ -506,6 +509,9 @@ void main() {
await preferences.clear(
const ClearPreferencesParameters(filter: PreferencesFilters()),
emptyOptions);
await preferences.clear(
const ClearPreferencesParameters(filter: PreferencesFilters()),
optionsWithSuiteName);
return preferences;
}

Expand Down Expand Up @@ -577,6 +583,39 @@ void main() {
expect(gotAll[listKey], testList);
});

testWidgets('getPreferences with options', (WidgetTester _) async {
final SharedPreferencesAsyncPlatform preferences = await getPreferences();
await Future.wait(<Future<void>>[
preferences.setString(stringKey, testString, optionsWithSuiteName),
preferences.setBool(boolKey, testBool, emptyOptions),
preferences.setInt(intKey, testInt, optionsWithSuiteName),
preferences.setDouble(doubleKey, testDouble, emptyOptions),
preferences.setStringList(listKey, testList, optionsWithSuiteName)
]);

final Map<String, Object?> preferencesWithEmptyOptions =
await preferences.getPreferences(
const GetPreferencesParameters(filter: PreferencesFilters()),
emptyOptions,
);

final Map<String, Object?> preferencesWithSuiteName =
await preferences.getPreferences(
const GetPreferencesParameters(filter: PreferencesFilters()),
optionsWithSuiteName,
);

expect(preferencesWithEmptyOptions.length, 2);
expect(preferencesWithSuiteName.length, 3);

expect(preferencesWithEmptyOptions[boolKey], testBool);
expect(preferencesWithEmptyOptions[doubleKey], testDouble);

expect(preferencesWithSuiteName[stringKey], testString);
expect(preferencesWithSuiteName[intKey], testInt);
expect(preferencesWithSuiteName[listKey], testList);
});

testWidgets('getPreferences with filter', (WidgetTester _) async {
final SharedPreferencesAsyncPlatform preferences = await getPreferences();
await Future.wait(<Future<void>>[
Expand Down Expand Up @@ -622,6 +661,37 @@ void main() {
expect(keys, contains(listKey));
});

testWidgets('getKeys with options', (WidgetTester _) async {
final SharedPreferencesAsyncPlatform preferences = await getPreferences();
await Future.wait(<Future<void>>[
preferences.setString(stringKey, testString, optionsWithSuiteName),
preferences.setBool(boolKey, testBool, emptyOptions),
preferences.setInt(intKey, testInt, optionsWithSuiteName),
preferences.setDouble(doubleKey, testDouble, emptyOptions),
preferences.setStringList(listKey, testList, optionsWithSuiteName)
]);

final Set<String> keysWithEmptyOptions = await preferences.getKeys(
const GetPreferencesParameters(filter: PreferencesFilters()),
emptyOptions,
);

final Set<String> keysWithSuiteName = await preferences.getKeys(
const GetPreferencesParameters(filter: PreferencesFilters()),
optionsWithSuiteName,
);

expect(keysWithEmptyOptions.length, 2);
expect(keysWithSuiteName.length, 3);

expect(keysWithEmptyOptions, contains(boolKey));
expect(keysWithEmptyOptions, contains(doubleKey));

expect(keysWithSuiteName, contains(stringKey));
expect(keysWithSuiteName, contains(intKey));
expect(keysWithSuiteName, contains(listKey));
});

testWidgets('getKeys with filter', (WidgetTester _) async {
final SharedPreferencesAsyncPlatform preferences = await getPreferences();
await Future.wait(<Future<void>>[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: shared_preferences_foundation
description: iOS and macOS implementation of the shared_preferences plugin.
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.5.1
version: 2.5.2

environment:
sdk: ^3.3.0
Expand Down

0 comments on commit c0109e2

Please sign in to comment.