react-native-mmkv 2.12.2 → 3.0.0-beta.2
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/LICENSE +1 -200
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +4 -2
- package/MMKV/Core/MMKVPredef.h +1 -1
- package/MMKV/Core/MMKV_IO.cpp +5 -1
- package/MMKV/Core/MemoryFile.cpp +1 -0
- package/MMKV/Core/MemoryFile_OSX.cpp +2 -1
- package/MMKV/README.md +8 -8
- package/README.md +35 -4
- package/android/CMakeLists.txt +20 -28
- package/android/build.gradle +59 -89
- package/android/gradle.properties +4 -5
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/{hasNamespace/AndroidManifest.xml → main/AndroidManifestNew.xml} +0 -1
- package/android/src/main/cpp/AndroidLogger.cpp +16 -0
- package/android/src/main/cpp/cpp-adapter.cpp +4 -80
- package/android/src/main/java/com/mrousavy/mmkv/MmkvPackage.java +44 -0
- package/android/src/main/java/com/mrousavy/mmkv/MmkvPlatformContextModule.java +17 -0
- package/cpp/Logger.h +35 -0
- package/cpp/MMKVManagedBuffer.h +32 -0
- package/{android/src/main/cpp → cpp}/MmkvHostObject.cpp +126 -63
- package/{android/src/main/cpp → cpp}/MmkvHostObject.h +9 -3
- package/cpp/NativeMmkvModule.cpp +46 -0
- package/cpp/NativeMmkvModule.h +37 -0
- package/ios/AppleLogger.mm +16 -0
- package/ios/MmkvOnLoad.mm +25 -0
- package/ios/MmkvPlatformContext.h +19 -0
- package/ios/MmkvPlatformContextModule.mm +37 -0
- package/lib/commonjs/LazyTurboModule.js +49 -0
- package/lib/commonjs/LazyTurboModule.js.map +1 -0
- package/lib/commonjs/MMKV.js +28 -4
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/NativeMmkv.js +35 -0
- package/lib/commonjs/NativeMmkv.js.map +1 -0
- package/lib/commonjs/NativeMmkvPlatformContext.js +13 -0
- package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -0
- package/lib/commonjs/PlatformChecker.js.map +1 -1
- package/lib/commonjs/Types.js +2 -0
- package/lib/commonjs/Types.js.map +1 -0
- package/lib/commonjs/createMMKV.js +6 -43
- package/lib/commonjs/createMMKV.js.map +1 -1
- package/lib/commonjs/createMMKV.mock.js +5 -1
- package/lib/commonjs/createMMKV.mock.js.map +1 -1
- package/lib/commonjs/createMMKV.web.js +8 -4
- package/lib/commonjs/createMMKV.web.js.map +1 -1
- package/lib/commonjs/createTextEncoder.js.map +1 -1
- package/lib/commonjs/hooks.js +11 -10
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/LazyTurboModule.js +43 -0
- package/lib/module/LazyTurboModule.js.map +1 -0
- package/lib/module/MMKV.js +16 -4
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/NativeMmkv.js +32 -0
- package/lib/module/NativeMmkv.js.map +1 -0
- package/lib/module/NativeMmkvPlatformContext.js +7 -0
- package/lib/module/NativeMmkvPlatformContext.js.map +1 -0
- package/lib/module/PlatformChecker.js.map +1 -1
- package/lib/module/Types.js +2 -0
- package/lib/module/Types.js.map +1 -0
- package/lib/module/createMMKV.js +6 -43
- package/lib/module/createMMKV.js.map +1 -1
- package/lib/module/createMMKV.mock.js +5 -1
- package/lib/module/createMMKV.mock.js.map +1 -1
- package/lib/module/createMMKV.web.js +6 -4
- package/lib/module/createMMKV.web.js.map +1 -1
- package/lib/module/createTextEncoder.js.map +1 -1
- package/lib/module/hooks.js +7 -2
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/LazyTurboModule.d.ts +6 -0
- package/lib/typescript/src/LazyTurboModule.d.ts.map +1 -0
- package/lib/typescript/src/MMKV.d.ts +35 -0
- package/lib/typescript/src/MMKV.d.ts.map +1 -0
- package/lib/typescript/src/NativeMmkv.d.ts +83 -0
- package/lib/typescript/src/NativeMmkv.d.ts.map +1 -0
- package/lib/typescript/src/NativeMmkvPlatformContext.d.ts +9 -0
- package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -0
- package/lib/typescript/src/PlatformChecker.d.ts.map +1 -0
- package/lib/typescript/src/Types.d.ts +86 -0
- package/lib/typescript/src/Types.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/hooks.test.d.ts +2 -0
- package/lib/typescript/src/__tests__/hooks.test.d.ts.map +1 -0
- package/lib/typescript/src/createMMKV.d.ts +4 -0
- package/lib/typescript/src/createMMKV.d.ts.map +1 -0
- package/lib/typescript/src/createMMKV.mock.d.ts +3 -0
- package/lib/typescript/src/createMMKV.mock.d.ts.map +1 -0
- package/lib/typescript/src/createMMKV.web.d.ts +4 -0
- package/lib/typescript/src/createMMKV.web.d.ts.map +1 -0
- package/lib/typescript/src/createTextEncoder.d.ts.map +1 -0
- package/lib/typescript/{hooks.d.ts → src/hooks.d.ts} +7 -4
- package/lib/typescript/src/hooks.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +52 -40
- package/react-native-mmkv.podspec +17 -18
- package/react-native.config.js +20 -0
- package/src/LazyTurboModule.ts +62 -0
- package/src/MMKV.ts +19 -132
- package/src/NativeMmkv.ts +105 -0
- package/src/NativeMmkvPlatformContext.ts +14 -0
- package/src/Types.ts +89 -0
- package/src/__tests__/hooks.test.tsx +89 -0
- package/src/createMMKV.mock.ts +7 -3
- package/src/createMMKV.ts +10 -65
- package/src/createMMKV.web.ts +7 -2
- package/src/hooks.ts +17 -11
- package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +0 -49
- package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +0 -26
- package/cpp/TypedArray.cpp +0 -322
- package/cpp/TypedArray.h +0 -153
- package/ios/JSIUtils.h +0 -38
- package/ios/JSIUtils.mm +0 -167
- package/ios/Mmkv.xcodeproj/project.pbxproj +0 -291
- package/ios/MmkvHostObject.h +0 -27
- package/ios/MmkvHostObject.mm +0 -295
- package/ios/MmkvModule.h +0 -5
- package/ios/MmkvModule.mm +0 -101
- package/lib/typescript/MMKV.d.ts +0 -142
- package/lib/typescript/MMKV.d.ts.map +0 -1
- package/lib/typescript/PlatformChecker.d.ts.map +0 -1
- package/lib/typescript/createMMKV.d.ts +0 -7
- package/lib/typescript/createMMKV.d.ts.map +0 -1
- package/lib/typescript/createMMKV.mock.d.ts +0 -3
- package/lib/typescript/createMMKV.mock.d.ts.map +0 -1
- package/lib/typescript/createMMKV.web.d.ts +0 -3
- package/lib/typescript/createMMKV.web.d.ts.map +0 -1
- package/lib/typescript/createTextEncoder.d.ts.map +0 -1
- package/lib/typescript/hooks.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- /package/lib/typescript/{PlatformChecker.d.ts → src/PlatformChecker.d.ts} +0 -0
- /package/lib/typescript/{createTextEncoder.d.ts → src/createTextEncoder.d.ts} +0 -0
- /package/lib/typescript/{index.d.ts → src/index.d.ts} +0 -0
|
@@ -7,31 +7,39 @@
|
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
#include "MmkvHostObject.h"
|
|
10
|
-
#include "
|
|
10
|
+
#include "Logger.h"
|
|
11
|
+
#include "MMKVManagedBuffer.h"
|
|
11
12
|
#include <MMKV.h>
|
|
12
|
-
#include <android/log.h>
|
|
13
13
|
#include <string>
|
|
14
14
|
#include <vector>
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
using namespace mmkv;
|
|
17
|
+
|
|
18
|
+
MmkvHostObject::MmkvHostObject(const facebook::react::MMKVConfig& config) {
|
|
19
|
+
std::string path = config.path.has_value() ? config.path.value() : "";
|
|
20
|
+
std::string encryptionKey = config.encryptionKey.has_value() ? config.encryptionKey.value() : "";
|
|
21
|
+
bool hasEncryptionKey = encryptionKey.size() > 0;
|
|
22
|
+
Logger::log("RNMMKV", "Creating MMKV instance \"%s\"... (Path: %s, Encrypted: %s)",
|
|
23
|
+
config.id.c_str(), path.c_str(), hasEncryptionKey ? "true" : "false");
|
|
24
|
+
|
|
22
25
|
std::string* pathPtr = path.size() > 0 ? &path : nullptr;
|
|
23
|
-
std::string*
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
std::string* encryptionKeyPtr = encryptionKey.size() > 0 ? &encryptionKey : nullptr;
|
|
27
|
+
MMKVMode mode = getMMKVMode(config);
|
|
28
|
+
|
|
29
|
+
#ifdef __APPLE__
|
|
30
|
+
instance = MMKV::mmkvWithID(config.id, mode, encryptionKeyPtr, pathPtr);
|
|
31
|
+
#else
|
|
32
|
+
instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr);
|
|
33
|
+
#endif
|
|
26
34
|
|
|
27
35
|
if (instance == nullptr) {
|
|
28
36
|
// Check if instanceId is invalid
|
|
29
|
-
if (
|
|
37
|
+
if (config.id.empty()) {
|
|
30
38
|
throw std::runtime_error("Failed to create MMKV instance! `id` cannot be empty!");
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
// Check if encryptionKey is invalid
|
|
34
|
-
if (
|
|
42
|
+
if (encryptionKey.size() > 16) {
|
|
35
43
|
throw std::runtime_error(
|
|
36
44
|
"Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!");
|
|
37
45
|
}
|
|
@@ -40,8 +48,18 @@ MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path,
|
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
MmkvHostObject::~MmkvHostObject() {
|
|
52
|
+
if (instance != nullptr) {
|
|
53
|
+
std::string instanceId = instance->mmapID();
|
|
54
|
+
Logger::log("RNMMKV", "Destroying MMKV instance \"%s\"...", instanceId.c_str());
|
|
55
|
+
instance->clearMemoryCache();
|
|
56
|
+
}
|
|
57
|
+
instance = nullptr;
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt) {
|
|
44
61
|
std::vector<jsi::PropNameID> result;
|
|
62
|
+
result.reserve(12);
|
|
45
63
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("set")));
|
|
46
64
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBoolean")));
|
|
47
65
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBuffer")));
|
|
@@ -52,26 +70,44 @@ std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt)
|
|
|
52
70
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getAllKeys")));
|
|
53
71
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("deleteAll")));
|
|
54
72
|
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("recrypt")));
|
|
73
|
+
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("trim")));
|
|
74
|
+
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("size")));
|
|
55
75
|
return result;
|
|
56
76
|
}
|
|
57
77
|
|
|
78
|
+
MMKVMode MmkvHostObject::getMMKVMode(const facebook::react::MMKVConfig& config) {
|
|
79
|
+
if (!config.mode.has_value()) {
|
|
80
|
+
return MMKVMode::MMKV_SINGLE_PROCESS;
|
|
81
|
+
}
|
|
82
|
+
auto mode = config.mode.value();
|
|
83
|
+
switch (mode) {
|
|
84
|
+
case facebook::react::MmkvCxxMode::SINGLE_PROCESS:
|
|
85
|
+
return MMKVMode::MMKV_SINGLE_PROCESS;
|
|
86
|
+
case facebook::react::MmkvCxxMode::MULTI_PROCESS:
|
|
87
|
+
return MMKVMode::MMKV_MULTI_PROCESS;
|
|
88
|
+
default:
|
|
89
|
+
throw std::runtime_error("Invalid MMKV Mode value!");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
58
93
|
jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) {
|
|
59
94
|
auto propName = propNameId.utf8(runtime);
|
|
60
95
|
auto funcName = "MMKV." + propName;
|
|
61
96
|
|
|
62
97
|
if (propName == "set") {
|
|
63
|
-
// MMKV.set(key: string, value: string | number | bool |
|
|
98
|
+
// MMKV.set(key: string, value: string | number | bool | ArrayBuffer)
|
|
64
99
|
return jsi::Function::createFromHostFunction(
|
|
65
100
|
runtime, jsi::PropNameID::forAscii(runtime, funcName),
|
|
66
101
|
2, // key, value
|
|
67
102
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
68
103
|
size_t count) -> jsi::Value {
|
|
69
|
-
if (!arguments[0].isString()) {
|
|
104
|
+
if (count != 2 || !arguments[0].isString()) {
|
|
105
|
+
[[unlikely]];
|
|
70
106
|
throw jsi::JSError(runtime,
|
|
71
107
|
"MMKV::set: First argument ('key') has to be of type string!");
|
|
72
108
|
}
|
|
73
109
|
|
|
74
|
-
auto keyName = arguments[0].
|
|
110
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
75
111
|
|
|
76
112
|
if (arguments[1].isBool()) {
|
|
77
113
|
// bool
|
|
@@ -81,22 +117,21 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
81
117
|
instance->set(arguments[1].getNumber(), keyName);
|
|
82
118
|
} else if (arguments[1].isString()) {
|
|
83
119
|
// string
|
|
84
|
-
auto stringValue = arguments[1].
|
|
120
|
+
auto stringValue = arguments[1].asString(runtime).utf8(runtime);
|
|
85
121
|
instance->set(stringValue, keyName);
|
|
86
122
|
} else if (arguments[1].isObject()) {
|
|
87
123
|
// object
|
|
88
124
|
auto object = arguments[1].asObject(runtime);
|
|
89
|
-
if (
|
|
90
|
-
//
|
|
91
|
-
auto
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
mmkv::MMBufferCopyFlag::MMBufferNoCopy);
|
|
95
|
-
instance->set(buffer, keyName);
|
|
125
|
+
if (object.isArrayBuffer(runtime)) {
|
|
126
|
+
// ArrayBuffer
|
|
127
|
+
auto arrayBuffer = object.getArrayBuffer(runtime);
|
|
128
|
+
MMBuffer data(arrayBuffer.data(runtime), arrayBuffer.size(runtime), MMBufferNoCopy);
|
|
129
|
+
instance->set(data, keyName);
|
|
96
130
|
} else {
|
|
97
131
|
// unknown object
|
|
98
132
|
throw jsi::JSError(
|
|
99
|
-
runtime,
|
|
133
|
+
runtime,
|
|
134
|
+
"MMKV::set: 'value' argument is an object, but not of type ArrayBuffer!");
|
|
100
135
|
}
|
|
101
136
|
} else {
|
|
102
137
|
// unknown type
|
|
@@ -116,62 +151,65 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
116
151
|
1, // key
|
|
117
152
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
118
153
|
size_t count) -> jsi::Value {
|
|
119
|
-
if (!arguments[0].isString()) {
|
|
154
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
155
|
+
[[unlikely]];
|
|
120
156
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
121
157
|
}
|
|
122
158
|
|
|
123
|
-
auto keyName = arguments[0].
|
|
159
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
124
160
|
bool hasValue;
|
|
125
161
|
auto value = instance->getBool(keyName, false, &hasValue);
|
|
126
|
-
if (hasValue) {
|
|
127
|
-
|
|
128
|
-
} else {
|
|
162
|
+
if (!hasValue) {
|
|
163
|
+
[[unlikely]];
|
|
129
164
|
return jsi::Value::undefined();
|
|
130
165
|
}
|
|
166
|
+
return jsi::Value(value);
|
|
131
167
|
});
|
|
132
168
|
}
|
|
133
169
|
|
|
134
|
-
if (propName == "
|
|
135
|
-
// MMKV.
|
|
170
|
+
if (propName == "getNumber") {
|
|
171
|
+
// MMKV.getNumber(key: string)
|
|
136
172
|
return jsi::Function::createFromHostFunction(
|
|
137
173
|
runtime, jsi::PropNameID::forAscii(runtime, funcName),
|
|
138
174
|
1, // key
|
|
139
175
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
140
176
|
size_t count) -> jsi::Value {
|
|
141
|
-
if (!arguments[0].isString()) {
|
|
177
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
178
|
+
[[unlikely]];
|
|
142
179
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
143
180
|
}
|
|
144
181
|
|
|
145
|
-
auto keyName = arguments[0].
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (hasValue) {
|
|
149
|
-
|
|
150
|
-
} else {
|
|
182
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
183
|
+
bool hasValue;
|
|
184
|
+
auto value = instance->getDouble(keyName, 0.0, &hasValue);
|
|
185
|
+
if (!hasValue) {
|
|
186
|
+
[[unlikely]];
|
|
151
187
|
return jsi::Value::undefined();
|
|
152
188
|
}
|
|
189
|
+
return jsi::Value(value);
|
|
153
190
|
});
|
|
154
191
|
}
|
|
155
192
|
|
|
156
|
-
if (propName == "
|
|
157
|
-
// MMKV.
|
|
193
|
+
if (propName == "getString") {
|
|
194
|
+
// MMKV.getString(key: string)
|
|
158
195
|
return jsi::Function::createFromHostFunction(
|
|
159
196
|
runtime, jsi::PropNameID::forAscii(runtime, funcName),
|
|
160
197
|
1, // key
|
|
161
198
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
162
199
|
size_t count) -> jsi::Value {
|
|
163
|
-
if (!arguments[0].isString()) {
|
|
200
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
201
|
+
[[unlikely]];
|
|
164
202
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
165
203
|
}
|
|
166
204
|
|
|
167
|
-
auto keyName = arguments[0].
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (hasValue) {
|
|
171
|
-
|
|
172
|
-
} else {
|
|
205
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
206
|
+
std::string result;
|
|
207
|
+
bool hasValue = instance->getString(keyName, result);
|
|
208
|
+
if (!hasValue) {
|
|
209
|
+
[[unlikely]];
|
|
173
210
|
return jsi::Value::undefined();
|
|
174
211
|
}
|
|
212
|
+
return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result));
|
|
175
213
|
});
|
|
176
214
|
}
|
|
177
215
|
|
|
@@ -182,24 +220,20 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
182
220
|
1, // key
|
|
183
221
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
184
222
|
size_t count) -> jsi::Value {
|
|
185
|
-
if (!arguments[0].isString()) {
|
|
223
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
224
|
+
[[unlikely]];
|
|
186
225
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
187
226
|
}
|
|
188
227
|
|
|
189
|
-
auto keyName = arguments[0].
|
|
228
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
190
229
|
mmkv::MMBuffer buffer;
|
|
191
230
|
bool hasValue = instance->getBytes(keyName, buffer);
|
|
192
|
-
if (hasValue) {
|
|
193
|
-
|
|
194
|
-
TypedArray<TypedArrayKind::Uint8Array> array(runtime, length);
|
|
195
|
-
auto data = static_cast<const unsigned char*>(buffer.getPtr());
|
|
196
|
-
std::vector<unsigned char> vector(length);
|
|
197
|
-
vector.assign(data, data + length);
|
|
198
|
-
array.update(runtime, vector);
|
|
199
|
-
return array;
|
|
200
|
-
} else {
|
|
231
|
+
if (!hasValue) {
|
|
232
|
+
[[unlikely]];
|
|
201
233
|
return jsi::Value::undefined();
|
|
202
234
|
}
|
|
235
|
+
auto mutableData = std::make_shared<MMKVManagedBuffer>(std::move(buffer));
|
|
236
|
+
return jsi::ArrayBuffer(runtime, mutableData);
|
|
203
237
|
});
|
|
204
238
|
}
|
|
205
239
|
|
|
@@ -210,11 +244,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
210
244
|
1, // key
|
|
211
245
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
212
246
|
size_t count) -> jsi::Value {
|
|
213
|
-
if (!arguments[0].isString()) {
|
|
247
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
248
|
+
[[unlikely]];
|
|
214
249
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
215
250
|
}
|
|
216
251
|
|
|
217
|
-
auto keyName = arguments[0].
|
|
252
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
218
253
|
bool containsKey = instance->containsKey(keyName);
|
|
219
254
|
return jsi::Value(containsKey);
|
|
220
255
|
});
|
|
@@ -227,11 +262,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
227
262
|
1, // key
|
|
228
263
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
229
264
|
size_t count) -> jsi::Value {
|
|
230
|
-
if (!arguments[0].isString()) {
|
|
265
|
+
if (count != 1 || !arguments[0].isString()) {
|
|
266
|
+
[[unlikely]];
|
|
231
267
|
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
|
|
232
268
|
}
|
|
233
269
|
|
|
234
|
-
auto keyName = arguments[0].
|
|
270
|
+
auto keyName = arguments[0].asString(runtime).utf8(runtime);
|
|
235
271
|
instance->removeValueForKey(keyName);
|
|
236
272
|
return jsi::Value::undefined();
|
|
237
273
|
});
|
|
@@ -270,6 +306,12 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
270
306
|
1, // encryptionKey
|
|
271
307
|
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
272
308
|
size_t count) -> jsi::Value {
|
|
309
|
+
if (count != 1) {
|
|
310
|
+
[[unlikely]];
|
|
311
|
+
throw jsi::JSError(runtime, "Expected 1 argument (encryptionKey), but received " +
|
|
312
|
+
std::to_string(count) + "!");
|
|
313
|
+
}
|
|
314
|
+
|
|
273
315
|
if (arguments[0].isUndefined()) {
|
|
274
316
|
// reset encryption key to "no encryption"
|
|
275
317
|
instance->reKey(std::string());
|
|
@@ -278,13 +320,34 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
|
|
|
278
320
|
auto encryptionKey = arguments[0].getString(runtime).utf8(runtime);
|
|
279
321
|
instance->reKey(encryptionKey);
|
|
280
322
|
} else {
|
|
323
|
+
// Invalid argument (maybe object?)
|
|
281
324
|
throw jsi::JSError(
|
|
282
325
|
runtime,
|
|
283
326
|
"First argument ('encryptionKey') has to be of type string (or undefined)!");
|
|
284
327
|
}
|
|
328
|
+
|
|
285
329
|
return jsi::Value::undefined();
|
|
286
330
|
});
|
|
287
331
|
}
|
|
288
332
|
|
|
333
|
+
if (propName == "trim") {
|
|
334
|
+
// MMKV.trim()
|
|
335
|
+
return jsi::Function::createFromHostFunction(
|
|
336
|
+
runtime, jsi::PropNameID::forAscii(runtime, funcName), 0,
|
|
337
|
+
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
338
|
+
size_t count) -> jsi::Value {
|
|
339
|
+
instance->clearMemoryCache();
|
|
340
|
+
instance->trim();
|
|
341
|
+
|
|
342
|
+
return jsi::Value::undefined();
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (propName == "size") {
|
|
347
|
+
// MMKV.size
|
|
348
|
+
size_t size = instance->actualSize();
|
|
349
|
+
return jsi::Value(static_cast<int>(size));
|
|
350
|
+
}
|
|
351
|
+
|
|
289
352
|
return jsi::Value::undefined();
|
|
290
353
|
}
|
|
@@ -8,19 +8,25 @@
|
|
|
8
8
|
|
|
9
9
|
#pragma once
|
|
10
10
|
|
|
11
|
-
#include
|
|
11
|
+
#include "MMKV.h"
|
|
12
|
+
#include "NativeMmkvModule.h"
|
|
12
13
|
#include <jsi/jsi.h>
|
|
13
14
|
|
|
14
15
|
using namespace facebook;
|
|
16
|
+
using namespace mmkv;
|
|
15
17
|
|
|
16
|
-
class
|
|
18
|
+
class MmkvHostObject : public jsi::HostObject {
|
|
17
19
|
public:
|
|
18
|
-
MmkvHostObject(const
|
|
20
|
+
MmkvHostObject(const facebook::react::MMKVConfig& config);
|
|
21
|
+
~MmkvHostObject();
|
|
19
22
|
|
|
20
23
|
public:
|
|
21
24
|
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
|
|
22
25
|
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
|
|
23
26
|
|
|
27
|
+
private:
|
|
28
|
+
static MMKVMode getMMKVMode(const facebook::react::MMKVConfig& config);
|
|
29
|
+
|
|
24
30
|
private:
|
|
25
31
|
MMKV* instance;
|
|
26
32
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NativeMmkvModule.cpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.2024.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "NativeMmkvModule.h"
|
|
9
|
+
#include "Logger.h"
|
|
10
|
+
#include "MMKV.h"
|
|
11
|
+
#include "MmkvHostObject.h"
|
|
12
|
+
|
|
13
|
+
namespace facebook::react {
|
|
14
|
+
|
|
15
|
+
NativeMmkvModule::NativeMmkvModule(std::shared_ptr<CallInvoker> jsInvoker)
|
|
16
|
+
: NativeMmkvCxxSpec(jsInvoker) {}
|
|
17
|
+
|
|
18
|
+
bool NativeMmkvModule::initialize(jsi::Runtime& runtime, std::string basePath) {
|
|
19
|
+
if (basePath.size() < 1) {
|
|
20
|
+
throw jsi::JSError(runtime, "Path cannot be empty!");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Logger::log("RNMMKV", "Initializing MMKV at %s...", basePath.c_str());
|
|
24
|
+
|
|
25
|
+
#ifdef DEBUG
|
|
26
|
+
MMKVLogLevel logLevel = MMKVLogDebug;
|
|
27
|
+
#else
|
|
28
|
+
MMKVLogLevel logLevel = MMKVLogWarning;
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
MMKV::initializeMMKV(basePath, logLevel);
|
|
32
|
+
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
NativeMmkvModule::~NativeMmkvModule() {
|
|
37
|
+
Logger::log("RNMMKV", "Closing all MMKV instances...");
|
|
38
|
+
MMKV::onExit();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
jsi::Object NativeMmkvModule::createMMKV(jsi::Runtime& runtime, MMKVConfig config) {
|
|
42
|
+
auto instance = std::make_shared<MmkvHostObject>(config);
|
|
43
|
+
return jsi::Object::createFromHostObject(runtime, instance);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NativeMmkvModule.h
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.2024.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<React-Codegen/RNMmkvSpecJSI.h>)
|
|
11
|
+
// CocoaPods include (iOS)
|
|
12
|
+
#include <React-Codegen/RNMmkvSpecJSI.h>
|
|
13
|
+
#elif __has_include(<RNMmkvSpecJSI.h>)
|
|
14
|
+
// CMake include on Android
|
|
15
|
+
#include <RNMmkvSpecJSI.h>
|
|
16
|
+
#else
|
|
17
|
+
#error Cannot find react-native-mmkv spec! Try cleaning your cache and re-running CodeGen!
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
namespace facebook::react {
|
|
21
|
+
|
|
22
|
+
// The MMKVConfiguration type from JS
|
|
23
|
+
using MMKVConfig = MmkvCxxConfiguration<std::string, std::optional<std::string>,
|
|
24
|
+
std::optional<std::string>, std::optional<MmkvCxxMode>>;
|
|
25
|
+
template <> struct Bridging<MMKVConfig> : MmkvCxxConfigurationBridging<MMKVConfig> {};
|
|
26
|
+
|
|
27
|
+
// The TurboModule itself
|
|
28
|
+
class NativeMmkvModule : public NativeMmkvCxxSpec<NativeMmkvModule> {
|
|
29
|
+
public:
|
|
30
|
+
NativeMmkvModule(std::shared_ptr<CallInvoker> jsInvoker);
|
|
31
|
+
~NativeMmkvModule();
|
|
32
|
+
|
|
33
|
+
bool initialize(jsi::Runtime& runtime, std::string basePath);
|
|
34
|
+
jsi::Object createMMKV(jsi::Runtime& runtime, MMKVConfig config);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AppleLogger.m
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "Logger.h"
|
|
9
|
+
#import <Foundation/Foundation.h>
|
|
10
|
+
|
|
11
|
+
void Logger::log(const std::string& tag, const std::string& message) {
|
|
12
|
+
#pragma clang diagnostic push
|
|
13
|
+
#pragma clang diagnostic ignored "-Wformat-security"
|
|
14
|
+
NSLog(@"[%s]: %s", tag.c_str(), message.c_str());
|
|
15
|
+
#pragma clang diagnostic pop
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MmkvOnLoad.mm
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 27.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "NativeMmkvModule.h"
|
|
9
|
+
#import <Foundation/Foundation.h>
|
|
10
|
+
#import <ReactCommon/CxxTurboModuleUtils.h>
|
|
11
|
+
|
|
12
|
+
@interface MMKVOnLoad : NSObject
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
@implementation MMKVOnLoad
|
|
16
|
+
|
|
17
|
+
+ (void)load {
|
|
18
|
+
facebook::react::registerCxxModuleToGlobalModuleMap(
|
|
19
|
+
std::string(facebook::react::NativeMmkvModule::kModuleName),
|
|
20
|
+
[&](std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
|
|
21
|
+
return std::make_shared<facebook::react::NativeMmkvModule>(jsInvoker);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RTNMmkvPlatformContext.h
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 27.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#import <Foundation/Foundation.h>
|
|
11
|
+
#import <RNMmkvSpec/RNMmkvSpec.h>
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
14
|
+
|
|
15
|
+
@interface MmkvPlatformContext : NSObject <NativeMmkvPlatformContextSpec>
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AppleMmkvPlatformContext.m
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "MmkvPlatformContext.h"
|
|
9
|
+
#import <Foundation/Foundation.h>
|
|
10
|
+
|
|
11
|
+
@implementation MmkvPlatformContext
|
|
12
|
+
|
|
13
|
+
RCT_EXPORT_MODULE()
|
|
14
|
+
|
|
15
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
16
|
+
(const facebook::react::ObjCTurboModule::InitParams&)params {
|
|
17
|
+
return std::make_shared<facebook::react::NativeMmkvPlatformContextSpecJSI>(params);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
- (NSString*)getBaseDirectory {
|
|
21
|
+
#if TARGET_OS_TV
|
|
22
|
+
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
|
23
|
+
#else
|
|
24
|
+
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
25
|
+
#endif
|
|
26
|
+
NSString* documentPath = (NSString*)[paths firstObject];
|
|
27
|
+
if ([documentPath length] > 0) {
|
|
28
|
+
NSString* basePath = [documentPath stringByAppendingPathComponent:@"mmkv"];
|
|
29
|
+
return basePath;
|
|
30
|
+
} else {
|
|
31
|
+
@throw [NSException exceptionWithName:@"BasePathNotFound"
|
|
32
|
+
reason:@"Cannot find base-path to store MMKV files!"
|
|
33
|
+
userInfo:nil];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getLazyTurboModule = getLazyTurboModule;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
/**
|
|
9
|
+
* Lazily get a TurboModule by wrapping it in a Proxy.
|
|
10
|
+
*/
|
|
11
|
+
function getLazyTurboModule(initializeTurboModule) {
|
|
12
|
+
const proxy = new Proxy({
|
|
13
|
+
module: null
|
|
14
|
+
}, {
|
|
15
|
+
get: (target, property) => {
|
|
16
|
+
if (target.module == null) {
|
|
17
|
+
// Target is null, let's initialize it!
|
|
18
|
+
target.module = initializeTurboModule();
|
|
19
|
+
if (target.module == null) {
|
|
20
|
+
// TurboModule not found, something went wrong!
|
|
21
|
+
let message = 'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
|
|
22
|
+
message += '\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
|
|
23
|
+
if (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'macos') {
|
|
24
|
+
message += '\n* Make sure you ran `pod install` in the ios/ directory.';
|
|
25
|
+
}
|
|
26
|
+
if (_reactNative.Platform.OS === 'android') {
|
|
27
|
+
message += '\n* Make sure gradle is synced.';
|
|
28
|
+
}
|
|
29
|
+
// check if Expo
|
|
30
|
+
const ExpoConstants = _reactNative.NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;
|
|
31
|
+
if (ExpoConstants != null) {
|
|
32
|
+
if (ExpoConstants.appOwnership === 'expo') {
|
|
33
|
+
// We're running Expo Go
|
|
34
|
+
throw new Error('react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.');
|
|
35
|
+
} else {
|
|
36
|
+
// We're running Expo bare / standalone
|
|
37
|
+
message += '\n* Make sure you ran `expo prebuild`.';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
message += '\n* Make sure you rebuilt the app.';
|
|
41
|
+
throw new Error(message);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return target.module[property];
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return proxy;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=LazyTurboModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","getLazyTurboModule","initializeTurboModule","proxy","Proxy","module","get","target","property","message","Platform","OS","ExpoConstants","NativeModules","NativeUnimoduleProxy","modulesConstants","ExponentConstants","appOwnership","Error"],"sourceRoot":"../../src","sources":["LazyTurboModule.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAMA;AACA;AACA;AACO,SAASC,kBAAkBA,CAChCC,qBAAqC,EAClC;EACH,MAAMC,KAAK,GAAG,IAAIC,KAAK,CACrB;IACEC,MAAM,EAAE;EACV,CAAC,EACD;IACEC,GAAG,EAAEA,CAACC,MAAM,EAAEC,QAAQ,KAAK;MACzB,IAAID,MAAM,CAACF,MAAM,IAAI,IAAI,EAAE;QACzB;QACAE,MAAM,CAACF,MAAM,GAAGH,qBAAqB,CAAC,CAAC;QAEvC,IAAIK,MAAM,CAACF,MAAM,IAAI,IAAI,EAAE;UACzB;UACA,IAAII,OAAO,GACT,kFAAkF;UACpFA,OAAO,IACL,mGAAmG;UACrG,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,IAAID,qBAAQ,CAACC,EAAE,KAAK,OAAO,EAAE;YACpDF,OAAO,IACL,4DAA4D;UAChE;UACA,IAAIC,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;YAC7BF,OAAO,IAAI,iCAAiC;UAC9C;UACA;UACA,MAAMG,aAAa,GACjBC,0BAAa,CAACC,oBAAoB,EAAEC,gBAAgB,EAChDC,iBAAiB;UACvB,IAAIJ,aAAa,IAAI,IAAI,EAAE;YACzB,IAAIA,aAAa,CAACK,YAAY,KAAK,MAAM,EAAE;cACzC;cACA,MAAM,IAAIC,KAAK,CACb,+GACF,CAAC;YACH,CAAC,MAAM;cACL;cACAT,OAAO,IAAI,wCAAwC;YACrD;UACF;UAEAA,OAAO,IAAI,oCAAoC;UAC/C,MAAM,IAAIS,KAAK,CAACT,OAAO,CAAC;QAC1B;MACF;MAEA,OAAOF,MAAM,CAACF,MAAM,CAACG,QAAQ,CAAY;IAC3C;EACF,CACF,CAAC;EACD,OAAOL,KAAK;AACd","ignoreList":[]}
|