@fto-consult/expo-ui 6.37.3 → 6.37.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/.package-lock.json +26218 -26188
- package/node_modules/@react-native-async-storage/async-storage/LICENSE +21 -0
- package/node_modules/@react-native-async-storage/async-storage/README.md +27 -0
- package/node_modules/@react-native-async-storage/async-storage/RNCAsyncStorage.podspec +19 -0
- package/node_modules/@react-native-async-storage/async-storage/android/build.gradle +142 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/AndroidManifest.xml +6 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java +178 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageErrorUtil.java +45 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageExpoMigration.java +154 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java +424 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java +58 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/ReactDatabaseSupplier.java +163 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/SerialExecutor.java +40 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/ArgumentHelpers.kt +86 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/ErrorHelpers.kt +39 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageModule.kt +90 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt +161 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/test/java/com/reactnativecommunity/asyncstorage/next/ArgumentHelpersTest.kt +93 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/test/java/com/reactnativecommunity/asyncstorage/next/StorageTest.kt +141 -0
- package/node_modules/@react-native-async-storage/async-storage/android/testresults.gradle +38 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.h +51 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.m +898 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.xcodeproj/project.pbxproj +283 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorageDelegate.h +73 -0
- package/node_modules/@react-native-async-storage/async-storage/jest/async-storage-mock.d.ts +9 -0
- package/node_modules/@react-native-async-storage/async-storage/jest/async-storage-mock.js +109 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.js +164 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.native.js +366 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.native.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/RCTAsyncStorage.js +30 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/RCTAsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/helpers.js +69 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/helpers.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/hooks.js +44 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/hooks.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/index.js +22 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/index.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/shouldFallbackToLegacyNativeModule.js +39 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/shouldFallbackToLegacyNativeModule.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/types.js +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/types.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.js +153 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.native.js +348 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.native.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/RCTAsyncStorage.js +20 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/RCTAsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/helpers.js +56 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/helpers.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/hooks.js +34 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/hooks.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/index.js +4 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/index.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/shouldFallbackToLegacyNativeModule.js +31 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/shouldFallbackToLegacyNativeModule.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/types.js +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/types.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/AsyncStorage.d.ts +10 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/AsyncStorage.native.d.ts +16 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/RCTAsyncStorage.d.ts +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/helpers.d.ts +5 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/hooks.d.ts +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/index.d.ts +4 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/shouldFallbackToLegacyNativeModule.d.ts +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/types.d.ts +113 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/project.pbxproj +385 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/xcshareddata/xcschemes/RNCAsyncStorage-macOS.xcscheme +67 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/xcshareddata/xcschemes/RNCAsyncStorage.xcscheme +67 -0
- package/node_modules/@react-native-async-storage/async-storage/package.json +197 -0
- package/node_modules/@react-native-async-storage/async-storage/src/AsyncStorage.native.ts +356 -0
- package/node_modules/@react-native-async-storage/async-storage/src/AsyncStorage.ts +173 -0
- package/node_modules/@react-native-async-storage/async-storage/src/RCTAsyncStorage.ts +28 -0
- package/node_modules/@react-native-async-storage/async-storage/src/helpers.ts +74 -0
- package/node_modules/@react-native-async-storage/async-storage/src/hooks.ts +11 -0
- package/node_modules/@react-native-async-storage/async-storage/src/index.ts +7 -0
- package/node_modules/@react-native-async-storage/async-storage/src/shouldFallbackToLegacyNativeModule.ts +34 -0
- package/node_modules/@react-native-async-storage/async-storage/src/types.ts +155 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/PropertySheet.props +16 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/ReactNativeAsyncStorage.vcxproj +172 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/ReactNativeAsyncStorage.vcxproj.filters +34 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/packages.config +4 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage.sln +172 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/PropertySheet.props +16 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/ReactNativeAsyncStorage61.vcxproj +157 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/ReactNativeAsyncStorage61.vcxproj.filters +34 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/packages.config +4 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61.sln +195 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage62.sln +192 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/DBStorage.cpp +599 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/DBStorage.h +162 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/RNCAsyncStorage.h +118 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactNativeAsyncStorage.def +3 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.cpp +20 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.h +23 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.idl +7 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/pch.cpp +3 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/pch.h +15 -0
- package/node_modules/merge-options/index.d.ts +2 -0
- package/node_modules/merge-options/index.js +171 -0
- package/node_modules/merge-options/index.mjs +8 -0
- package/node_modules/merge-options/license +21 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/index.d.ts +29 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/index.js +10 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/license +9 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/package.json +38 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/readme.md +54 -0
- package/node_modules/merge-options/package.json +59 -0
- package/node_modules/merge-options/readme.md +130 -0
- package/package.json +131 -130
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2015-present, Facebook, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# React Native Async Storage
|
2
|
+
|
3
|
+
An asynchronous, unencrypted, persistent, key-value storage system for React Native.
|
4
|
+
|
5
|
+
|
6
|
+
## Supported platforms
|
7
|
+
|
8
|
+
- iOS
|
9
|
+
- Android
|
10
|
+
- [Web](https://github.com/react-native-async-storage/async-storage/releases/tag/v1.9.0)
|
11
|
+
- [MacOS](https://github.com/react-native-async-storage/async-storage/releases/tag/v1.8.1)
|
12
|
+
- [Windows](https://github.com/react-native-async-storage/async-storage/releases/tag/v1.10.0)
|
13
|
+
|
14
|
+
|
15
|
+
## Getting Started
|
16
|
+
|
17
|
+
Head over to [documentation](https://react-native-async-storage.github.io/async-storage/docs/install) to learn more.
|
18
|
+
|
19
|
+
|
20
|
+
## Contribution
|
21
|
+
Pull requests are welcome. Please open an issue first to discuss what you would like to change.
|
22
|
+
|
23
|
+
See the [CONTRIBUTING](CONTRIBUTING.md) file for more information.
|
24
|
+
|
25
|
+
## License
|
26
|
+
|
27
|
+
MIT.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
4
|
+
|
5
|
+
Pod::Spec.new do |s|
|
6
|
+
s.name = "RNCAsyncStorage"
|
7
|
+
s.version = package['version']
|
8
|
+
s.summary = package['description']
|
9
|
+
s.license = package['license']
|
10
|
+
|
11
|
+
s.authors = package['author']
|
12
|
+
s.homepage = package['homepage']
|
13
|
+
s.platforms = { :ios => "9.0", :tvos => "9.2", :osx => "10.14" }
|
14
|
+
|
15
|
+
s.source = { :git => "https://github.com/react-native-async-storage/async-storage.git", :tag => "v#{s.version}" }
|
16
|
+
s.source_files = "ios/**/*.{h,m}"
|
17
|
+
|
18
|
+
s.dependency 'React-Core'
|
19
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import java.nio.file.Paths
|
2
|
+
|
3
|
+
def resolveModulePath(packageName) {
|
4
|
+
def basePath = rootDir.toPath().normalize()
|
5
|
+
|
6
|
+
// Node's module resolution algorithm searches up to the root directory,
|
7
|
+
// after which the base path will be null
|
8
|
+
while (basePath) {
|
9
|
+
def candidatePath = Paths.get(basePath.toString(), 'node_modules', packageName)
|
10
|
+
if (candidatePath.toFile().exists()) {
|
11
|
+
return candidatePath.toString()
|
12
|
+
}
|
13
|
+
|
14
|
+
basePath = basePath.getParent()
|
15
|
+
}
|
16
|
+
|
17
|
+
return null
|
18
|
+
}
|
19
|
+
|
20
|
+
def safeExtGet(prop, fallback) {
|
21
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
22
|
+
}
|
23
|
+
|
24
|
+
def getFlagOrDefault(flagName, defaultValue) {
|
25
|
+
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] == "true" : defaultValue
|
26
|
+
}
|
27
|
+
|
28
|
+
def getVersionOrDefault(String flagName, String defaultVersion) {
|
29
|
+
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion
|
30
|
+
}
|
31
|
+
|
32
|
+
configurations {
|
33
|
+
compileClasspath
|
34
|
+
}
|
35
|
+
|
36
|
+
buildscript {
|
37
|
+
// kotlin version is dictated by rootProject extension or property in gradle.properties
|
38
|
+
ext.asyncStorageKtVersion = rootProject.ext.has('kotlinVersion')
|
39
|
+
? rootProject.ext['kotlinVersion']
|
40
|
+
: rootProject.hasProperty('AsyncStorage_kotlinVersion')
|
41
|
+
? rootProject.properties['AsyncStorage_kotlinVersion']
|
42
|
+
: '1.8.10'
|
43
|
+
|
44
|
+
repositories {
|
45
|
+
mavenCentral()
|
46
|
+
google()
|
47
|
+
}
|
48
|
+
dependencies {
|
49
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$asyncStorageKtVersion"
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
// AsyncStorage has default size of 6MB.
|
54
|
+
// This is a sane limit to protect the user from the app storing too much data in the database.
|
55
|
+
// This also protects the database from filling up the disk cache and becoming malformed.
|
56
|
+
// If you really need bigger size, please keep in mind the potential consequences.
|
57
|
+
long dbSizeInMB = 6L
|
58
|
+
def newDbSize = rootProject.properties['AsyncStorage_db_size_in_MB']
|
59
|
+
if (newDbSize != null && newDbSize.isLong()) {
|
60
|
+
dbSizeInMB = newDbSize.toLong()
|
61
|
+
}
|
62
|
+
|
63
|
+
// Instead of reusing AsyncTask thread pool, AsyncStorage can use its own executor
|
64
|
+
def useDedicatedExecutor = getFlagOrDefault('AsyncStorage_dedicatedExecutor', false)
|
65
|
+
|
66
|
+
// Use next storage implementation
|
67
|
+
def useNextStorage = getFlagOrDefault("AsyncStorage_useNextStorage", false)
|
68
|
+
|
69
|
+
apply plugin: 'com.android.library'
|
70
|
+
if (useNextStorage) {
|
71
|
+
apply plugin: 'kotlin-android'
|
72
|
+
apply plugin: 'kotlin-kapt'
|
73
|
+
apply from: './testresults.gradle'
|
74
|
+
}
|
75
|
+
|
76
|
+
android {
|
77
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 32)
|
78
|
+
defaultConfig {
|
79
|
+
minSdkVersion safeExtGet('minSdkVersion', 23)
|
80
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 32)
|
81
|
+
buildConfigField "Long", "AsyncStorage_db_size", "${dbSizeInMB}L"
|
82
|
+
buildConfigField "boolean", "AsyncStorage_useDedicatedExecutor", "${useDedicatedExecutor}"
|
83
|
+
buildConfigField "boolean", "AsyncStorage_useNextStorage", "${useNextStorage}"
|
84
|
+
}
|
85
|
+
lintOptions {
|
86
|
+
abortOnError false
|
87
|
+
}
|
88
|
+
|
89
|
+
if (useNextStorage) {
|
90
|
+
testOptions {
|
91
|
+
unitTests {
|
92
|
+
returnDefaultValues = true
|
93
|
+
includeAndroidResources = true
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
repositories {
|
100
|
+
maven {
|
101
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
102
|
+
url "${resolveModulePath("react-native")}/android"
|
103
|
+
}
|
104
|
+
google()
|
105
|
+
mavenCentral()
|
106
|
+
}
|
107
|
+
|
108
|
+
dependencies {
|
109
|
+
|
110
|
+
if (useNextStorage) {
|
111
|
+
def room_version = getVersionOrDefault('AsyncStorage_next_roomVersion', '2.4.3')
|
112
|
+
def coroutines_version = "1.6.4"
|
113
|
+
def coroutinesTest_version = "1.6.4"
|
114
|
+
// if we don't provide explicit dependency on reflection, kotlin plugin
|
115
|
+
// would add one automatically, probably a version that is not compatible with
|
116
|
+
// used kotlin
|
117
|
+
def kotlinReflect_version = project.ext.asyncStorageKtVersion
|
118
|
+
def junit_version = "4.13.2"
|
119
|
+
def robolectric_version = "4.7.3"
|
120
|
+
def truth_version = "1.1.3"
|
121
|
+
def androidxtest_version = "1.4.0"
|
122
|
+
def androidtest_junit_version = "1.1.3"
|
123
|
+
|
124
|
+
implementation "androidx.room:room-runtime:$room_version"
|
125
|
+
implementation "androidx.room:room-ktx:$room_version"
|
126
|
+
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinReflect_version"
|
127
|
+
|
128
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
129
|
+
kapt "androidx.room:room-compiler:$room_version"
|
130
|
+
|
131
|
+
testImplementation "junit:junit:$junit_version"
|
132
|
+
testImplementation "androidx.test:runner:$androidxtest_version"
|
133
|
+
testImplementation "androidx.test:rules:$androidxtest_version"
|
134
|
+
testImplementation "androidx.test.ext:junit:$androidtest_junit_version"
|
135
|
+
testImplementation "org.robolectric:robolectric:$robolectric_version"
|
136
|
+
testImplementation "com.google.truth:truth:$truth_version"
|
137
|
+
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesTest_version"
|
138
|
+
}
|
139
|
+
|
140
|
+
//noinspection GradleDynamicVersion
|
141
|
+
implementation 'com.facebook.react:react-native:+' // From node_modules
|
142
|
+
}
|
@@ -0,0 +1,178 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
3
|
+
*
|
4
|
+
* This source code is licensed under the MIT license found in the
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
6
|
+
*/
|
7
|
+
|
8
|
+
package com.reactnativecommunity.asyncstorage;
|
9
|
+
|
10
|
+
import javax.annotation.Nullable;
|
11
|
+
import java.io.File;
|
12
|
+
import java.util.Arrays;
|
13
|
+
import java.util.Iterator;
|
14
|
+
import android.content.ContentValues;
|
15
|
+
import android.content.Context;
|
16
|
+
import android.database.Cursor;
|
17
|
+
import android.database.sqlite.SQLiteDatabase;
|
18
|
+
import android.os.Build;
|
19
|
+
import android.text.TextUtils;
|
20
|
+
import android.util.Log;
|
21
|
+
import com.facebook.react.bridge.ReadableArray;
|
22
|
+
import org.json.JSONException;
|
23
|
+
import org.json.JSONObject;
|
24
|
+
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.KEY_COLUMN;
|
25
|
+
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.TABLE_CATALYST;
|
26
|
+
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.VALUE_COLUMN;
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Helper for database operations.
|
30
|
+
*/
|
31
|
+
public class AsyncLocalStorageUtil {
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Build the String required for an SQL select statement:
|
35
|
+
* WHERE key IN (?, ?, ..., ?)
|
36
|
+
* without 'WHERE' and with selectionCount '?'
|
37
|
+
*/
|
38
|
+
/* package */ static String buildKeySelection(int selectionCount) {
|
39
|
+
String[] list = new String[selectionCount];
|
40
|
+
Arrays.fill(list, "?");
|
41
|
+
return KEY_COLUMN + " IN (" + TextUtils.join(", ", list) + ")";
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Build the String[] arguments needed for an SQL selection, i.e.:
|
46
|
+
* {a, b, c}
|
47
|
+
* to be used in the SQL select statement: WHERE key in (?, ?, ?)
|
48
|
+
*/
|
49
|
+
/* package */ static String[] buildKeySelectionArgs(ReadableArray keys, int start, int count) {
|
50
|
+
String[] selectionArgs = new String[count];
|
51
|
+
for (int keyIndex = 0; keyIndex < count; keyIndex++) {
|
52
|
+
selectionArgs[keyIndex] = keys.getString(start + keyIndex);
|
53
|
+
}
|
54
|
+
return selectionArgs;
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Returns the value of the given key, or null if not found.
|
59
|
+
*/
|
60
|
+
public static @Nullable String getItemImpl(SQLiteDatabase db, String key) {
|
61
|
+
String[] columns = {VALUE_COLUMN};
|
62
|
+
String[] selectionArgs = {key};
|
63
|
+
|
64
|
+
Cursor cursor = db.query(
|
65
|
+
TABLE_CATALYST,
|
66
|
+
columns,
|
67
|
+
KEY_COLUMN + "=?",
|
68
|
+
selectionArgs,
|
69
|
+
null,
|
70
|
+
null,
|
71
|
+
null);
|
72
|
+
|
73
|
+
try {
|
74
|
+
if (!cursor.moveToFirst()) {
|
75
|
+
return null;
|
76
|
+
} else {
|
77
|
+
return cursor.getString(0);
|
78
|
+
}
|
79
|
+
} finally {
|
80
|
+
cursor.close();
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
/**
|
85
|
+
* Sets the value for the key given, returns true if successful, false otherwise.
|
86
|
+
*/
|
87
|
+
/* package */ static boolean setItemImpl(SQLiteDatabase db, String key, String value) {
|
88
|
+
ContentValues contentValues = new ContentValues();
|
89
|
+
contentValues.put(KEY_COLUMN, key);
|
90
|
+
contentValues.put(VALUE_COLUMN, value);
|
91
|
+
|
92
|
+
long inserted = db.insertWithOnConflict(
|
93
|
+
TABLE_CATALYST,
|
94
|
+
null,
|
95
|
+
contentValues,
|
96
|
+
SQLiteDatabase.CONFLICT_REPLACE);
|
97
|
+
|
98
|
+
return (-1 != inserted);
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Does the actual merge of the (key, value) pair with the value stored in the database.
|
103
|
+
* NB: This assumes that a database lock is already in effect!
|
104
|
+
* @return the errorCode of the operation
|
105
|
+
*/
|
106
|
+
/* package */ static boolean mergeImpl(SQLiteDatabase db, String key, String value)
|
107
|
+
throws JSONException {
|
108
|
+
String oldValue = getItemImpl(db, key);
|
109
|
+
String newValue;
|
110
|
+
|
111
|
+
if (oldValue == null) {
|
112
|
+
newValue = value;
|
113
|
+
} else {
|
114
|
+
JSONObject oldJSON = new JSONObject(oldValue);
|
115
|
+
JSONObject newJSON = new JSONObject(value);
|
116
|
+
deepMergeInto(oldJSON, newJSON);
|
117
|
+
newValue = oldJSON.toString();
|
118
|
+
}
|
119
|
+
|
120
|
+
return setItemImpl(db, key, newValue);
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Merges two {@link JSONObject}s. The newJSON object will be merged with the oldJSON object by
|
125
|
+
* either overriding its values, or merging them (if the values of the same key in both objects
|
126
|
+
* are of type {@link JSONObject}). oldJSON will contain the result of this merge.
|
127
|
+
*/
|
128
|
+
private static void deepMergeInto(JSONObject oldJSON, JSONObject newJSON)
|
129
|
+
throws JSONException {
|
130
|
+
Iterator<?> keys = newJSON.keys();
|
131
|
+
while (keys.hasNext()) {
|
132
|
+
String key = (String) keys.next();
|
133
|
+
|
134
|
+
JSONObject newJSONObject = newJSON.optJSONObject(key);
|
135
|
+
JSONObject oldJSONObject = oldJSON.optJSONObject(key);
|
136
|
+
if (newJSONObject != null && oldJSONObject != null) {
|
137
|
+
deepMergeInto(oldJSONObject, newJSONObject);
|
138
|
+
oldJSON.put(key, oldJSONObject);
|
139
|
+
} else {
|
140
|
+
oldJSON.put(key, newJSON.get(key));
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
/**
|
145
|
+
* From Pie and up, Android started to use Write-ahead logging (WAL), instead of journal rollback
|
146
|
+
* for atomic commits and rollbacks.
|
147
|
+
* Basically, WAL does not write directly to the database file, rather to the supporting WAL file.
|
148
|
+
* Because of that, migration to the next storage might not be successful, because the content of
|
149
|
+
* RKStorage might be still in WAL file instead. Committing all data from WAL to db file is called
|
150
|
+
* a "checkpoint" and is done automatically (by default) when the WAL file reaches a threshold
|
151
|
+
* size of 1000 pages.
|
152
|
+
* More here: https://sqlite.org/wal.html
|
153
|
+
*
|
154
|
+
* This helper will force checkpoint on RKStorage, if Next storage file does not exists yet.
|
155
|
+
*/
|
156
|
+
public static void verifyAndForceSqliteCheckpoint(Context ctx) {
|
157
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
158
|
+
Log.i("AsyncStorage_Next", "SQLite checkpoint not required on this API version.");
|
159
|
+
}
|
160
|
+
|
161
|
+
File nextStorageFile = ctx.getDatabasePath("AsyncStorage");
|
162
|
+
File currentStorageFile = ctx.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME);
|
163
|
+
boolean isCheckpointRequired = !nextStorageFile.exists() && currentStorageFile.exists();
|
164
|
+
if (!isCheckpointRequired) {
|
165
|
+
Log.i("AsyncStorage_Next", "SQLite checkpoint not required.");
|
166
|
+
return;
|
167
|
+
}
|
168
|
+
|
169
|
+
try {
|
170
|
+
ReactDatabaseSupplier supplier = ReactDatabaseSupplier.getInstance(ctx);
|
171
|
+
supplier.get().rawQuery("PRAGMA wal_checkpoint", null).close();
|
172
|
+
supplier.closeDatabase();
|
173
|
+
Log.i("AsyncStorage_Next", "Forcing SQLite checkpoint successful.");
|
174
|
+
} catch (Exception e) {
|
175
|
+
Log.w("AsyncStorage_Next", "Could not force checkpoint on RKStorage, the Next storage might not migrate the data properly: " + e.getMessage());
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
3
|
+
*
|
4
|
+
* This source code is licensed under the MIT license found in the
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
6
|
+
*/
|
7
|
+
|
8
|
+
package com.reactnativecommunity.asyncstorage;
|
9
|
+
|
10
|
+
import javax.annotation.Nullable;
|
11
|
+
|
12
|
+
import com.facebook.react.bridge.Arguments;
|
13
|
+
import com.facebook.react.bridge.WritableMap;
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Helper class for database errors.
|
17
|
+
*/
|
18
|
+
public class AsyncStorageErrorUtil {
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Create Error object to be passed back to the JS callback.
|
22
|
+
*/
|
23
|
+
/* package */ static WritableMap getError(@Nullable String key, String errorMessage) {
|
24
|
+
WritableMap errorMap = Arguments.createMap();
|
25
|
+
errorMap.putString("message", errorMessage);
|
26
|
+
if (key != null) {
|
27
|
+
errorMap.putString("key", key);
|
28
|
+
}
|
29
|
+
return errorMap;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* package */ static WritableMap getInvalidKeyError(@Nullable String key) {
|
33
|
+
return getError(key, "Invalid key");
|
34
|
+
}
|
35
|
+
|
36
|
+
/* package */ static WritableMap getInvalidValueError(@Nullable String key) {
|
37
|
+
return getError(key, "Invalid Value");
|
38
|
+
}
|
39
|
+
|
40
|
+
/* package */ static WritableMap getDBError(@Nullable String key) {
|
41
|
+
return getError(key, "Database Error");
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
}
|
@@ -0,0 +1,154 @@
|
|
1
|
+
package com.reactnativecommunity.asyncstorage;
|
2
|
+
|
3
|
+
import android.content.Context;
|
4
|
+
import android.os.Build;
|
5
|
+
import android.util.Log;
|
6
|
+
|
7
|
+
import androidx.annotation.RequiresApi;
|
8
|
+
|
9
|
+
import java.io.File;
|
10
|
+
import java.io.FileInputStream;
|
11
|
+
import java.io.FileOutputStream;
|
12
|
+
import java.io.IOException;
|
13
|
+
import java.nio.channels.FileChannel;
|
14
|
+
import java.nio.file.Files;
|
15
|
+
import java.nio.file.attribute.BasicFileAttributes;
|
16
|
+
import java.util.ArrayList;
|
17
|
+
|
18
|
+
// A utility class that migrates a scoped AsyncStorage database to RKStorage.
|
19
|
+
// This utility only runs if the RKStorage file has not been created yet.
|
20
|
+
public class AsyncStorageExpoMigration {
|
21
|
+
static final String LOG_TAG = "AsyncStorageExpoMigration";
|
22
|
+
|
23
|
+
public static void migrate(Context context) {
|
24
|
+
// Only migrate if the default async storage file does not exist.
|
25
|
+
if (isAsyncStorageDatabaseCreated(context)) {
|
26
|
+
return;
|
27
|
+
}
|
28
|
+
|
29
|
+
ArrayList<File> expoDatabases = getExpoDatabases(context);
|
30
|
+
|
31
|
+
File expoDatabase = getLastModifiedFile(expoDatabases);
|
32
|
+
|
33
|
+
if (expoDatabase == null) {
|
34
|
+
Log.v(LOG_TAG, "No scoped database found");
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
|
38
|
+
try {
|
39
|
+
// Create the storage file
|
40
|
+
ReactDatabaseSupplier.getInstance(context).get();
|
41
|
+
copyFile(new FileInputStream(expoDatabase), new FileOutputStream(context.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME)));
|
42
|
+
Log.v(LOG_TAG, "Migrated most recently modified database " + expoDatabase.getName() + " to RKStorage");
|
43
|
+
} catch (Exception e) {
|
44
|
+
Log.v(LOG_TAG, "Failed to migrate scoped database " + expoDatabase.getName());
|
45
|
+
e.printStackTrace();
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
|
49
|
+
try {
|
50
|
+
for (File file : expoDatabases) {
|
51
|
+
if (file.delete()) {
|
52
|
+
Log.v(LOG_TAG, "Deleted scoped database " + file.getName());
|
53
|
+
} else {
|
54
|
+
Log.v(LOG_TAG, "Failed to delete scoped database " + file.getName());
|
55
|
+
}
|
56
|
+
}
|
57
|
+
} catch (Exception e) {
|
58
|
+
e.printStackTrace();
|
59
|
+
}
|
60
|
+
|
61
|
+
Log.v(LOG_TAG, "Completed the scoped AsyncStorage migration");
|
62
|
+
}
|
63
|
+
|
64
|
+
private static boolean isAsyncStorageDatabaseCreated(Context context) {
|
65
|
+
return context.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME).exists();
|
66
|
+
}
|
67
|
+
|
68
|
+
// Find all database files that the user may have created while using Expo.
|
69
|
+
private static ArrayList<File> getExpoDatabases(Context context) {
|
70
|
+
ArrayList<File> scopedDatabases = new ArrayList<>();
|
71
|
+
try {
|
72
|
+
File databaseDirectory = context.getDatabasePath("noop").getParentFile();
|
73
|
+
File[] directoryListing = databaseDirectory.listFiles();
|
74
|
+
if (directoryListing != null) {
|
75
|
+
for (File child : directoryListing) {
|
76
|
+
// Find all databases matching the Expo scoped key, and skip any database journals.
|
77
|
+
if (child.getName().startsWith("RKStorage-scoped-experience-") && !child.getName().endsWith("-journal")) {
|
78
|
+
scopedDatabases.add(child);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
} catch (Exception e) {
|
83
|
+
// Just in case anything happens catch and print, file system rules can tend to be different across vendors.
|
84
|
+
e.printStackTrace();
|
85
|
+
}
|
86
|
+
return scopedDatabases;
|
87
|
+
}
|
88
|
+
|
89
|
+
// Returns the most recently modified file.
|
90
|
+
// If a user publishes an app with Expo, then changes the slug
|
91
|
+
// and publishes again, a new database will be created.
|
92
|
+
// We want to select the most recent database and migrate it to RKStorage.
|
93
|
+
private static File getLastModifiedFile(ArrayList<File> files) {
|
94
|
+
if (files.size() == 0) {
|
95
|
+
return null;
|
96
|
+
}
|
97
|
+
long lastMod = -1;
|
98
|
+
File lastModFile = null;
|
99
|
+
for (File child : files) {
|
100
|
+
long modTime = getLastModifiedTimeInMillis(child);
|
101
|
+
if (modTime > lastMod) {
|
102
|
+
lastMod = modTime;
|
103
|
+
lastModFile = child;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
if (lastModFile != null) {
|
107
|
+
return lastModFile;
|
108
|
+
}
|
109
|
+
|
110
|
+
return files.get(0);
|
111
|
+
}
|
112
|
+
|
113
|
+
private static long getLastModifiedTimeInMillis(File file) {
|
114
|
+
try {
|
115
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
116
|
+
return getLastModifiedTimeFromBasicFileAttrs(file);
|
117
|
+
} else {
|
118
|
+
return file.lastModified();
|
119
|
+
}
|
120
|
+
} catch (Exception e) {
|
121
|
+
e.printStackTrace();
|
122
|
+
return -1;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
@RequiresApi(Build.VERSION_CODES.O)
|
127
|
+
private static long getLastModifiedTimeFromBasicFileAttrs(File file) {
|
128
|
+
try {
|
129
|
+
return Files.readAttributes(file.toPath(), BasicFileAttributes.class).creationTime().toMillis();
|
130
|
+
} catch (Exception e) {
|
131
|
+
return -1;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
private static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
|
136
|
+
FileChannel fromChannel = null;
|
137
|
+
FileChannel toChannel = null;
|
138
|
+
try {
|
139
|
+
fromChannel = fromFile.getChannel();
|
140
|
+
toChannel = toFile.getChannel();
|
141
|
+
fromChannel.transferTo(0, fromChannel.size(), toChannel);
|
142
|
+
} finally {
|
143
|
+
try {
|
144
|
+
if (fromChannel != null) {
|
145
|
+
fromChannel.close();
|
146
|
+
}
|
147
|
+
} finally {
|
148
|
+
if (toChannel != null) {
|
149
|
+
toChannel.close();
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|