react-native-mmkv 2.12.2 → 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 -18
- 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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NativeModules, Platform, TurboModule } from 'react-native';
|
|
2
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
3
|
+
import { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
|
|
4
|
+
import { PlatformContext } from './NativeMmkvPlatformContext';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configures the mode of the MMKV instance.
|
|
8
|
+
*/
|
|
9
|
+
export enum Mode {
|
|
10
|
+
/**
|
|
11
|
+
* The MMKV instance is only used from a single process (this app).
|
|
12
|
+
*/
|
|
13
|
+
SINGLE_PROCESS,
|
|
14
|
+
/**
|
|
15
|
+
* The MMKV instance may be used from multiple processes, such as app clips, share extensions or background services.
|
|
16
|
+
*/
|
|
17
|
+
MULTI_PROCESS,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Used for configuration of a single MMKV instance.
|
|
22
|
+
*/
|
|
23
|
+
export interface Configuration {
|
|
24
|
+
/**
|
|
25
|
+
* The MMKV instance's ID. If you want to use multiple instances, make sure to use different IDs!
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const userStorage = new MMKV({ id: `user-${userId}-storage` })
|
|
30
|
+
* const globalStorage = new MMKV({ id: 'global-app-storage' })
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @default 'mmkv.default'
|
|
34
|
+
*/
|
|
35
|
+
id: string;
|
|
36
|
+
/**
|
|
37
|
+
* The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization:
|
|
38
|
+
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const temporaryStorage = new MMKV({ path: '/tmp/' })
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* _Notice_: On iOS you can set the AppGroup bundle property to share the same storage between your app and its extensions.
|
|
45
|
+
* In this case `path` property will be ignored.
|
|
46
|
+
* See more on MMKV configuration [here](https://github.com/Tencent/MMKV/wiki/iOS_tutorial#configuration).
|
|
47
|
+
*
|
|
48
|
+
* @default undefined
|
|
49
|
+
*/
|
|
50
|
+
path?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.
|
|
53
|
+
*
|
|
54
|
+
* Encryption keys can have a maximum length of 16 bytes.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const secureStorage = new MMKV({ encryptionKey: 'my-encryption-key!' })
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @default undefined
|
|
62
|
+
*/
|
|
63
|
+
encryptionKey?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Configure the processing mode for MMKV.
|
|
66
|
+
* - `SINGLE_PROCESS`: The MMKV instance is only used from a single process (this app).
|
|
67
|
+
* - `MULTI_PROCESS`: The MMKV instance may be used from multiple processes, such as app clips, share extensions or background services.
|
|
68
|
+
*
|
|
69
|
+
* @default SINGLE_PROCESS
|
|
70
|
+
*/
|
|
71
|
+
mode?: Mode;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Spec extends TurboModule {
|
|
75
|
+
initialize(basePath: string): boolean;
|
|
76
|
+
createMMKV(configuration: Configuration): UnsafeObject;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let module: Spec | null = null;
|
|
80
|
+
let basePath: string | null = null;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the MMKV TurboModule, and initialize it if this is the first time calling.
|
|
84
|
+
* This will throw an error if the module cannot be found.
|
|
85
|
+
*/
|
|
86
|
+
export function getMMKVTurboModule(): Spec {
|
|
87
|
+
if (module == null) {
|
|
88
|
+
// try to find the turbomodule
|
|
89
|
+
module = TurboModuleRegistry.get<Spec>('MmkvCxx');
|
|
90
|
+
|
|
91
|
+
if (module == null) {
|
|
92
|
+
// if it still is null, something went wrong!
|
|
93
|
+
let message =
|
|
94
|
+
'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
|
|
95
|
+
message +=
|
|
96
|
+
'\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
|
|
97
|
+
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
|
98
|
+
message += '\n* Make sure you ran `pod install` in the ios/ directory.';
|
|
99
|
+
}
|
|
100
|
+
if (Platform.OS === 'android') {
|
|
101
|
+
message += '\n* Make sure gradle is synced.';
|
|
102
|
+
}
|
|
103
|
+
// check if Expo
|
|
104
|
+
const ExpoConstants =
|
|
105
|
+
NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;
|
|
106
|
+
if (ExpoConstants != null) {
|
|
107
|
+
if (ExpoConstants.appOwnership === 'expo') {
|
|
108
|
+
// We're running Expo Go
|
|
109
|
+
throw new Error(
|
|
110
|
+
'react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.'
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
// We're running Expo bare / standalone
|
|
114
|
+
message += '\n* Make sure you ran `expo prebuild`.';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
message += '\n* Make sure you rebuilt the app.';
|
|
119
|
+
throw new Error(message);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (basePath == null) {
|
|
123
|
+
// Get base path from platform specific context
|
|
124
|
+
basePath = PlatformContext.getBaseDirectory();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Initialize MMKV
|
|
128
|
+
module.initialize(basePath);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return module;
|
|
132
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TurboModule, TurboModuleRegistry } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface Spec extends TurboModule {
|
|
4
|
+
/**
|
|
5
|
+
* Gets the base directory of the documents storage
|
|
6
|
+
*/
|
|
7
|
+
getBaseDirectory(): string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const PlatformContext = TurboModuleRegistry.getEnforcing<Spec>(
|
|
11
|
+
'MmkvPlatformContext'
|
|
12
|
+
);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button, Text } from 'react-native';
|
|
3
|
+
import {
|
|
4
|
+
act,
|
|
5
|
+
fireEvent,
|
|
6
|
+
render,
|
|
7
|
+
renderHook,
|
|
8
|
+
screen,
|
|
9
|
+
} from '@testing-library/react-native';
|
|
10
|
+
import { MMKV, useMMKVNumber, useMMKVString } from '..';
|
|
11
|
+
|
|
12
|
+
const mmkv = new MMKV();
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mmkv.clearAll();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('hooks update when the value is changed directly through the instance', () => {
|
|
19
|
+
const { result } = renderHook(() => useMMKVString('string-key', mmkv));
|
|
20
|
+
|
|
21
|
+
expect(result.current[0]).toBeUndefined();
|
|
22
|
+
|
|
23
|
+
// First, make a "normal" change
|
|
24
|
+
act(() => {
|
|
25
|
+
result.current[1]('value 1');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result.current[0]).toStrictEqual('value 1');
|
|
29
|
+
|
|
30
|
+
// Now, make the change directly through the instance.
|
|
31
|
+
act(() => {
|
|
32
|
+
mmkv.set('string-key', 'value 2');
|
|
33
|
+
});
|
|
34
|
+
expect(result.current[0]).toStrictEqual('value 2');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('functional updates to hooks', () => {
|
|
38
|
+
const Component: React.FC = () => {
|
|
39
|
+
const [state, setState] = React.useState(0);
|
|
40
|
+
const [value, setValue] = useMMKVNumber('number-key', mmkv);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<Button
|
|
45
|
+
testID="button"
|
|
46
|
+
title="Double Increment Me"
|
|
47
|
+
onPress={() => {
|
|
48
|
+
// Increment the state value twice, using the function form of useState.
|
|
49
|
+
setState((current) => current + 1);
|
|
50
|
+
setState((current) => current + 1);
|
|
51
|
+
|
|
52
|
+
// Increment the MMKV value twice, using the same function form.
|
|
53
|
+
setValue((current) => (current ?? 0) + 1);
|
|
54
|
+
setValue((current) => (current ?? 0) + 1);
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
<Text testID="state-value">State: {state.toString()}</Text>
|
|
58
|
+
<Text testID="mmkv-value">MMKV: {(value ?? 0).toString()}</Text>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
render(<Component />);
|
|
64
|
+
|
|
65
|
+
const button = screen.getByTestId('button');
|
|
66
|
+
|
|
67
|
+
// Why these assertions:
|
|
68
|
+
// https://github.com/mrousavy/react-native-mmkv/issues/599
|
|
69
|
+
fireEvent.press(button);
|
|
70
|
+
expect(screen.getByTestId('state-value').children).toStrictEqual([
|
|
71
|
+
'State: ',
|
|
72
|
+
'2',
|
|
73
|
+
]);
|
|
74
|
+
expect(screen.getByTestId('mmkv-value').children).toStrictEqual([
|
|
75
|
+
'MMKV: ',
|
|
76
|
+
'2',
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
fireEvent.press(button);
|
|
80
|
+
expect(screen.getByTestId('state-value').children).toStrictEqual([
|
|
81
|
+
'State: ',
|
|
82
|
+
'4',
|
|
83
|
+
]);
|
|
84
|
+
expect(screen.getByTestId('mmkv-value').children).toStrictEqual([
|
|
85
|
+
'MMKV: ',
|
|
86
|
+
'4',
|
|
87
|
+
]);
|
|
88
|
+
});
|
package/src/createMMKV.mock.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { NativeMMKV } from '
|
|
1
|
+
import type { NativeMMKV } from './MMKV';
|
|
2
2
|
|
|
3
3
|
/* Mock MMKV instance for use in tests */
|
|
4
4
|
export const createMockMMKV = (): NativeMMKV => {
|
|
5
|
-
const storage = new Map<string, string | boolean | number |
|
|
5
|
+
const storage = new Map<string, string | boolean | number | ArrayBuffer>();
|
|
6
6
|
|
|
7
7
|
return {
|
|
8
8
|
clearAll: () => storage.clear(),
|
|
@@ -22,12 +22,16 @@ export const createMockMMKV = (): NativeMMKV => {
|
|
|
22
22
|
},
|
|
23
23
|
getBuffer: (key) => {
|
|
24
24
|
const result = storage.get(key);
|
|
25
|
-
return result instanceof
|
|
25
|
+
return result instanceof ArrayBuffer ? result : undefined;
|
|
26
26
|
},
|
|
27
27
|
getAllKeys: () => Array.from(storage.keys()),
|
|
28
28
|
contains: (key) => storage.has(key),
|
|
29
29
|
recrypt: () => {
|
|
30
30
|
console.warn('Encryption is not supported in mocked MMKV instances!');
|
|
31
31
|
},
|
|
32
|
+
size: 0,
|
|
33
|
+
trim: () => {
|
|
34
|
+
// no-op
|
|
35
|
+
},
|
|
32
36
|
};
|
|
33
37
|
};
|
package/src/createMMKV.ts
CHANGED
|
@@ -1,70 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { Configuration, NativeMMKV } from './MMKV';
|
|
2
|
+
import { getMMKVTurboModule } from './NativeMmkv';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
declare global {
|
|
6
|
-
function mmkvCreateNewInstance(configuration: MMKVConfiguration): NativeMMKV;
|
|
7
|
-
function nativeCallSyncHook(): unknown;
|
|
8
|
-
}
|
|
4
|
+
const module = getMMKVTurboModule();
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// Check if the constructor exists. If not, try installing the JSI bindings.
|
|
15
|
-
if (global.mmkvCreateNewInstance == null) {
|
|
16
|
-
// Get the native MMKV ReactModule
|
|
17
|
-
const MMKVModule = NativeModules.MMKV;
|
|
18
|
-
if (MMKVModule == null) {
|
|
19
|
-
let message =
|
|
20
|
-
'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
|
|
21
|
-
message +=
|
|
22
|
-
'\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
|
|
23
|
-
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
|
24
|
-
message += '\n* Make sure you ran `pod install` in the ios/ directory.';
|
|
25
|
-
}
|
|
26
|
-
if (Platform.OS === 'android') {
|
|
27
|
-
message += '\n* Make sure gradle is synced.';
|
|
28
|
-
}
|
|
29
|
-
// check if Expo
|
|
30
|
-
const ExpoConstants =
|
|
31
|
-
NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;
|
|
32
|
-
if (ExpoConstants != null) {
|
|
33
|
-
if (ExpoConstants.appOwnership === 'expo') {
|
|
34
|
-
// We're running Expo Go
|
|
35
|
-
throw new Error(
|
|
36
|
-
'react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.'
|
|
37
|
-
);
|
|
38
|
-
} else {
|
|
39
|
-
// We're running Expo bare / standalone
|
|
40
|
-
message += '\n* Make sure you ran `expo prebuild`.';
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
message += '\n* Make sure you rebuilt the app.';
|
|
45
|
-
throw new Error(message);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Check if we are running on-device (JSI)
|
|
49
|
-
if (global.nativeCallSyncHook == null || MMKVModule.install == null) {
|
|
6
|
+
export const createMMKV = (config: Configuration): NativeMMKV => {
|
|
7
|
+
const instance = module.createMMKV(config);
|
|
8
|
+
if (__DEV__) {
|
|
9
|
+
if (typeof instance !== 'object' || instance == null) {
|
|
50
10
|
throw new Error(
|
|
51
|
-
'Failed to create
|
|
11
|
+
'Failed to create MMKV instance - an unknown object was returned by createMMKV(..)!'
|
|
52
12
|
);
|
|
53
13
|
}
|
|
54
|
-
|
|
55
|
-
// Call the synchronous blocking install() function
|
|
56
|
-
const result = MMKVModule.install(ROOT_DIRECTORY);
|
|
57
|
-
if (result !== true)
|
|
58
|
-
throw new Error(
|
|
59
|
-
`Failed to create a new MMKV instance: The native MMKV Module could not be installed! Looks like something went wrong when installing JSI bindings: ${result}`
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// Check again if the constructor now exists. If not, throw an error.
|
|
63
|
-
if (global.mmkvCreateNewInstance == null)
|
|
64
|
-
throw new Error(
|
|
65
|
-
'Failed to create a new MMKV instance, the native initializer function does not exist. Are you trying to use MMKV from different JS Runtimes?'
|
|
66
|
-
);
|
|
67
14
|
}
|
|
68
|
-
|
|
69
|
-
return global.mmkvCreateNewInstance(config);
|
|
15
|
+
return instance as NativeMMKV;
|
|
70
16
|
};
|
package/src/createMMKV.web.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* global localStorage */
|
|
2
|
-
import type {
|
|
2
|
+
import type { Configuration, NativeMMKV } from './MMKV';
|
|
3
3
|
import { createTextEncoder } from './createTextEncoder';
|
|
4
4
|
|
|
5
5
|
const canUseDOM =
|
|
@@ -19,7 +19,7 @@ const hasAccessToLocalStorage = () => {
|
|
|
19
19
|
const KEY_WILDCARD = '\\';
|
|
20
20
|
const inMemoryStorage = new Map<string, string>();
|
|
21
21
|
|
|
22
|
-
export const createMMKV = (config:
|
|
22
|
+
export const createMMKV = (config: Configuration): NativeMMKV => {
|
|
23
23
|
if (config.encryptionKey != null) {
|
|
24
24
|
throw new Error("MMKV: 'encryptionKey' is not supported on Web!");
|
|
25
25
|
}
|
|
@@ -118,5 +118,9 @@ export const createMMKV = (config: MMKVConfiguration): NativeMMKV => {
|
|
|
118
118
|
recrypt: () => {
|
|
119
119
|
throw new Error('`recrypt(..)` is not supported on Web!');
|
|
120
120
|
},
|
|
121
|
+
size: 0,
|
|
122
|
+
trim: () => {
|
|
123
|
+
// no-op
|
|
124
|
+
},
|
|
121
125
|
};
|
|
122
126
|
};
|
package/src/hooks.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
|
|
2
|
-
import { MMKV,
|
|
2
|
+
import { MMKV, Configuration } from './MMKV';
|
|
3
3
|
|
|
4
4
|
function isConfigurationEqual(
|
|
5
|
-
left?:
|
|
6
|
-
right?:
|
|
5
|
+
left?: Configuration,
|
|
6
|
+
right?: Configuration
|
|
7
7
|
): boolean {
|
|
8
8
|
if (left == null || right == null) return left == null && right == null;
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
11
|
left.encryptionKey === right.encryptionKey &&
|
|
12
12
|
left.id === right.id &&
|
|
13
|
-
left.path === right.path
|
|
13
|
+
left.path === right.path &&
|
|
14
|
+
left.mode === right.mode
|
|
14
15
|
);
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -30,10 +31,10 @@ export function useMMKV(): MMKV;
|
|
|
30
31
|
* Use a custom MMKV instance with the given configuration.
|
|
31
32
|
* @param configuration The configuration to initialize the MMKV instance with. Does not have to be memoized.
|
|
32
33
|
*/
|
|
33
|
-
export function useMMKV(configuration:
|
|
34
|
-
export function useMMKV(configuration?:
|
|
34
|
+
export function useMMKV(configuration: Configuration): MMKV;
|
|
35
|
+
export function useMMKV(configuration?: Configuration): MMKV {
|
|
35
36
|
const instance = useRef<MMKV>();
|
|
36
|
-
const lastConfiguration = useRef<
|
|
37
|
+
const lastConfiguration = useRef<Configuration>();
|
|
37
38
|
|
|
38
39
|
if (configuration == null) return getDefaultInstance();
|
|
39
40
|
|
|
@@ -49,9 +50,9 @@ export function useMMKV(configuration?: MMKVConfiguration): MMKV {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
function createMMKVHook<
|
|
52
|
-
T extends (boolean | number | string |
|
|
53
|
+
T extends (boolean | number | string | ArrayBuffer) | undefined,
|
|
53
54
|
TSet extends T | undefined,
|
|
54
|
-
TSetAction extends TSet | ((current: T) => TSet)
|
|
55
|
+
TSetAction extends TSet | ((current: T) => TSet),
|
|
55
56
|
>(getter: (instance: MMKV, key: string) => T) {
|
|
56
57
|
return (
|
|
57
58
|
key: string,
|
|
@@ -82,7 +83,7 @@ function createMMKVHook<
|
|
|
82
83
|
mmkv.delete(key);
|
|
83
84
|
break;
|
|
84
85
|
case 'object':
|
|
85
|
-
if (newValue instanceof
|
|
86
|
+
if (newValue instanceof ArrayBuffer) {
|
|
86
87
|
mmkv.set(key, newValue);
|
|
87
88
|
break;
|
|
88
89
|
} else {
|
|
@@ -179,7 +180,12 @@ export const useMMKVBuffer = createMMKVHook((instance, key) =>
|
|
|
179
180
|
export function useMMKVObject<T>(
|
|
180
181
|
key: string,
|
|
181
182
|
instance?: MMKV
|
|
182
|
-
): [
|
|
183
|
+
): [
|
|
184
|
+
value: T | undefined,
|
|
185
|
+
setValue: (
|
|
186
|
+
value: T | undefined | ((prevValue: T | undefined) => T | undefined)
|
|
187
|
+
) => void,
|
|
188
|
+
] {
|
|
183
189
|
const [json, setJson] = useMMKVString(key, instance);
|
|
184
190
|
|
|
185
191
|
const value = useMemo(() => {
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
package com.reactnativemmkv;
|
|
2
|
-
|
|
3
|
-
import android.util.Log;
|
|
4
|
-
|
|
5
|
-
import androidx.annotation.NonNull;
|
|
6
|
-
import androidx.annotation.Nullable;
|
|
7
|
-
|
|
8
|
-
import com.facebook.react.bridge.JavaScriptContextHolder;
|
|
9
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
10
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
11
|
-
import com.facebook.react.bridge.ReactMethod;
|
|
12
|
-
import com.facebook.react.module.annotations.ReactModule;
|
|
13
|
-
|
|
14
|
-
@ReactModule(name = MmkvModule.NAME)
|
|
15
|
-
public class MmkvModule extends ReactContextBaseJavaModule {
|
|
16
|
-
public static final String NAME = "MMKV";
|
|
17
|
-
|
|
18
|
-
public MmkvModule(ReactApplicationContext reactContext) {
|
|
19
|
-
super(reactContext);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
@NonNull
|
|
23
|
-
@Override
|
|
24
|
-
public String getName() {
|
|
25
|
-
return NAME;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
29
|
-
public boolean install(@Nullable String rootDirectory) {
|
|
30
|
-
try {
|
|
31
|
-
Log.i(NAME, "Loading C++ library...");
|
|
32
|
-
System.loadLibrary("reactnativemmkv");
|
|
33
|
-
|
|
34
|
-
JavaScriptContextHolder jsContext = getReactApplicationContext().getJavaScriptContextHolder();
|
|
35
|
-
if (rootDirectory == null) {
|
|
36
|
-
rootDirectory = getReactApplicationContext().getFilesDir().getAbsolutePath() + "/mmkv";
|
|
37
|
-
}
|
|
38
|
-
Log.i(NAME, "Installing MMKV JSI Bindings for MMKV root directory: " + rootDirectory);
|
|
39
|
-
nativeInstall(jsContext.get(), rootDirectory);
|
|
40
|
-
Log.i(NAME, "Successfully installed MMKV JSI Bindings!");
|
|
41
|
-
return true;
|
|
42
|
-
} catch (Exception exception) {
|
|
43
|
-
Log.e(NAME, "Failed to install MMKV JSI Bindings!", exception);
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private static native void nativeInstall(long jsiPtr, String path);
|
|
49
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
package com.reactnativemmkv;
|
|
2
|
-
|
|
3
|
-
import androidx.annotation.NonNull;
|
|
4
|
-
|
|
5
|
-
import com.facebook.react.ReactPackage;
|
|
6
|
-
import com.facebook.react.bridge.NativeModule;
|
|
7
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
-
import com.facebook.react.uimanager.ViewManager;
|
|
9
|
-
|
|
10
|
-
import java.util.Collections;
|
|
11
|
-
import java.util.List;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
public class MmkvPackage implements ReactPackage {
|
|
15
|
-
@NonNull
|
|
16
|
-
@Override
|
|
17
|
-
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
18
|
-
return Collections.singletonList(new MmkvModule(reactContext));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@NonNull
|
|
22
|
-
@Override
|
|
23
|
-
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
24
|
-
return Collections.emptyList();
|
|
25
|
-
}
|
|
26
|
-
}
|