react-native-mmkv 2.12.1 → 3.0.0-beta.1
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 +7 -1
- 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 +37 -0
- package/{android/src/main/cpp → cpp}/MmkvHostObject.cpp +126 -63
- package/{android/src/main/cpp → cpp}/MmkvHostObject.h +14 -3
- package/cpp/NativeMmkvModule.cpp +40 -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/MMKV.js +34 -4
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/NativeMmkv.js +66 -0
- package/lib/commonjs/NativeMmkv.js.map +1 -0
- package/lib/commonjs/NativeMmkvPlatformContext.js +9 -0
- package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -0
- package/lib/commonjs/PlatformChecker.js.map +1 -1
- package/lib/commonjs/createMMKV.js +7 -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/MMKV.js +23 -4
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/NativeMmkv.js +63 -0
- package/lib/module/NativeMmkv.js.map +1 -0
- package/lib/module/NativeMmkvPlatformContext.js +3 -0
- package/lib/module/NativeMmkvPlatformContext.js.map +1 -0
- package/lib/module/PlatformChecker.js.map +1 -1
- package/lib/module/createMMKV.js +7 -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/{MMKV.d.ts → src/MMKV.d.ts} +26 -49
- package/lib/typescript/src/MMKV.d.ts.map +1 -0
- package/lib/typescript/src/NativeMmkv.d.ts +79 -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/__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 +3 -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 +3 -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 +49 -40
- package/react-native-mmkv.podspec +17 -14
- package/src/MMKV.ts +40 -62
- package/src/NativeMmkv.ts +132 -0
- package/src/NativeMmkvPlatformContext.ts +12 -0
- package/src/__tests__/hooks.test.tsx +88 -0
- package/src/createMMKV.mock.ts +7 -3
- package/src/createMMKV.ts +9 -63
- package/src/createMMKV.web.ts +6 -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.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
- /package/src/{index.ts → index.tsx} +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<manifest
|
|
2
|
-
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.mrousavy.mmkv">
|
|
3
3
|
</manifest>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AndroidLogger.cpp
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 05.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "Logger.h"
|
|
9
|
+
#include <android/log.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
|
+
__android_log_print(ANDROID_LOG_INFO, tag.c_str(), message.c_str());
|
|
15
|
+
#pragma clang diagnostic pop
|
|
16
|
+
}
|
|
@@ -1,83 +1,7 @@
|
|
|
1
|
-
#include "MmkvHostObject.h"
|
|
2
|
-
#include "TypedArray.h"
|
|
3
|
-
#include <MMKV.h>
|
|
4
1
|
#include <jni.h>
|
|
5
|
-
#include <jsi/jsi.h>
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
jsi::Runtime& runtime) {
|
|
12
|
-
jsi::Value value = object.getProperty(runtime, propertyName.c_str());
|
|
13
|
-
return value.isString() ? value.asString(runtime).utf8(runtime) : "";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
void install(jsi::Runtime& jsiRuntime) {
|
|
17
|
-
// MMKV.createNewInstance()
|
|
18
|
-
auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(
|
|
19
|
-
jsiRuntime, jsi::PropNameID::forAscii(jsiRuntime, "mmkvCreateNewInstance"), 1,
|
|
20
|
-
[](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
|
|
21
|
-
size_t count) -> jsi::Value {
|
|
22
|
-
if (count != 1) {
|
|
23
|
-
throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
|
|
24
|
-
}
|
|
25
|
-
jsi::Object config = arguments[0].asObject(runtime);
|
|
26
|
-
|
|
27
|
-
std::string instanceId = getPropertyAsStringOrEmptyFromObject(config, "id", runtime);
|
|
28
|
-
std::string path = getPropertyAsStringOrEmptyFromObject(config, "path", runtime);
|
|
29
|
-
std::string encryptionKey =
|
|
30
|
-
getPropertyAsStringOrEmptyFromObject(config, "encryptionKey", runtime);
|
|
31
|
-
|
|
32
|
-
auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
|
|
33
|
-
return jsi::Object::createFromHostObject(runtime, instance);
|
|
34
|
-
});
|
|
35
|
-
jsiRuntime.global().setProperty(jsiRuntime, "mmkvCreateNewInstance",
|
|
36
|
-
std::move(mmkvCreateNewInstance));
|
|
37
|
-
|
|
38
|
-
// Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets
|
|
39
|
-
// destroyed and the cache gets invalidated.
|
|
40
|
-
auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(jsiRuntime);
|
|
41
|
-
jsiRuntime.global().setProperty(jsiRuntime, "mmkvArrayBufferPropNameIdCache",
|
|
42
|
-
jsi::Object::createFromHostObject(jsiRuntime, propNameIdCache));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
std::string jstringToStdString(JNIEnv* env, jstring jStr) {
|
|
46
|
-
if (!jStr)
|
|
47
|
-
return "";
|
|
48
|
-
|
|
49
|
-
const auto stringClass = env->GetObjectClass(jStr);
|
|
50
|
-
const auto getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
|
|
51
|
-
const auto stringJbytes =
|
|
52
|
-
(jbyteArray)env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));
|
|
53
|
-
|
|
54
|
-
auto length = (size_t)env->GetArrayLength(stringJbytes);
|
|
55
|
-
auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr);
|
|
56
|
-
|
|
57
|
-
std::string ret = std::string((char*)pBytes, length);
|
|
58
|
-
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
|
|
59
|
-
|
|
60
|
-
env->DeleteLocalRef(stringJbytes);
|
|
61
|
-
env->DeleteLocalRef(stringClass);
|
|
62
|
-
return ret;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
extern "C" JNIEXPORT void JNICALL Java_com_reactnativemmkv_MmkvModule_nativeInstall(JNIEnv* env,
|
|
66
|
-
jobject clazz,
|
|
67
|
-
jlong jsiPtr,
|
|
68
|
-
jstring path) {
|
|
69
|
-
#if DEBUG
|
|
70
|
-
MMKVLogLevel logLevel = MMKVLogDebug;
|
|
71
|
-
#else
|
|
72
|
-
MMKVLogLevel logLevel = MMKVLogError;
|
|
73
|
-
#endif
|
|
74
|
-
std::string storageDirectory = jstringToStdString(env, path);
|
|
75
|
-
MMKV::initializeMMKV(storageDirectory, logLevel);
|
|
76
|
-
|
|
77
|
-
auto runtime = reinterpret_cast<jsi::Runtime*>(jsiPtr);
|
|
78
|
-
if (runtime) {
|
|
79
|
-
install(*runtime);
|
|
80
|
-
}
|
|
81
|
-
// if runtime was nullptr, MMKV will not be installed. This should only happen while Remote
|
|
82
|
-
// Debugging (Chrome), but will be weird either way.
|
|
3
|
+
extern "C" JNIEXPORT jdouble JNICALL Java_com_mmkv_MmkvModule_nativeMultiply(JNIEnv* env,
|
|
4
|
+
jclass type, jdouble a,
|
|
5
|
+
jdouble b) {
|
|
6
|
+
return 5.0;
|
|
83
7
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.mrousavy.mmkv;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
import com.facebook.react.bridge.NativeModule;
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
+
import com.facebook.react.module.model.ReactModuleInfo;
|
|
9
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
10
|
+
import com.facebook.react.TurboReactPackage;
|
|
11
|
+
|
|
12
|
+
import java.util.HashMap;
|
|
13
|
+
import java.util.Map;
|
|
14
|
+
|
|
15
|
+
public class MmkvPackage extends TurboReactPackage {
|
|
16
|
+
@Nullable
|
|
17
|
+
@Override
|
|
18
|
+
public NativeModule getModule(String name, @NonNull ReactApplicationContext reactContext) {
|
|
19
|
+
if (name.equals(MmkvPlatformContextModule.NAME)) {
|
|
20
|
+
return new MmkvPlatformContextModule(reactContext);
|
|
21
|
+
} else {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Override
|
|
27
|
+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
|
|
28
|
+
return () -> {
|
|
29
|
+
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
|
|
30
|
+
moduleInfos.put(
|
|
31
|
+
MmkvPlatformContextModule.NAME,
|
|
32
|
+
new ReactModuleInfo(
|
|
33
|
+
MmkvPlatformContextModule.NAME,
|
|
34
|
+
MmkvPlatformContextModule.NAME,
|
|
35
|
+
false, // canOverrideExistingModule
|
|
36
|
+
false, // needsEagerInit
|
|
37
|
+
true, // hasConstants
|
|
38
|
+
false, // isCxxModule
|
|
39
|
+
true // isTurboModule
|
|
40
|
+
));
|
|
41
|
+
return moduleInfos;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.mrousavy.mmkv;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
|
|
5
|
+
public class MmkvPlatformContextModule extends NativeMmkvPlatformContextSpec {
|
|
6
|
+
private final ReactApplicationContext context;
|
|
7
|
+
|
|
8
|
+
public MmkvPlatformContextModule(ReactApplicationContext reactContext) {
|
|
9
|
+
super(reactContext);
|
|
10
|
+
context = reactContext;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Override
|
|
14
|
+
public String getBaseDirectory() {
|
|
15
|
+
return context.getFilesDir().getAbsolutePath() + "/mmkv";
|
|
16
|
+
}
|
|
17
|
+
}
|
package/cpp/Logger.h
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Logger.h
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
class Logger {
|
|
11
|
+
private:
|
|
12
|
+
Logger() = delete;
|
|
13
|
+
|
|
14
|
+
private:
|
|
15
|
+
template <typename... Args>
|
|
16
|
+
static std::string string_format(const std::string& format, Args... args) {
|
|
17
|
+
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
|
18
|
+
if (size_s <= 0) {
|
|
19
|
+
throw std::runtime_error("Failed to format string!");
|
|
20
|
+
}
|
|
21
|
+
auto size = static_cast<size_t>(size_s);
|
|
22
|
+
std::unique_ptr<char[]> buf(new char[size]);
|
|
23
|
+
std::snprintf(buf.get(), size, format.c_str(), args...);
|
|
24
|
+
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public:
|
|
28
|
+
static void log(const std::string& tag, const std::string& message);
|
|
29
|
+
|
|
30
|
+
template <typename... Args>
|
|
31
|
+
inline static void log(const std::string& tag, const std::string& formatString, Args&&... args) {
|
|
32
|
+
std::string formattedString = string_format(formatString, std::forward<Args>(args)...);
|
|
33
|
+
log(tag, formattedString);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ManagedBuffer.h
|
|
3
|
+
// react-native-mmkv
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 25.03.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <jsi/jsi.h>
|
|
11
|
+
|
|
12
|
+
#if __has_include("MMKVManagedBuffer.h")
|
|
13
|
+
#include "MMKVManagedBuffer.h"
|
|
14
|
+
#else
|
|
15
|
+
#include <MMKVCore/MMKVManagedBuffer.h>
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
using namespace facebook;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
A jsi::MutableBuffer that manages mmkv::MMBuffer memory (by ownership).
|
|
22
|
+
*/
|
|
23
|
+
class MMKVManagedBuffer : public jsi::MutableBuffer {
|
|
24
|
+
public:
|
|
25
|
+
explicit MMKVManagedBuffer(mmkv::MMBuffer&& buffer) : _buffer(std::move(buffer)) {}
|
|
26
|
+
|
|
27
|
+
uint8_t* data() override {
|
|
28
|
+
return static_cast<uint8_t*>(_buffer.getPtr());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
size_t size() const override {
|
|
32
|
+
return _buffer.length();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private:
|
|
36
|
+
mmkv::MMBuffer _buffer;
|
|
37
|
+
};
|
|
@@ -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,30 @@
|
|
|
8
8
|
|
|
9
9
|
#pragma once
|
|
10
10
|
|
|
11
|
-
#include
|
|
11
|
+
#include "NativeMmkvModule.h"
|
|
12
12
|
#include <jsi/jsi.h>
|
|
13
13
|
|
|
14
|
+
#if __has_include("MMKV.h")
|
|
15
|
+
#include "MMKV.h"
|
|
16
|
+
#else
|
|
17
|
+
#include <MMKVCore/MMKV.h>
|
|
18
|
+
#endif
|
|
19
|
+
|
|
14
20
|
using namespace facebook;
|
|
21
|
+
using namespace mmkv;
|
|
15
22
|
|
|
16
|
-
class
|
|
23
|
+
class MmkvHostObject : public jsi::HostObject {
|
|
17
24
|
public:
|
|
18
|
-
MmkvHostObject(const
|
|
25
|
+
MmkvHostObject(const facebook::react::MMKVConfig& config);
|
|
26
|
+
~MmkvHostObject();
|
|
19
27
|
|
|
20
28
|
public:
|
|
21
29
|
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
|
|
22
30
|
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
|
|
23
31
|
|
|
32
|
+
private:
|
|
33
|
+
static MMKVMode getMMKVMode(const facebook::react::MMKVConfig& config);
|
|
34
|
+
|
|
24
35
|
private:
|
|
25
36
|
MMKV* instance;
|
|
26
37
|
};
|