react-native-mmkv 2.0.0 → 2.0.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.
@@ -28,6 +28,7 @@
28
28
  # include "ScopedLock.hpp"
29
29
  # include "ThreadLock.h"
30
30
  # include <cassert>
31
+ # include <strsafe.h>
31
32
 
32
33
  using namespace std;
33
34
 
@@ -36,13 +37,73 @@ namespace mmkv {
36
37
  static bool getFileSize(MMKVFileHandle_t fd, size_t &size);
37
38
  static bool ftruncate(MMKVFileHandle_t file, size_t size);
38
39
 
39
- MemoryFile::MemoryFile(const MMKVPath_t &path)
40
- : m_name(path), m_fd(INVALID_HANDLE_VALUE), m_fileMapping(nullptr), m_ptr(nullptr), m_size(0) {
40
+ File::File(MMKVPath_t path, OpenFlag flag) : m_path(std::move(path)), m_fd(INVALID_HANDLE_VALUE), m_flag(flag) {
41
+ open();
42
+ }
43
+
44
+ static pair<int, int> OpenFlag2NativeFlag(OpenFlag flag) {
45
+ int access = 0, create = OPEN_EXISTING;
46
+ if (flag & OpenFlag::ReadWrite) {
47
+ access = (GENERIC_READ | GENERIC_WRITE);
48
+ } else if (flag & OpenFlag::ReadOnly) {
49
+ access |= GENERIC_READ;
50
+ } else if (flag & OpenFlag::WriteOnly) {
51
+ access |= GENERIC_WRITE;
52
+ }
53
+ if (flag & OpenFlag::Create) {
54
+ create = OPEN_ALWAYS;
55
+ }
56
+ if (flag & OpenFlag::Excel) {
57
+ access = CREATE_NEW;
58
+ }
59
+ if (flag & OpenFlag::Truncate) {
60
+ access = CREATE_ALWAYS;
61
+ }
62
+ return {access, create};
63
+ }
64
+
65
+ bool File::open() {
66
+ if (isFileValid()) {
67
+ return true;
68
+ }
69
+ auto pair = OpenFlag2NativeFlag(m_flag);
70
+ m_fd = CreateFile(m_path.c_str(), pair.first, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
71
+ pair.second, FILE_ATTRIBUTE_NORMAL, nullptr);
72
+ if (!isFileValid()) {
73
+ MMKVError("fail to open:[%ws], %d", m_path.c_str(), GetLastError());
74
+ return false;
75
+ }
76
+ MMKVInfo("open fd[%p], %ws", m_fd, m_path.c_str());
77
+ return true;
78
+ }
79
+
80
+ void File::close() {
81
+ if (isFileValid()) {
82
+ MMKVInfo("closing fd[%p], %ws", m_fd, m_path.c_str());
83
+ if (CloseHandle(m_fd)) {
84
+ m_fd = INVALID_HANDLE_VALUE;
85
+ } else {
86
+ MMKVError("fail to close [%ws], %d", m_path.c_str(), GetLastError());
87
+ }
88
+ }
89
+ }
90
+
91
+ size_t File::getActualFileSize() const {
92
+ size_t size = 0;
93
+ mmkv::getFileSize(m_fd, size);
94
+ return size;
95
+ }
96
+
97
+ MemoryFile::MemoryFile(MMKVPath_t path)
98
+ : m_diskFile(std::move(path), OpenFlag::ReadWrite | OpenFlag::Create)
99
+ , m_fileMapping(nullptr)
100
+ , m_ptr(nullptr)
101
+ , m_size(0) {
41
102
  reloadFromFile();
42
103
  }
43
104
 
44
105
  bool MemoryFile::truncate(size_t size) {
45
- if (m_fd < 0) {
106
+ if (!m_diskFile.isFileValid()) {
46
107
  return false;
47
108
  }
48
109
  if (size == m_size) {
@@ -56,14 +117,14 @@ bool MemoryFile::truncate(size_t size) {
56
117
  m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
57
118
  }
58
119
 
59
- if (!ftruncate(m_fd, m_size)) {
60
- MMKVError("fail to truncate [%ws] to size %zu", m_name.c_str(), m_size);
120
+ if (!ftruncate(m_diskFile.getFd(), m_size)) {
121
+ MMKVError("fail to truncate [%ws] to size %zu", m_diskFile.m_path.c_str(), m_size);
61
122
  m_size = oldSize;
62
123
  return false;
63
124
  }
64
125
  if (m_size > oldSize) {
65
- if (!zeroFillFile(m_fd, oldSize, m_size - oldSize)) {
66
- MMKVError("fail to zeroFile [%ws] to size %zu", m_name.c_str(), m_size);
126
+ if (!zeroFillFile(m_diskFile.getFd(), oldSize, m_size - oldSize)) {
127
+ MMKVError("fail to zeroFile [%ws] to size %zu", m_diskFile.m_path.c_str(), m_size);
67
128
  m_size = oldSize;
68
129
  return false;
69
130
  }
@@ -71,7 +132,7 @@ bool MemoryFile::truncate(size_t size) {
71
132
 
72
133
  if (m_ptr) {
73
134
  if (!UnmapViewOfFile(m_ptr)) {
74
- MMKVError("fail to munmap [%ws], %d", m_name.c_str(), GetLastError());
135
+ MMKVError("fail to munmap [%ws], %d", m_diskFile.m_path.c_str(), GetLastError());
75
136
  }
76
137
  m_ptr = nullptr;
77
138
  }
@@ -90,28 +151,28 @@ bool MemoryFile::msync(SyncFlag syncFlag) {
90
151
  if (m_ptr) {
91
152
  if (FlushViewOfFile(m_ptr, m_size)) {
92
153
  if (syncFlag == MMKV_SYNC) {
93
- if (!FlushFileBuffers(m_fd)) {
94
- MMKVError("fail to FlushFileBuffers [%ws]:%d", m_name.c_str(), GetLastError());
154
+ if (!FlushFileBuffers(m_diskFile.getFd())) {
155
+ MMKVError("fail to FlushFileBuffers [%ws]:%d", m_diskFile.m_path.c_str(), GetLastError());
95
156
  return false;
96
157
  }
97
158
  }
98
159
  return true;
99
160
  }
100
- MMKVError("fail to FlushViewOfFile [%ws]:%d", m_name.c_str(), GetLastError());
161
+ MMKVError("fail to FlushViewOfFile [%ws]:%d", m_diskFile.m_path.c_str(), GetLastError());
101
162
  return false;
102
163
  }
103
164
  return false;
104
165
  }
105
166
 
106
167
  bool MemoryFile::mmap() {
107
- m_fileMapping = CreateFileMapping(m_fd, nullptr, PAGE_READWRITE, 0, 0, nullptr);
168
+ m_fileMapping = CreateFileMapping(m_diskFile.getFd(), nullptr, PAGE_READWRITE, 0, 0, nullptr);
108
169
  if (!m_fileMapping) {
109
- MMKVError("fail to CreateFileMapping [%ws], %d", m_name.c_str(), GetLastError());
170
+ MMKVError("fail to CreateFileMapping [%ws], %d", m_diskFile.m_path.c_str(), GetLastError());
110
171
  return false;
111
172
  } else {
112
173
  m_ptr = (char *) MapViewOfFile(m_fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
113
174
  if (!m_ptr) {
114
- MMKVError("fail to mmap [%ws], %d", m_name.c_str(), GetLastError());
175
+ MMKVError("fail to mmap [%ws], %d", m_diskFile.m_path.c_str(), GetLastError());
115
176
  return false;
116
177
  }
117
178
  }
@@ -121,22 +182,17 @@ bool MemoryFile::mmap() {
121
182
 
122
183
  void MemoryFile::reloadFromFile() {
123
184
  if (isFileValid()) {
124
- MMKVWarning("calling reloadFromFile while the cache [%ws] is still valid", m_name.c_str());
185
+ MMKVWarning("calling reloadFromFile while the cache [%ws] is still valid", m_diskFile.m_path.c_str());
125
186
  assert(0);
126
187
  clearMemoryCache();
127
188
  }
128
-
129
- m_fd =
130
- CreateFile(m_name.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
131
- nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
132
- if (m_fd == INVALID_HANDLE_VALUE) {
133
- MMKVError("fail to open:%ws, %d", m_name.c_str(), GetLastError());
134
- } else {
135
- FileLock fileLock(m_fd);
189
+ m_diskFile.open();
190
+ if (m_diskFile.isFileValid()) {
191
+ FileLock fileLock(m_diskFile.getFd());
136
192
  InterProcessLock lock(&fileLock, ExclusiveLockType);
137
193
  SCOPED_LOCK(&lock);
138
194
 
139
- mmkv::getFileSize(m_fd, m_size);
195
+ mmkv::getFileSize(m_diskFile.getFd(), m_size);
140
196
  // round up to (n * pagesize)
141
197
  if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
142
198
  size_t roundSize = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
@@ -159,16 +215,7 @@ void MemoryFile::doCleanMemoryCache(bool forceClean) {
159
215
  CloseHandle(m_fileMapping);
160
216
  m_fileMapping = nullptr;
161
217
  }
162
- if (m_fd != INVALID_HANDLE_VALUE) {
163
- CloseHandle(m_fd);
164
- m_fd = INVALID_HANDLE_VALUE;
165
- }
166
- }
167
-
168
- size_t MemoryFile::getActualFileSize() {
169
- size_t size = 0;
170
- mmkv::getFileSize(m_fd, size);
171
- return size;
218
+ m_diskFile.close();
172
219
  }
173
220
 
174
221
  size_t getPageSize() {
@@ -302,6 +349,170 @@ static bool getFileSize(MMKVFileHandle_t fd, size_t &size) {
302
349
  return false;
303
350
  }
304
351
 
352
+ static pair<MMKVPath_t, MMKVFileHandle_t> createUniqueTempFile(const wchar_t *prefix) {
353
+ wchar_t lpTempPathBuffer[MAX_PATH];
354
+ // Gets the temp path env string (no guarantee it's a valid path).
355
+ auto dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer);
356
+ if (dwRetVal > MAX_PATH || (dwRetVal == 0)) {
357
+ MMKVError("GetTempPath failed %d", GetLastError());
358
+ return {L"", INVALID_HANDLE_VALUE};
359
+ }
360
+ // Generates a temporary file name.
361
+ wchar_t szTempFileName[MAX_PATH];
362
+ if (!GetTempFileName(lpTempPathBuffer, prefix, 0, szTempFileName)) {
363
+ MMKVError("GetTempFileName failed %d", GetLastError());
364
+ return {L"", INVALID_HANDLE_VALUE};
365
+ }
366
+ auto hTempFile = CreateFile(szTempFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
367
+ if (hTempFile == INVALID_HANDLE_VALUE) {
368
+ MMKVError("fail to create unique temp file [%ws], %d", szTempFileName, GetLastError());
369
+ return {L"", INVALID_HANDLE_VALUE};
370
+ }
371
+ MMKVDebug("create unique temp file [%ws] with fd[%p]", szTempFileName, hTempFile);
372
+ return {MMKVPath_t(szTempFileName), hTempFile};
373
+ }
374
+
375
+ bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
376
+ if (MoveFileEx(srcPath.c_str(), dstPath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) == 0) {
377
+ MMKVError("MoveFileEx [%ws] to [%ws] failed %d", srcPath.c_str(), dstPath.c_str(), GetLastError());
378
+ return false;
379
+ }
380
+ return true;
381
+ }
382
+
383
+ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
384
+ if (dstFD == INVALID_HANDLE_VALUE) {
385
+ return false;
386
+ }
387
+ bool ret = false;
388
+ File srcFile(srcPath, OpenFlag::ReadOnly);
389
+ if (!srcFile.isFileValid()) {
390
+ return false;
391
+ }
392
+ auto bufferSize = getPageSize();
393
+ auto buffer = (char *) malloc(bufferSize);
394
+ if (!buffer) {
395
+ MMKVError("fail to malloc size %zu, %d(%s)", bufferSize, errno, strerror(errno));
396
+ goto errorOut;
397
+ }
398
+ SetFilePointer(dstFD, 0, 0, FILE_BEGIN);
399
+
400
+ // the Win32 platform don't have sendfile()/fcopyfile() equivalent, do it the hard way
401
+ while (true) {
402
+ DWORD sizeRead = 0;
403
+ if (!ReadFile(srcFile.getFd(), buffer, bufferSize, &sizeRead, nullptr)) {
404
+ MMKVError("fail to read %ws: %d", srcPath.c_str(), GetLastError());
405
+ goto errorOut;
406
+ }
407
+
408
+ DWORD sizeWrite = 0;
409
+ if (!WriteFile(dstFD, buffer, sizeRead, &sizeWrite, nullptr)) {
410
+ MMKVError("fail to write fd [%d], %d", dstFD, GetLastError());
411
+ goto errorOut;
412
+ }
413
+
414
+ if (sizeRead < bufferSize) {
415
+ break;
416
+ }
417
+ }
418
+ if (needTruncate) {
419
+ size_t dstFileSize = 0;
420
+ getFileSize(dstFD, dstFileSize);
421
+ auto srcFileSize = srcFile.getActualFileSize();
422
+ if ((dstFileSize != srcFileSize) && !ftruncate(dstFD, static_cast<off_t>(srcFileSize))) {
423
+ MMKVError("fail to truncate [%d] to size [%zu]", dstFD, srcFileSize);
424
+ goto errorOut;
425
+ }
426
+ }
427
+
428
+ ret = true;
429
+ MMKVInfo("copy content from %ws to fd[%d] finish", srcPath.c_str(), dstFD);
430
+
431
+ errorOut:
432
+ free(buffer);
433
+ return ret;
434
+ }
435
+
436
+ // copy to a temp file then rename it
437
+ // this is the best we can do on Win32
438
+ bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
439
+ auto pair = createUniqueTempFile(L"MMKV");
440
+ auto tmpFD = pair.second;
441
+ auto &tmpPath = pair.first;
442
+ if (tmpFD == INVALID_HANDLE_VALUE) {
443
+ return false;
444
+ }
445
+
446
+ bool renamed = false;
447
+ if (copyFileContent(srcPath, tmpFD, false)) {
448
+ MMKVInfo("copyed file [%ws] to [%ws]", srcPath.c_str(), tmpPath.c_str());
449
+ CloseHandle(tmpFD);
450
+ renamed = tryAtomicRename(tmpPath.c_str(), dstPath.c_str());
451
+ if (renamed) {
452
+ MMKVInfo("copyfile [%ws] to [%ws] finish.", srcPath.c_str(), dstPath.c_str());
453
+ }
454
+ } else {
455
+ CloseHandle(tmpFD);
456
+ }
457
+
458
+ if (!renamed) {
459
+ DeleteFile(tmpPath.c_str());
460
+ }
461
+ return renamed;
462
+ }
463
+
464
+ bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
465
+ File dstFile(dstPath, OpenFlag::WriteOnly | OpenFlag::Create | OpenFlag::Truncate);
466
+ if (!dstFile.isFileValid()) {
467
+ return false;
468
+ }
469
+ auto ret = copyFileContent(srcPath, dstFile.getFd(), false);
470
+ if (!ret) {
471
+ MMKVError("fail to copyfile(): target file %ws", dstPath.c_str());
472
+ } else {
473
+ MMKVInfo("copy content from %ws to [%ws] finish", srcPath.c_str(), dstPath.c_str());
474
+ }
475
+ return ret;
476
+ }
477
+
478
+ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD) {
479
+ return copyFileContent(srcPath, dstFD, true);
480
+ }
481
+
482
+ void walkInDir(const MMKVPath_t &dirPath,
483
+ WalkType type,
484
+ const std::function<void(const MMKVPath_t &, WalkType)> &walker) {
485
+ wchar_t szDir[MAX_PATH];
486
+ StringCchCopy(szDir, MAX_PATH, dirPath.c_str());
487
+ StringCchCat(szDir, MAX_PATH, L"\\*");
488
+
489
+ WIN32_FIND_DATA ffd;
490
+ auto hFind = FindFirstFile(szDir, &ffd);
491
+ if (hFind == INVALID_HANDLE_VALUE) {
492
+ return;
493
+ }
494
+
495
+ do {
496
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
497
+ if (type & WalkFolder) {
498
+ if (wcscmp(ffd.cFileName, L".") == 0 || wcscmp(ffd.cFileName, L"..") == 0) {
499
+ continue;
500
+ }
501
+ walker(dirPath + L"\\" + ffd.cFileName, WalkFolder);
502
+ }
503
+ } else if (type & WalkFile) {
504
+ walker(dirPath + L"\\" + ffd.cFileName, WalkFile);
505
+ }
506
+ } while (FindNextFile(hFind, &ffd) != 0);
507
+
508
+ auto dwError = GetLastError();
509
+ if (dwError != ERROR_NO_MORE_FILES) {
510
+ MMKVError("WalkInDir fail %d", dwError);
511
+ }
512
+
513
+ FindClose(hFind);
514
+ }
515
+
305
516
  } // namespace mmkv
306
517
 
307
518
  std::wstring string2MMKVPath_t(const std::string &str) {
@@ -313,4 +524,13 @@ std::wstring string2MMKVPath_t(const std::string &str) {
313
524
  return result;
314
525
  }
315
526
 
527
+ std::string MMKVPath_t2String(const MMKVPath_t &str) {
528
+ auto length = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, nullptr, 0, 0, 0);
529
+ auto buffer = new char[length];
530
+ WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, buffer, length, 0, 0);
531
+ string result(buffer);
532
+ delete[] buffer;
533
+ return result;
534
+ }
535
+
316
536
  #endif // MMKV_WIN32
@@ -89,13 +89,13 @@ int AES_C_set_decrypt_key(const uint8_t *userKey, const int bits, void *key);
89
89
  void AES_C_encrypt(const uint8_t *in, uint8_t *out, const void *key);
90
90
  void AES_C_decrypt(const uint8_t *in, uint8_t *out, const void *key);
91
91
 
92
- } // namespace openssl
93
-
94
92
  extern aes_set_encrypt_t AES_set_encrypt_key;
95
93
  extern aes_set_decrypt_t AES_set_decrypt_key;
96
94
  extern aes_encrypt_t AES_encrypt;
97
95
  extern aes_decrypt_t AES_decrypt;
98
96
 
97
+ } // namespace openssl
98
+
99
99
  #endif // __ARM_MAX_ARCH__ <= 7
100
100
 
101
101
  #endif // __linux__
@@ -43,6 +43,8 @@
43
43
 
44
44
  #ifndef MMKV_DISABLE_CRYPT
45
45
 
46
+ namespace openssl {
47
+
46
48
  #if (__ARM_MAX_ARCH__ > 7) && defined(__linux__)
47
49
 
48
50
  aes_set_encrypt_t AES_set_encrypt_key = openssl::AES_C_set_encrypt_key;
@@ -54,8 +56,6 @@ aes_encrypt_t AES_decrypt = openssl::AES_C_decrypt;
54
56
 
55
57
  #if (__ARM_MAX_ARCH__ <= 0) || (__ARM_MAX_ARCH__ > 7 && defined(__linux__))
56
58
 
57
- namespace openssl {
58
-
59
59
  /*-
60
60
  Te0[x] = S [x].[02, 01, 01, 03];
61
61
  Te1[x] = S [x].[03, 02, 01, 01];
@@ -1037,8 +1037,8 @@ void AES_C_decrypt(const uint8_t *in, uint8_t *out, const void *k) {
1037
1037
  PUTU32(out + 12, s3);
1038
1038
  }
1039
1039
 
1040
- } // namespace openssl
1041
-
1042
1040
  #endif // (__ARM_MAX_ARCH__ < 0) || (__ARM_MAX_ARCH__ > 7 && defined(__linux__))
1043
1041
 
1042
+ } // namespace openssl
1043
+
1044
1044
  #endif // MMKV_DISABLE_CRYPT
package/MMKV/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT)
2
2
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls)
3
- [![Release Version](https://img.shields.io/badge/release-1.2.10-brightgreen.svg)](https://github.com/Tencent/MMKV/releases)
3
+ [![Release Version](https://img.shields.io/badge/release-1.2.12-brightgreen.svg)](https://github.com/Tencent/MMKV/releases)
4
4
  [![Platform](https://img.shields.io/badge/Platform-%20Android%20%7C%20iOS%2FmacOS%20%7C%20Win32%20%7C%20POSIX-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home)
5
5
 
6
6
  中文版本请参看[这里](./README_CN.md)
@@ -28,12 +28,12 @@ Add the following lines to `build.gradle` on your app module:
28
28
 
29
29
  ```gradle
30
30
  dependencies {
31
- implementation 'com.tencent:mmkv-static:1.2.10'
32
- // replace "1.2.10" with any available version
31
+ implementation 'com.tencent:mmkv:1.2.12'
32
+ // replace "1.2.12" with any available version
33
33
  }
34
34
  ```
35
35
 
36
- Starting from v1.2.8, MMKV has been **migrated to Maven Central**. Older versions (<= v1.2.7) are still available on JCenter.
36
+ Starting from v1.2.8, MMKV has been **migrated to Maven Central**.
37
37
  For other installation options, see [Android Setup](https://github.com/Tencent/MMKV/wiki/android_setup).
38
38
 
39
39
  ### Quick Tutorial
package/README.md CHANGED
@@ -160,9 +160,10 @@ const userObject = JSON.parse(jsonUser)
160
160
  * [Hooks](./docs/HOOKS.md)
161
161
  * [Value-change Listeners](./docs/LISTENERS.md)
162
162
  * [Migrate from AsyncStorage](./docs/MIGRATE_FROM_ASYNC_STORAGE.md)
163
- * [Using MMKV with redux-persis](./docs/WRAPPER_REDUX.md)
163
+ * [Using MMKV with redux-persist](./docs/WRAPPER_REDUX.md)
164
164
  * [Using MMKV with mobx-persist-storage](./docs/WRAPPER_MOBX.md)
165
165
  * [Using MMKV with mobx-persist](./docs/WRAPPER_MOBXPERSIST.md)
166
+ * [How is this library different from **react-native-mmkv-storage**?](https://github.com/mrousavy/react-native-mmkv/issues/100#issuecomment-886477361)
166
167
 
167
168
  ## Limitations
168
169
 
@@ -13,14 +13,50 @@ const ROOT_DIRECTORY = null;
13
13
  const createMMKV = config => {
14
14
  // Check if the constructor exists. If not, try installing the JSI bindings.
15
15
  if (global.mmkvCreateNewInstance == null) {
16
- // get the MMKV ReactModule
16
+ // Get the native MMKV ReactModule
17
17
  const MMKVModule = _reactNative.NativeModules.MMKV;
18
- if (MMKVModule == null || typeof MMKVModule.install !== 'function') throw new Error('The native MMKV Module could not be found! Is it correctly installed and autolinked?'); // Call the synchronous blocking install() function
18
+
19
+ if (MMKVModule == null) {
20
+ var _NativeModules$Native, _NativeModules$Native2;
21
+
22
+ let message = 'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
23
+ message += '\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
24
+
25
+ if (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'macos') {
26
+ message += '\n* Make sure you ran `pod install` in the ios/ directory.';
27
+ }
28
+
29
+ if (_reactNative.Platform.OS === 'android') {
30
+ message += '\n* Make sure gradle is synced.';
31
+ } // check if Expo
32
+
33
+
34
+ const ExpoConstants = (_NativeModules$Native = _reactNative.NativeModules.NativeUnimoduleProxy) === null || _NativeModules$Native === void 0 ? void 0 : (_NativeModules$Native2 = _NativeModules$Native.modulesConstants) === null || _NativeModules$Native2 === void 0 ? void 0 : _NativeModules$Native2.ExponentConstants;
35
+
36
+ if (ExpoConstants != null) {
37
+ if (ExpoConstants.appOwnership === 'expo') {
38
+ // We're running Expo Go
39
+ throw new Error('react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.');
40
+ } else {
41
+ // We're running Expo bare / standalone
42
+ message += '\n* Make sure you ran `expo prebuild`.';
43
+ }
44
+ }
45
+
46
+ message += '\n* Make sure you rebuilt the app.';
47
+ throw new Error(message);
48
+ } // Check if we are running on-device (JSI)
49
+
50
+
51
+ if (global.nativeCallSyncHook == null || MMKVModule.install == null) {
52
+ throw new Error('Failed to create a new MMKV instance: React Native is not running on-device. MMKV can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.');
53
+ } // Call the synchronous blocking install() function
54
+
19
55
 
20
56
  const result = MMKVModule.install(ROOT_DIRECTORY);
21
- if (result !== true) throw new Error(`The native MMKV Module could not be installed! Looks like something went wrong when installing JSI bindings: ${result}`); // Check again if the constructor now exists. If not, throw an error.
57
+ if (result !== true) throw new Error(`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}`); // Check again if the constructor now exists. If not, throw an error.
22
58
 
23
- if (global.mmkvCreateNewInstance == null) throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!');
59
+ if (global.mmkvCreateNewInstance == null) throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Are you trying to use MMKV from different JS Runtimes?');
24
60
  }
25
61
 
26
62
  return global.mmkvCreateNewInstance(config);
@@ -1 +1 @@
1
- {"version":3,"sources":["createMMKV.ts"],"names":["ROOT_DIRECTORY","createMMKV","config","global","mmkvCreateNewInstance","MMKVModule","NativeModules","MMKV","install","Error","result"],"mappings":";;;;;;;AAAA;;AAQA;AACA,MAAMA,cAA6B,GAAG,IAAtC;;AAEO,MAAMC,UAAU,GAAIC,MAAD,IAA2C;AACnE;AACA,MAAIC,MAAM,CAACC,qBAAP,IAAgC,IAApC,EAA0C;AACxC;AACA,UAAMC,UAAU,GAAGC,2BAAcC,IAAjC;AACA,QAAIF,UAAU,IAAI,IAAd,IAAsB,OAAOA,UAAU,CAACG,OAAlB,KAA8B,UAAxD,EACE,MAAM,IAAIC,KAAJ,CACJ,sFADI,CAAN,CAJsC,CAOxC;;AACA,UAAMC,MAAM,GAAGL,UAAU,CAACG,OAAX,CAAmBR,cAAnB,CAAf;AACA,QAAIU,MAAM,KAAK,IAAf,EACE,MAAM,IAAID,KAAJ,CACH,gHAA+GC,MAAO,EADnH,CAAN,CAVsC,CAaxC;;AACA,QAAIP,MAAM,CAACC,qBAAP,IAAgC,IAApC,EACE,MAAM,IAAIK,KAAJ,CACJ,0MADI,CAAN;AAGH;;AAED,SAAON,MAAM,CAACC,qBAAP,CAA6BF,MAA7B,CAAP;AACD,CAvBM","sourcesContent":["import { NativeModules } from 'react-native';\nimport type { MMKVConfiguration, NativeMMKV } from 'react-native-mmkv';\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(configuration: MMKVConfiguration): NativeMMKV;\n}\n\n// Root directory of all MMKV stores\nconst ROOT_DIRECTORY: string | null = null;\n\nexport const createMMKV = (config: MMKVConfiguration): NativeMMKV => {\n // Check if the constructor exists. If not, try installing the JSI bindings.\n if (global.mmkvCreateNewInstance == null) {\n // get the MMKV ReactModule\n const MMKVModule = NativeModules.MMKV;\n if (MMKVModule == null || typeof MMKVModule.install !== 'function')\n throw new Error(\n 'The native MMKV Module could not be found! Is it correctly installed and autolinked?'\n );\n // Call the synchronous blocking install() function\n const result = MMKVModule.install(ROOT_DIRECTORY);\n if (result !== true)\n throw new Error(\n `The native MMKV Module could not be installed! Looks like something went wrong when installing JSI bindings: ${result}`\n );\n // Check again if the constructor now exists. If not, throw an error.\n if (global.mmkvCreateNewInstance == null)\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!'\n );\n }\n\n return global.mmkvCreateNewInstance(config);\n};\n"]}
1
+ {"version":3,"sources":["createMMKV.ts"],"names":["ROOT_DIRECTORY","createMMKV","config","global","mmkvCreateNewInstance","MMKVModule","NativeModules","MMKV","message","Platform","OS","ExpoConstants","NativeUnimoduleProxy","modulesConstants","ExponentConstants","appOwnership","Error","nativeCallSyncHook","install","result"],"mappings":";;;;;;;AAAA;;AASA;AACA,MAAMA,cAA6B,GAAG,IAAtC;;AAEO,MAAMC,UAAU,GAAIC,MAAD,IAA2C;AACnE;AACA,MAAIC,MAAM,CAACC,qBAAP,IAAgC,IAApC,EAA0C;AACxC;AACA,UAAMC,UAAU,GAAGC,2BAAcC,IAAjC;;AACA,QAAIF,UAAU,IAAI,IAAlB,EAAwB;AAAA;;AACtB,UAAIG,OAAO,GACT,kFADF;AAEAA,MAAAA,OAAO,IACL,mGADF;;AAEA,UAAIC,sBAASC,EAAT,KAAgB,KAAhB,IAAyBD,sBAASC,EAAT,KAAgB,OAA7C,EAAsD;AACpDF,QAAAA,OAAO,IAAI,4DAAX;AACD;;AACD,UAAIC,sBAASC,EAAT,KAAgB,SAApB,EAA+B;AAC7BF,QAAAA,OAAO,IAAI,iCAAX;AACD,OAVqB,CAWtB;;;AACA,YAAMG,aAAa,4BACjBL,2BAAcM,oBADG,oFACjB,sBAAoCC,gBADnB,2DACjB,uBAAsDC,iBADxD;;AAEA,UAAIH,aAAa,IAAI,IAArB,EAA2B;AACzB,YAAIA,aAAa,CAACI,YAAd,KAA+B,MAAnC,EAA2C;AACzC;AACA,gBAAM,IAAIC,KAAJ,CACJ,+GADI,CAAN;AAGD,SALD,MAKO;AACL;AACAR,UAAAA,OAAO,IAAI,wCAAX;AACD;AACF;;AAEDA,MAAAA,OAAO,IAAI,oCAAX;AACA,YAAM,IAAIQ,KAAJ,CAAUR,OAAV,CAAN;AACD,KA/BuC,CAiCxC;;;AACA,QAAIL,MAAM,CAACc,kBAAP,IAA6B,IAA7B,IAAqCZ,UAAU,CAACa,OAAX,IAAsB,IAA/D,EAAqE;AACnE,YAAM,IAAIF,KAAJ,CACJ,sQADI,CAAN;AAGD,KAtCuC,CAwCxC;;;AACA,UAAMG,MAAM,GAAGd,UAAU,CAACa,OAAX,CAAmBlB,cAAnB,CAAf;AACA,QAAImB,MAAM,KAAK,IAAf,EACE,MAAM,IAAIH,KAAJ,CACH,sJAAqJG,MAAO,EADzJ,CAAN,CA3CsC,CA+CxC;;AACA,QAAIhB,MAAM,CAACC,qBAAP,IAAgC,IAApC,EACE,MAAM,IAAIY,KAAJ,CACJ,8IADI,CAAN;AAGH;;AAED,SAAOb,MAAM,CAACC,qBAAP,CAA6BF,MAA7B,CAAP;AACD,CAzDM","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nimport type { MMKVConfiguration, NativeMMKV } from 'react-native-mmkv';\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(configuration: MMKVConfiguration): NativeMMKV;\n function nativeCallSyncHook(): unknown;\n}\n\n// Root directory of all MMKV stores\nconst ROOT_DIRECTORY: string | null = null;\n\nexport const createMMKV = (config: MMKVConfiguration): NativeMMKV => {\n // Check if the constructor exists. If not, try installing the JSI bindings.\n if (global.mmkvCreateNewInstance == null) {\n // Get the native MMKV ReactModule\n const MMKVModule = NativeModules.MMKV;\n if (MMKVModule == null) {\n let message =\n 'Failed to create a new MMKV instance: The native MMKV Module could not be found.';\n message +=\n '\\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';\n if (Platform.OS === 'ios' || Platform.OS === 'macos') {\n message += '\\n* Make sure you ran `pod install` in the ios/ directory.';\n }\n if (Platform.OS === 'android') {\n message += '\\n* Make sure gradle is synced.';\n }\n // check if Expo\n const ExpoConstants =\n NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;\n if (ExpoConstants != null) {\n if (ExpoConstants.appOwnership === 'expo') {\n // We're running Expo Go\n throw new Error(\n 'react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.'\n );\n } else {\n // We're running Expo bare / standalone\n message += '\\n* Make sure you ran `expo prebuild`.';\n }\n }\n\n message += '\\n* Make sure you rebuilt the app.';\n throw new Error(message);\n }\n\n // Check if we are running on-device (JSI)\n if (global.nativeCallSyncHook == null || MMKVModule.install == null) {\n throw new Error(\n 'Failed to create a new MMKV instance: React Native is not running on-device. MMKV can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.'\n );\n }\n\n // Call the synchronous blocking install() function\n const result = MMKVModule.install(ROOT_DIRECTORY);\n if (result !== true)\n throw new Error(\n `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}`\n );\n\n // Check again if the constructor now exists. If not, throw an error.\n if (global.mmkvCreateNewInstance == null)\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Are you trying to use MMKV from different JS Runtimes?'\n );\n }\n\n return global.mmkvCreateNewInstance(config);\n};\n"]}
@@ -71,7 +71,7 @@ function createMMKVHook(getter) {
71
71
  });
72
72
  return () => listener.remove();
73
73
  }, [key, mmkv]);
74
- return (0, _react.useMemo)(() => [value, set], [value, set]);
74
+ return [value, set];
75
75
  };
76
76
  }
77
77
  /**
@@ -135,7 +135,13 @@ function useMMKVObject(key, instance) {
135
135
  return JSON.parse(string);
136
136
  }, [string]);
137
137
  const setValue = (0, _react.useCallback)(v => {
138
- setString(JSON.stringify(v));
138
+ if (v == null) {
139
+ // Clear the Value
140
+ setString(undefined);
141
+ } else {
142
+ // Store the Object as a serialized Value
143
+ setString(JSON.stringify(v));
144
+ }
139
145
  }, [setString]);
140
146
  return [value, setValue];
141
147
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["hooks.ts"],"names":["isConfigurationEqual","left","right","encryptionKey","id","path","defaultInstance","getDefaultInstance","MMKV","useMMKV","configuration","instance","lastConfiguration","current","createMMKVHook","getter","key","mmkv","value","setValue","valueRef","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration } from './MMKV';\n\nfunction isConfigurationEqual(\n left: MMKVConfiguration,\n right: MMKVConfiguration\n): boolean {\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKV> {\n const instance = useRef<MMKV>();\n\n const lastConfiguration = useRef<MMKVConfiguration>();\n if (\n lastConfiguration.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n lastConfiguration.current = configuration;\n instance.current = new MMKV(configuration);\n }\n\n // @ts-expect-error it's not null, I promise.\n return instance;\n}\n\nfunction createMMKVHook<\n T extends boolean | number | (string | undefined),\n TSet extends T | undefined,\n TSetAction extends TSet | ((current: T) => TSet)\n>(getter: (instance: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : v;\n switch (typeof newValue) {\n case 'number':\n case 'string':\n case 'boolean':\n mmkv.set(key, newValue);\n break;\n case 'undefined':\n mmkv.delete(key);\n break;\n default:\n throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);\n }\n },\n [key, mmkv]\n );\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n if (changedKey === key) {\n setValue(getter(mmkv, key));\n }\n });\n return () => listener.remove();\n }, [key, mmkv]);\n\n return useMemo(() => [value, set], [value, set]);\n };\n}\n\n/**\n * Use the string value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [username, setUsername] = useMMKVString(\"user.name\")\n * ```\n */\nexport const useMMKVString = createMMKVHook((instance, key) =>\n instance.getString(key)\n);\n\n/**\n * Use the number value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [age, setAge] = useMMKVNumber(\"user.age\")\n * ```\n */\nexport const useMMKVNumber = createMMKVHook((instance, key) =>\n instance.getNumber(key)\n);\n/**\n * Use the boolean value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean(\"user.isPremium\")\n * ```\n */\nexport const useMMKVBoolean = createMMKVHook((instance, key) =>\n instance.getBoolean(key)\n);\n/**\n * Use an object value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * The object will be serialized using `JSON`.\n *\n * @example\n * ```ts\n * const [user, setUser] = useMMKVObject<User>(\"user\")\n * ```\n */\nexport function useMMKVObject<T>(\n key: string,\n instance?: MMKV\n): [value: T | undefined, setValue: (value: T) => void] {\n const [string, setString] = useMMKVString(key, instance);\n\n const value = useMemo(() => {\n if (string == null) return undefined;\n return JSON.parse(string) as T;\n }, [string]);\n const setValue = useCallback(\n (v: T) => {\n setString(JSON.stringify(v));\n },\n [setString]\n );\n\n return [value, setValue];\n}\n"]}
1
+ {"version":3,"sources":["hooks.ts"],"names":["isConfigurationEqual","left","right","encryptionKey","id","path","defaultInstance","getDefaultInstance","MMKV","useMMKV","configuration","instance","lastConfiguration","current","createMMKVHook","getter","key","mmkv","value","setValue","valueRef","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration } from './MMKV';\n\nfunction isConfigurationEqual(\n left: MMKVConfiguration,\n right: MMKVConfiguration\n): boolean {\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKV> {\n const instance = useRef<MMKV>();\n\n const lastConfiguration = useRef<MMKVConfiguration>();\n if (\n lastConfiguration.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n lastConfiguration.current = configuration;\n instance.current = new MMKV(configuration);\n }\n\n // @ts-expect-error it's not null, I promise.\n return instance;\n}\n\nfunction createMMKVHook<\n T extends boolean | number | (string | undefined),\n TSet extends T | undefined,\n TSetAction extends TSet | ((current: T) => TSet)\n>(getter: (instance: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : v;\n switch (typeof newValue) {\n case 'number':\n case 'string':\n case 'boolean':\n mmkv.set(key, newValue);\n break;\n case 'undefined':\n mmkv.delete(key);\n break;\n default:\n throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);\n }\n },\n [key, mmkv]\n );\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n if (changedKey === key) {\n setValue(getter(mmkv, key));\n }\n });\n return () => listener.remove();\n }, [key, mmkv]);\n\n return [value, set];\n };\n}\n\n/**\n * Use the string value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [username, setUsername] = useMMKVString(\"user.name\")\n * ```\n */\nexport const useMMKVString = createMMKVHook((instance, key) =>\n instance.getString(key)\n);\n\n/**\n * Use the number value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [age, setAge] = useMMKVNumber(\"user.age\")\n * ```\n */\nexport const useMMKVNumber = createMMKVHook((instance, key) =>\n instance.getNumber(key)\n);\n/**\n * Use the boolean value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean(\"user.isPremium\")\n * ```\n */\nexport const useMMKVBoolean = createMMKVHook((instance, key) =>\n instance.getBoolean(key)\n);\n/**\n * Use an object value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * The object will be serialized using `JSON`.\n *\n * @example\n * ```ts\n * const [user, setUser] = useMMKVObject<User>(\"user\")\n * ```\n */\nexport function useMMKVObject<T>(\n key: string,\n instance?: MMKV\n): [value: T | undefined, setValue: (value: T | undefined) => void] {\n const [string, setString] = useMMKVString(key, instance);\n\n const value = useMemo(() => {\n if (string == null) return undefined;\n return JSON.parse(string) as T;\n }, [string]);\n const setValue = useCallback(\n (v: T | undefined) => {\n if (v == null) {\n // Clear the Value\n setString(undefined);\n } else {\n // Store the Object as a serialized Value\n setString(JSON.stringify(v));\n }\n },\n [setString]\n );\n\n return [value, setValue];\n}\n"]}
@@ -1,17 +1,53 @@
1
- import { NativeModules } from 'react-native';
1
+ import { NativeModules, Platform } from 'react-native';
2
2
  // Root directory of all MMKV stores
3
3
  const ROOT_DIRECTORY = null;
4
4
  export const createMMKV = config => {
5
5
  // Check if the constructor exists. If not, try installing the JSI bindings.
6
6
  if (global.mmkvCreateNewInstance == null) {
7
- // get the MMKV ReactModule
7
+ // Get the native MMKV ReactModule
8
8
  const MMKVModule = NativeModules.MMKV;
9
- if (MMKVModule == null || typeof MMKVModule.install !== 'function') throw new Error('The native MMKV Module could not be found! Is it correctly installed and autolinked?'); // Call the synchronous blocking install() function
9
+
10
+ if (MMKVModule == null) {
11
+ var _NativeModules$Native, _NativeModules$Native2;
12
+
13
+ let message = 'Failed to create a new MMKV instance: The native MMKV Module could not be found.';
14
+ message += '\n* Make sure react-native-mmkv is correctly autolinked (run `npx react-native config` to verify)';
15
+
16
+ if (Platform.OS === 'ios' || Platform.OS === 'macos') {
17
+ message += '\n* Make sure you ran `pod install` in the ios/ directory.';
18
+ }
19
+
20
+ if (Platform.OS === 'android') {
21
+ message += '\n* Make sure gradle is synced.';
22
+ } // check if Expo
23
+
24
+
25
+ const ExpoConstants = (_NativeModules$Native = NativeModules.NativeUnimoduleProxy) === null || _NativeModules$Native === void 0 ? void 0 : (_NativeModules$Native2 = _NativeModules$Native.modulesConstants) === null || _NativeModules$Native2 === void 0 ? void 0 : _NativeModules$Native2.ExponentConstants;
26
+
27
+ if (ExpoConstants != null) {
28
+ if (ExpoConstants.appOwnership === 'expo') {
29
+ // We're running Expo Go
30
+ throw new Error('react-native-mmkv is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.');
31
+ } else {
32
+ // We're running Expo bare / standalone
33
+ message += '\n* Make sure you ran `expo prebuild`.';
34
+ }
35
+ }
36
+
37
+ message += '\n* Make sure you rebuilt the app.';
38
+ throw new Error(message);
39
+ } // Check if we are running on-device (JSI)
40
+
41
+
42
+ if (global.nativeCallSyncHook == null || MMKVModule.install == null) {
43
+ throw new Error('Failed to create a new MMKV instance: React Native is not running on-device. MMKV can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.');
44
+ } // Call the synchronous blocking install() function
45
+
10
46
 
11
47
  const result = MMKVModule.install(ROOT_DIRECTORY);
12
- if (result !== true) throw new Error(`The native MMKV Module could not be installed! Looks like something went wrong when installing JSI bindings: ${result}`); // Check again if the constructor now exists. If not, throw an error.
48
+ if (result !== true) throw new Error(`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}`); // Check again if the constructor now exists. If not, throw an error.
13
49
 
14
- if (global.mmkvCreateNewInstance == null) throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!');
50
+ if (global.mmkvCreateNewInstance == null) throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Are you trying to use MMKV from different JS Runtimes?');
15
51
  }
16
52
 
17
53
  return global.mmkvCreateNewInstance(config);