Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiProcess mode on Android #611

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,13 @@ See [Configuring App Groups](https://developer.apple.com/documentation/xcode/con
#### Customize

```js
import { MMKV } from 'react-native-mmkv'
import { MMKV, MMKVMode } from 'react-native-mmkv'

export const storage = new MMKV({
id: `user-${userId}-storage`,
path: `${USER_DIRECTORY}/storage`,
encryptionKey: 'hunter2'
encryptionKey: 'hunter2',
mode: 'single-process'
})
```

Expand All @@ -124,6 +125,8 @@ The following values can be configured:
* `id`: The MMKV instance's ID. If you want to use multiple instances, use different IDs. For example, you can separate the global app's storage and a logged-in user's storage. (required if `path` or `encryptionKey` fields are specified, otherwise defaults to: `'mmkv.default'`)
* `path`: The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization (documentation: [iOS](https://github.com/Tencent/MMKV/wiki/iOS_advance#customize-location) / [Android](https://github.com/Tencent/MMKV/wiki/android_advance#customize-location))
* `encryptionKey`: The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's/Android's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV. (documentation: [iOS](https://github.com/Tencent/MMKV/wiki/iOS_advance#encryption) / [Android](https://github.com/Tencent/MMKV/wiki/android_advance#encryption))
* `mode`: *Android Only*: The MMKV mode. It is set to `single-process` by default. You can set its value to `multi-process` to support simultaneous read-write access between processus at the cost of performance. This is useful when you want to share data between your react-native app and native extensions such as widgets. _Notice_: On iOS, this will automatically be set to `multi-process` if you set an AppGroup in the plist configuration (more information on AppGroups [here](https://github.com/mrousavy/react-native-mmkv/tree/master#app-groups))


### Set

Expand Down
4 changes: 2 additions & 2 deletions android/src/main/cpp/MmkvHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
#include <vector>

MmkvHostObject::MmkvHostObject(const std::string& instanceId, std::string path,
std::string cryptKey) {
std::string cryptKey, MMKVMode mmkvMode) {
bool hasEncryptionKey = cryptKey.size() > 0;
__android_log_print(ANDROID_LOG_INFO, "RNMMKV",
"Creating MMKV instance \"%s\"... (Path: %s, Encrypted: %b)",
instanceId.c_str(), path.c_str(), hasEncryptionKey);
std::string* pathPtr = path.size() > 0 ? &path : nullptr;
std::string* cryptKeyPtr = cryptKey.size() > 0 ? &cryptKey : nullptr;
instance = MMKV::mmkvWithID(instanceId, mmkv::DEFAULT_MMAP_SIZE, MMKV_SINGLE_PROCESS, cryptKeyPtr,
instance = MMKV::mmkvWithID(instanceId, mmkv::DEFAULT_MMAP_SIZE, mmkvMode, cryptKeyPtr,
pathPtr);

if (instance == nullptr) {
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/cpp/MmkvHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using namespace facebook;

class JSI_EXPORT MmkvHostObject : public jsi::HostObject {
public:
MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey);
MmkvHostObject(const std::string& instanceId, std::string path, std::string cryptKey, MMKVMode mmkvMode);

public:
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
Expand Down
16 changes: 15 additions & 1 deletion android/src/main/cpp/cpp-adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ std::string getPropertyAsStringOrEmptyFromObject(jsi::Object& object,
return value.isString() ? value.asString(runtime).utf8(runtime) : "";
}

const std::string MMKV_MULTI_PROCESS_MODE = "multi-process";
MMKVMode getPropertyAsMMKVModeFromObject(jsi::Object& object,
const std::string& propertyName,
jsi::Runtime& runtime) {
std::string value = getPropertyAsStringOrEmptyFromObject(object, propertyName, runtime);
if (value == MMKV_MULTI_PROCESS_MODE) {
return MMKV_MULTI_PROCESS;
}

// Use Single Process as default value
return MMKV_SINGLE_PROCESS;
}

void install(jsi::Runtime& jsiRuntime) {
// MMKV.createNewInstance()
auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(
Expand All @@ -28,8 +41,9 @@ void install(jsi::Runtime& jsiRuntime) {
std::string path = getPropertyAsStringOrEmptyFromObject(config, "path", runtime);
std::string encryptionKey =
getPropertyAsStringOrEmptyFromObject(config, "encryptionKey", runtime);
MMKVMode mode = getPropertyAsMMKVModeFromObject(config, "mode", runtime);

auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey, mode);
return jsi::Object::createFromHostObject(runtime, instance);
});
jsiRuntime.global().setProperty(jsiRuntime, "mmkvCreateNewInstance",
Expand Down
14 changes: 14 additions & 0 deletions src/MMKV.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ export interface MMKVConfiguration {
* ```
*/
encryptionKey?: string;
/**
* *Android Only*: The MMKV mode. It is set to `single-process` by default. You can set its value to `multi-process` to support simultaneous read-write access between processus at the cost of performance.
*
* This is useful when you want to share data between your react-native app and native extensions such as widgets.
*
* @example
* ```ts
* const extensionStorage = new MMKV({ id: 'mmkv.default', mode: 'multi-process' })
* ```
*
* _Notice_: On iOS, this will automatically be set to `multi-process` if you set an AppGroup in the plist configuration.
* More information on AppGroups [here](https://github.com/mrousavy/react-native-mmkv/tree/master#app-groups)
*/
mode?: 'single-process' | 'multi-process';
}

/**
Expand Down