Skip to content

Commit 3bbbbc7

Browse files
committed
feat(async-storage): legacy storage for android, example updated
1 parent de581ac commit 3bbbbc7

File tree

13 files changed

+680
-50
lines changed

13 files changed

+680
-50
lines changed

examples/example-react-native/App.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,55 @@
1-
/**
2-
* Sample React Native App
3-
* https://github.com/facebook/react-native
4-
*
5-
* @format
6-
*/
7-
8-
import React from "react";
9-
import { StatusBar, useColorScheme, View } from "react-native";
10-
import GetSetClear from "./src/BasicCrud";
1+
import React, { useState } from "react";
2+
import {
3+
Button,
4+
SafeAreaView,
5+
StatusBar,
6+
useColorScheme,
7+
View,
8+
} from "react-native";
9+
import BasicCrud from "./src/BasicCrud";
10+
import LegacyBasicCrud from "./src/LegacyBasicCrud";
1111

1212
function App(): React.JSX.Element {
1313
const isDarkMode = useColorScheme() === "dark";
14+
const [example, setExample] = useState<"basic" | "legacy-basic">("basic");
1415

1516
return (
16-
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
17-
<StatusBar barStyle={isDarkMode ? "light-content" : "dark-content"} />
18-
<GetSetClear />
19-
</View>
17+
<SafeAreaView style={{ flex: 1, paddingTop: 60 }}>
18+
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
19+
<StatusBar barStyle={isDarkMode ? "light-content" : "dark-content"} />
20+
21+
<View
22+
style={{
23+
maxHeight: 60,
24+
alignItems: "center",
25+
flexDirection: "row",
26+
gap: 4,
27+
}}
28+
>
29+
<Button
30+
disabled={example === "basic"}
31+
title="Basic"
32+
onPress={() => setExample("basic")}
33+
/>
34+
<Button
35+
disabled={example === "legacy-basic"}
36+
title="LegacyBasic"
37+
onPress={() => setExample("legacy-basic")}
38+
/>
39+
</View>
40+
41+
<View style={{ flex: 1 }}>
42+
{(() => {
43+
switch (example) {
44+
case "basic":
45+
return <BasicCrud />;
46+
case "legacy-basic":
47+
return <LegacyBasicCrud />;
48+
}
49+
})()}
50+
</View>
51+
</View>
52+
</SafeAreaView>
2053
);
2154
}
2255

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* eslint-disable */
2+
/**
3+
* Copyright (c) Facebook, Inc. and its affiliates.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import AsyncStorage from "@react-native-async-storage/async-storage";
10+
import React, { useState } from "react";
11+
import { Alert, Button, StyleSheet, Text, View } from "react-native";
12+
13+
export const STORAGE_KEY = "legacy-random";
14+
15+
const LegacyBasicCrud: React.FC = () => {
16+
const [storedNumber, setStoredNumber] = React.useState<number | null>(null);
17+
const [storage] = useState(() => AsyncStorage);
18+
19+
function reportError(e: any) {
20+
Alert.alert(e?.name ?? "Error", JSON.stringify(e, null, 2));
21+
}
22+
23+
async function readCurrent() {
24+
try {
25+
const value = await storage.getItem(STORAGE_KEY);
26+
setStoredNumber(value ? Number(value) : null);
27+
} catch (e: any) {
28+
reportError(e);
29+
}
30+
}
31+
32+
const increaseByTen = async () => {
33+
const newNumber = (storedNumber ?? 0) + 10;
34+
35+
try {
36+
await storage.setItem(STORAGE_KEY, `${newNumber}`);
37+
setStoredNumber(newNumber);
38+
await readCurrent();
39+
} catch (e) {
40+
reportError(e);
41+
}
42+
};
43+
44+
const removeItem = async () => {
45+
await storage.removeItem(STORAGE_KEY).catch(reportError);
46+
await readCurrent();
47+
};
48+
49+
const listAllKeys = async () => {
50+
try {
51+
const keys = await storage.getAllKeys();
52+
Alert.alert("keys", keys.join(", "));
53+
} catch (e) {
54+
reportError(e);
55+
}
56+
};
57+
58+
React.useEffect(() => {
59+
readCurrent();
60+
}, [storage]);
61+
62+
return (
63+
<View>
64+
<Text style={styles.text}>Currently stored: </Text>
65+
<Text style={styles.text}>{storedNumber}</Text>
66+
<Button title="Increase by 10" onPress={increaseByTen} />
67+
<Button title="remove item" onPress={removeItem} />
68+
<Button title="list all keys" onPress={listAllKeys} />
69+
</View>
70+
);
71+
};
72+
73+
const styles = StyleSheet.create({
74+
text: {
75+
color: "#000000",
76+
fontSize: 20,
77+
textAlign: "center",
78+
margin: 10,
79+
},
80+
});
81+
82+
export default LegacyBasicCrud;

packages/async-storage/android/build.gradle

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,21 @@ buildscript {
1111
dependencies {
1212
classpath "com.android.tools.build:gradle:8.7.2"
1313
// noinspection DifferentKotlinGradleVersion
14-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
14+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('KOTLIN_VERSION')}"
15+
classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:${getExtOrDefault('KSP_VERSION')}"
1516
}
1617
}
1718

1819

1920
apply plugin: "com.android.library"
2021
apply plugin: "kotlin-android"
21-
2222
apply plugin: "com.facebook.react"
2323

24-
def getExtOrIntegerDefault(name) {
25-
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["AsyncStorage_" + name]).toInteger()
24+
// to support migration from old storage
25+
apply plugin: 'com.google.devtools.ksp'
26+
27+
def getExtOrDefault(name) {
28+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["AsyncStorage_" + name])
2629
}
2730

2831
def isNewArchitectureEnabled() {
@@ -32,11 +35,11 @@ def isNewArchitectureEnabled() {
3235
android {
3336
namespace "org.asyncstorage"
3437

35-
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
38+
compileSdkVersion getExtOrDefault("compileSdkVersion").toInteger()
3639

3740
defaultConfig {
38-
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
39-
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
41+
minSdkVersion getExtOrDefault("minSdkVersion").toInteger()
42+
targetSdkVersion getExtOrDefault("targetSdkVersion").toInteger()
4043
}
4144

4245
buildFeatures {
@@ -101,4 +104,11 @@ repositories {
101104
dependencies {
102105
implementation "com.facebook.react:react-android"
103106
implementation "org.asyncstorage.shared_storage:storage-android:1.0.0"
107+
108+
109+
def room_version = getExtOrDefault("ROOM_VERSION")
110+
111+
implementation "androidx.room:room-runtime:$room_version"
112+
implementation "androidx.room:room-ktx:$room_version"
113+
ksp "androidx.room:room-compiler:$room_version"
104114
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
AsyncStorage_kotlinVersion=2.2.10
1+
AsyncStorage_KOTLIN_VERSION=2.2.10
2+
AsyncStorage_KSP_VERSION=2.2.10-2.0.2
3+
AsyncStorage_ROOM_VERSION=2.7.2
24
AsyncStorage_minSdkVersion=24
35
AsyncStorage_targetSdkVersion=36
4-
AsyncStorage_compileSdkVersion=36
6+
AsyncStorage_compileSdkVersion=36
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.asyncstorage.legacy_storage
2+
3+
import android.content.Context
4+
import com.facebook.react.bridge.Arguments
5+
import com.facebook.react.bridge.Promise
6+
import com.facebook.react.bridge.ReactApplicationContext
7+
import com.facebook.react.bridge.ReadableArray
8+
import kotlinx.coroutines.CoroutineExceptionHandler
9+
import kotlinx.coroutines.CoroutineName
10+
import kotlinx.coroutines.CoroutineScope
11+
import kotlinx.coroutines.Dispatchers
12+
import kotlinx.coroutines.SupervisorJob
13+
import kotlinx.coroutines.launch
14+
15+
class LegacyStorageModule(reactContext: ReactApplicationContext) : CoroutineScope {
16+
17+
override val coroutineContext =
18+
Dispatchers.IO + CoroutineName("AsyncStorageScope") + SupervisorJob()
19+
20+
private val storage = StorageSupplier.getInstance(reactContext)
21+
22+
companion object {
23+
@JvmStatic
24+
fun getStorageInstance(ctx: Context): AsyncStorageAccess {
25+
return StorageSupplier.getInstance(ctx)
26+
}
27+
}
28+
29+
fun multiGet(keys: ReadableArray, promise: Promise) {
30+
launch(createExceptionHandler(promise)) {
31+
val entries = storage.getValues(keys.toKeyList())
32+
promise.resolve(entries.toKeyValueArgument())
33+
}
34+
}
35+
36+
fun multiSet(keyValueArray: ReadableArray, promise: Promise) {
37+
launch(createExceptionHandler(promise)) {
38+
val entries = keyValueArray.toEntryList()
39+
storage.setValues(entries)
40+
promise.resolve(null)
41+
}
42+
}
43+
44+
fun multiRemove(keys: ReadableArray, promise: Promise) {
45+
launch(createExceptionHandler(promise)) {
46+
storage.removeValues(keys.toKeyList())
47+
promise.resolve(null)
48+
}
49+
}
50+
51+
fun multiMerge(keyValueArray: ReadableArray, promise: Promise) {
52+
launch(createExceptionHandler(promise)) {
53+
val entries = keyValueArray.toEntryList()
54+
storage.mergeValues(entries)
55+
promise.resolve(null)
56+
}
57+
}
58+
59+
fun getAllKeys(promise: Promise) {
60+
launch(createExceptionHandler(promise)) {
61+
val keys = storage.getKeys()
62+
val result = Arguments.createArray()
63+
keys.forEach { result.pushString(it) }
64+
promise.resolve(result)
65+
}
66+
}
67+
68+
fun clear(promise: Promise) {
69+
launch(createExceptionHandler(promise)) {
70+
storage.clear()
71+
promise.resolve(null)
72+
}
73+
}
74+
}
75+
76+
internal fun createExceptionHandler(promise: Promise): CoroutineExceptionHandler {
77+
return CoroutineExceptionHandler { _, throwable ->
78+
val error = Arguments.createMap()
79+
error.putString("type", "LegacyStorageException")
80+
error.putString(
81+
"message",
82+
throwable.message
83+
?: throwable.localizedMessage
84+
?: "Unknown LegacyAsyncStorage error: $throwable",
85+
)
86+
87+
promise.reject(code = "AsyncStorageError", throwable, userInfo = error)
88+
}
89+
}

0 commit comments

Comments
 (0)