Skip to content

Commit 9941b44

Browse files
tarrinnealFMorschel
authored andcommitted
[shared_preferences] update List<String> encode/decode (flutter#8335)
Follow up to flutter#8187 Updates Android `List<String>` encoding/decoding to use JSON to avoid potential future breakages from restricted list types.
1 parent 52932db commit 9941b44

File tree

18 files changed

+894
-303
lines changed

18 files changed

+894
-303
lines changed

packages/shared_preferences/shared_preferences_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.4.3
2+
3+
* Migrates `List<String>` value encoding to JSON.
4+
15
## 2.4.2
26

37
* Bumps gradle-plugin to 2.1.0.

packages/shared_preferences/shared_preferences_android/android/src/main/java/io/flutter/plugins/sharedpreferences/LegacySharedPreferencesPlugin.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,22 @@
2525
import java.util.HashSet;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.Objects;
2829
import java.util.Set;
2930

3031
/** LegacySharedPreferencesPlugin */
3132
public class LegacySharedPreferencesPlugin implements FlutterPlugin, SharedPreferencesApi {
3233
private static final String TAG = "SharedPreferencesPlugin";
3334
private static final String SHARED_PREFERENCES_NAME = "FlutterSharedPreferences";
35+
// All identifiers must match the SharedPreferencesPlugin.kt file, as well as the strings.dart file.
3436
private static final String LIST_IDENTIFIER = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBhIGxpc3Qu";
37+
// The symbol `!` was chosen as it cannot be created by the base 64 encoding used with LIST_IDENTIFIER.
38+
private static final String JSON_LIST_IDENTIFIER = LIST_IDENTIFIER + "!";
3539
private static final String BIG_INTEGER_PREFIX = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBCaWdJbnRlZ2Vy";
3640
private static final String DOUBLE_PREFIX = "VGhpcyBpcyB0aGUgcHJlZml4IGZvciBEb3VibGUu";
3741

3842
private SharedPreferences preferences;
39-
private SharedPreferencesListEncoder listEncoder;
43+
private final SharedPreferencesListEncoder listEncoder;
4044

4145
public LegacySharedPreferencesPlugin() {
4246
this(new ListEncoder());
@@ -100,7 +104,15 @@ public void onDetachedFromEngine(@NonNull FlutterPlugin.FlutterPluginBinding bin
100104
}
101105

102106
@Override
103-
public @NonNull Boolean setStringList(@NonNull String key, @NonNull List<String> value)
107+
public @NonNull Boolean setEncodedStringList(@NonNull String key, @NonNull String value)
108+
throws RuntimeException {
109+
return preferences.edit().putString(key, value).commit();
110+
}
111+
112+
// Deprecated, for testing purposes only.
113+
@Deprecated
114+
@Override
115+
public @NonNull Boolean setDeprecatedStringList(@NonNull String key, @NonNull List<String> value)
104116
throws RuntimeException {
105117
return preferences.edit().putString(key, LIST_IDENTIFIER + listEncoder.encode(value)).commit();
106118
}
@@ -131,14 +143,13 @@ public void onDetachedFromEngine(@NonNull FlutterPlugin.FlutterPluginBinding bin
131143

132144
// Gets all shared preferences, filtered to only those set with the given prefix.
133145
// Optionally filtered also to only those items in the optional [allowList].
134-
@SuppressWarnings("unchecked")
135146
private @NonNull Map<String, Object> getAllPrefs(
136147
@NonNull String prefix, @Nullable Set<String> allowList) throws RuntimeException {
137148
Map<String, ?> allPrefs = preferences.getAll();
138149
Map<String, Object> filteredPrefs = new HashMap<>();
139150
for (String key : allPrefs.keySet()) {
140151
if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
141-
filteredPrefs.put(key, transformPref(key, allPrefs.get(key)));
152+
filteredPrefs.put(key, transformPref(key, Objects.requireNonNull(allPrefs.get(key))));
142153
}
143154
}
144155

@@ -149,7 +160,13 @@ private Object transformPref(@NonNull String key, @NonNull Object value) {
149160
if (value instanceof String) {
150161
String stringValue = (String) value;
151162
if (stringValue.startsWith(LIST_IDENTIFIER)) {
152-
return listEncoder.decode(stringValue.substring(LIST_IDENTIFIER.length()));
163+
// The JSON-encoded lists use an extended prefix to distinguish them from
164+
// lists that are encoded on the platform.
165+
if (stringValue.startsWith(JSON_LIST_IDENTIFIER)) {
166+
return value;
167+
} else {
168+
return listEncoder.decode(stringValue.substring(LIST_IDENTIFIER.length()));
169+
}
153170
} else if (stringValue.startsWith(BIG_INTEGER_PREFIX)) {
154171
// TODO (tarrinneal): Remove all BigInt code.
155172
// https://github.com/flutter/flutter/issues/124420

0 commit comments

Comments
 (0)