From b32bee333b772d93f63b03ec237b586a70b2a3c6 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:07:55 +0530 Subject: [PATCH 01/50] Upgrade package --- package.json | 3 ++- yarn.lock | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ed1781498cf..c0d6c103c8b 100644 --- a/package.json +++ b/package.json @@ -105,8 +105,9 @@ "react-native-localize": "2.1.1", "react-native-math-view": "3.9.5", "react-native-mime-types": "2.3.0", - "react-native-mmkv": "3.3.3", + "react-native-mmkv": "^4.1.2", "react-native-modal": "13.0.1", + "react-native-nitro-modules": "^0.33.9", "react-native-notifier": "1.6.1", "react-native-picker-select": "9.0.1", "react-native-platform-touchable": "1.1.1", diff --git a/yarn.lock b/yarn.lock index 6055b1ec564..ffdc3fb6eca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12755,10 +12755,10 @@ react-native-mime-types@2.3.0: dependencies: mime-db "~1.37.0" -react-native-mmkv@3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/react-native-mmkv/-/react-native-mmkv-3.3.3.tgz#1f0326f6314e23725af8145964343224d074e6cd" - integrity sha512-GMsfOmNzx0p5+CtrCFRVtpOOMYNJXuksBVARSQrCFaZwjUyHJdQzcN900GGaFFNTxw2fs8s5Xje//RDKj9+PZA== +react-native-mmkv@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/react-native-mmkv/-/react-native-mmkv-4.1.2.tgz#fb337930ec50d509392832c649b578a00c0d008e" + integrity sha512-6LHb2DQBXuo96Aues13EugmlWw/HAYuh3KoJoQNrC4JsBwn3J3KiRYAg2mCm5Je0VYq2YsmbgZG7XJwX/WFYZA== react-native-modal@13.0.1: version "13.0.1" @@ -12768,6 +12768,11 @@ react-native-modal@13.0.1: prop-types "^15.6.2" react-native-animatable "1.3.3" +react-native-nitro-modules@^0.33.9: + version "0.33.9" + resolved "https://registry.yarnpkg.com/react-native-nitro-modules/-/react-native-nitro-modules-0.33.9.tgz#77983bd170b81b87e05c2989c82d91475649569d" + integrity sha512-BM9C5mCGYYjrc8CDWZZ0anLWU/knH2xaEuFzvzogKTOW6fzgS6mmsCdM3ty+AhImJNSYwK19DLrHaqwnrrwEzw== + react-native-notifier@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/react-native-notifier/-/react-native-notifier-1.6.1.tgz#eec07bdebed6c22cd22f5167555b7762e4119552" From c27b5a685fa62e1811c54063a05bd329b44096d3 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:07:57 +0530 Subject: [PATCH 02/50] changes --- app/lib/methods/userPreferences.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/lib/methods/userPreferences.ts b/app/lib/methods/userPreferences.ts index 8e9a605ee3c..a25a3467c6e 100644 --- a/app/lib/methods/userPreferences.ts +++ b/app/lib/methods/userPreferences.ts @@ -1,5 +1,5 @@ -import { MMKV, Mode, useMMKVString } from 'react-native-mmkv'; -import type { Configuration } from 'react-native-mmkv'; +import { createMMKV, useMMKVString } from 'react-native-mmkv'; +import type { Mode, Configuration } from 'react-native-mmkv'; import { NativeModules } from 'react-native'; import { isAndroid } from './helpers'; @@ -58,7 +58,7 @@ const getAppGroupPath = (): string => { } }; -const MMKV_INSTANCE = new MMKV(buildConfiguration()); +const MMKV_INSTANCE = createMMKV(buildConfiguration()); export const useUserPreferences = (key: string, defaultValue?: T): [T | undefined, (value: T | undefined) => void] => { const [storedValue, setStoredValue] = useMMKVString(key, MMKV_INSTANCE); @@ -134,7 +134,7 @@ class UserPreferences { } removeItem(key: string): void { - this.mmkv.delete(key); + this.mmkv.remove(key); } getNumber(key: string): number | null { From 6383fc4029bf4860f82c08c7134012f3a254bafe Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:11:09 +0530 Subject: [PATCH 03/50] Switch to multiple process --- app/lib/methods/userPreferences.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/lib/methods/userPreferences.ts b/app/lib/methods/userPreferences.ts index a25a3467c6e..2ff9544fd99 100644 --- a/app/lib/methods/userPreferences.ts +++ b/app/lib/methods/userPreferences.ts @@ -1,5 +1,5 @@ import { createMMKV, useMMKVString } from 'react-native-mmkv'; -import type { Mode, Configuration } from 'react-native-mmkv'; +import type { Configuration, MMKV } from 'react-native-mmkv'; import { NativeModules } from 'react-native'; import { isAndroid } from './helpers'; @@ -23,14 +23,10 @@ const getEncryptionKey = (): string | undefined => { const buildConfiguration = (): Configuration => { const config: Configuration = { - id: 'default' + id: 'default', + mode: 'multi-process' }; - const multiProcessMode = (Mode as { MULTI_PROCESS?: Mode })?.MULTI_PROCESS; - if (multiProcessMode) { - config.mode = multiProcessMode; - } - const appGroupPath = getAppGroupPath(); if (!isAndroid && appGroupPath) { config.path = `${appGroupPath}mmkv`; From 1f814c81edd70010c6ae0be7d82cff3fd1e82d87 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:26:30 +0530 Subject: [PATCH 04/50] use io.github.zhongwuzw:mmkv:2.2.4 same as rn-mmkv --- android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 951a4c11312..67e6aafcf53 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -147,7 +147,7 @@ dependencies { implementation project(':watermelondb-jsi') implementation "com.google.code.gson:gson:2.8.9" - implementation "com.tencent:mmkv-static:1.2.10" + implementation "io.github.zhongwuzw:mmkv:2.2.4" implementation 'com.facebook.soloader:soloader:0.10.4' // For SecureKeystore (EncryptedSharedPreferences) From 00c924319100f2f5f36b9bfc12c2f1e14f797c37 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:31:55 +0530 Subject: [PATCH 05/50] pod fix --- ios/Podfile | 1 - ios/Podfile.lock | 93 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 4d852a82cd3..780bcf8d37a 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -8,7 +8,6 @@ prepare_react_native_project! def all_pods pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true - pod 'react-native-mmkv', path: '../node_modules/react-native-mmkv', modular_headers: true $RNFirebaseAnalyticsWithoutAdIdSupport = true use_expo_modules! diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f4895e79616..45c9028f456 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -232,6 +232,7 @@ PODS: - libwebp/sharpyuv (1.5.0) - libwebp/webp (1.5.0): - libwebp/sharpyuv + - MMKVCore (2.2.4) - MobileCrypto (0.2.1): - DoubleConversion - glog @@ -261,6 +262,58 @@ PODS: - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) + - NitroMmkv (4.1.2): + - DoubleConversion + - glog + - hermes-engine + - MMKVCore (= 2.2.4) + - NitroModules + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-callinvoker + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - NitroModules (0.33.9): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-callinvoker + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) @@ -1689,30 +1742,6 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-mmkv (3.3.3): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.11.18.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-hermes - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - Yoga - react-native-netinfo (11.3.1): - React-Core - react-native-restart (0.0.22): @@ -2661,6 +2690,8 @@ DEPENDENCIES: - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - "MobileCrypto (from `../node_modules/@rocket.chat/mobile-crypto`)" + - NitroMmkv (from `../node_modules/react-native-mmkv`) + - NitroModules (from `../node_modules/react-native-nitro-modules`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) @@ -2699,7 +2730,6 @@ DEPENDENCIES: - "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)" - "react-native-cookies (from `../node_modules/@react-native-cookies/cookies`)" - react-native-keyboard-controller (from `../node_modules/react-native-keyboard-controller`) - - react-native-mmkv (from `../node_modules/react-native-mmkv`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-restart (from `../node_modules/react-native-restart`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) @@ -2775,6 +2805,7 @@ SPEC REPOS: - libavif - libdav1d - libwebp + - MMKVCore - nanopb - PromisesObjC - PromisesSwift @@ -2848,6 +2879,10 @@ EXTERNAL SOURCES: :tag: hermes-2025-06-04-RNv0.79.3-7f9a871eefeb2c3852365ee80f0b6733ec12ac3b MobileCrypto: :path: "../node_modules/@rocket.chat/mobile-crypto" + NitroMmkv: + :path: "../node_modules/react-native-mmkv" + NitroModules: + :path: "../node_modules/react-native-nitro-modules" RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: @@ -2920,8 +2955,6 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-cookies/cookies" react-native-keyboard-controller: :path: "../node_modules/react-native-keyboard-controller" - react-native-mmkv: - :path: "../node_modules/react-native-mmkv" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" react-native-restart: @@ -3082,8 +3115,11 @@ SPEC CHECKSUMS: libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 + MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df MobileCrypto: a424494b2f45bec9dbe60e3f6d16a40aedefe7b7 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + NitroMmkv: d533317827376527de53faabfebf925cfb3c63df + NitroModules: 61673a8ae8fec5df15bad3cb19d1796d5a63280a PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 @@ -3122,7 +3158,6 @@ SPEC CHECKSUMS: react-native-cameraroll: 23d28040c32ca8b20661e0c41b56ab041779244b react-native-cookies: d648ab7025833b977c0b19e142503034f5f29411 react-native-keyboard-controller: 9ec7ee23328c30251a399cffd8b54324a00343bf - react-native-mmkv: ec96a16cd90e0d994d486c3993abf712186f7262 react-native-netinfo: 2e3c27627db7d49ba412bfab25834e679db41e21 react-native-restart: f6f591aeb40194c41b9b5013901f00e6cf7d0f29 react-native-safe-area-context: 5928d84c879db2f9eb6969ca70e68f58623dbf25 @@ -3188,6 +3223,6 @@ SPEC CHECKSUMS: Yoga: dfabf1234ccd5ac41d1b1d43179f024366ae9831 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 199f6fbbe6fb415c822cca992e6152000ac55b3e +PODFILE CHECKSUM: 7e63d3866651d3227ddd0ed9cf5d23af2b4f54c7 COCOAPODS: 1.15.2 From 4c8588096b12dbf95e9304361ac7d57d85936c6e Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:01:45 +0530 Subject: [PATCH 06/50] Added mmkv core --- ios/Podfile | 1 + ios/Podfile.lock | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/Podfile b/ios/Podfile index 780bcf8d37a..bb0245ea0c5 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -8,6 +8,7 @@ prepare_react_native_project! def all_pods pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true + pod 'MMKVCore', :modular_headers => true $RNFirebaseAnalyticsWithoutAdIdSupport = true use_expo_modules! diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 45c9028f456..f1b31f48c37 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2689,6 +2689,7 @@ DEPENDENCIES: - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - MMKVCore - "MobileCrypto (from `../node_modules/@rocket.chat/mobile-crypto`)" - NitroMmkv (from `../node_modules/react-native-mmkv`) - NitroModules (from `../node_modules/react-native-nitro-modules`) @@ -3223,6 +3224,6 @@ SPEC CHECKSUMS: Yoga: dfabf1234ccd5ac41d1b1d43179f024366ae9831 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 7e63d3866651d3227ddd0ed9cf5d23af2b4f54c7 +PODFILE CHECKSUM: 412ae70eb3129cbf7a7884ff29d42de4e7e19073 COCOAPODS: 1.15.2 From 1c6178bbd0c7e803de42399eec54eba437b080cd Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:13:10 +0530 Subject: [PATCH 07/50] patch update --- patches/react-native-mmkv+3.3.3.patch | 39 --------------------------- patches/react-native-mmkv+4.1.2.patch | 26 ++++++++++++++++++ 2 files changed, 26 insertions(+), 39 deletions(-) delete mode 100644 patches/react-native-mmkv+3.3.3.patch create mode 100644 patches/react-native-mmkv+4.1.2.patch diff --git a/patches/react-native-mmkv+3.3.3.patch b/patches/react-native-mmkv+3.3.3.patch deleted file mode 100644 index de7f8be8ce6..00000000000 --- a/patches/react-native-mmkv+3.3.3.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/node_modules/react-native-mmkv/android/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties b/node_modules/react-native-mmkv/android/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties -new file mode 100644 -index 0000000..1211b1e ---- /dev/null -+++ b/node_modules/react-native-mmkv/android/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties -@@ -0,0 +1,6 @@ -+aarFormatVersion=1.0 -+aarMetadataVersion=1.0 -+minCompileSdk=1 -+minCompileSdkExtension=0 -+minAndroidGradlePluginVersion=1.0.0 -+coreLibraryDesugaringEnabled=false -diff --git a/node_modules/react-native-mmkv/src/MMKV.ts b/node_modules/react-native-mmkv/src/MMKV.ts -index 5ee1f01..ea3f444 100644 ---- a/node_modules/react-native-mmkv/src/MMKV.ts -+++ b/node_modules/react-native-mmkv/src/MMKV.ts -@@ -1,5 +1,5 @@ - import { createMMKV } from './createMMKV'; --import { createMockMMKV } from './createMMKV.mock'; -+// import { createMockMMKV } from './createMMKV.mock'; // Disabled via patch-package for E2E tests - import { isTest } from './PlatformChecker'; - import type { - Configuration, -@@ -25,9 +25,8 @@ export class MMKV implements MMKVInterface { - */ - constructor(configuration: Configuration = { id: 'mmkv.default' }) { - this.id = configuration.id; -- this.nativeInstance = isTest() -- ? createMockMMKV() -- : createMMKV(configuration); -+ // Always use real MMKV (mock disabled via patch-package for E2E tests) -+ this.nativeInstance = createMMKV(configuration); - this.functionCache = {}; - - addMemoryWarningListener(this); -diff --git a/node_modules/react-native-mmkv/src/createMMKV.mock.ts b/node_modules/react-native-mmkv/src/createMMKV.mock.ts.disabled -similarity index 100% -rename from node_modules/react-native-mmkv/src/createMMKV.mock.ts -rename to node_modules/react-native-mmkv/src/createMMKV.mock.ts.disabled diff --git a/patches/react-native-mmkv+4.1.2.patch b/patches/react-native-mmkv+4.1.2.patch new file mode 100644 index 00000000000..e11f0299747 --- /dev/null +++ b/patches/react-native-mmkv+4.1.2.patch @@ -0,0 +1,26 @@ +diff --git a/node_modules/react-native-mmkv/src/createMMKV/createMMKV.ts b/node_modules/react-native-mmkv/src/createMMKV/createMMKV.ts +index d5142f9..5da521f 100644 +--- a/node_modules/react-native-mmkv/src/createMMKV/createMMKV.ts ++++ b/node_modules/react-native-mmkv/src/createMMKV/createMMKV.ts +@@ -2,15 +2,15 @@ import type { MMKV } from '../specs/MMKV.nitro' + import type { Configuration } from '../specs/MMKVFactory.nitro' + import { Platform } from 'react-native' + import { addMemoryWarningListener } from '../addMemoryWarningListener/addMemoryWarningListener' +-import { isTest } from '../isTest' +-import { createMockMMKV } from './createMockMMKV' ++// import { isTest } from '../isTest' ++// import { createMockMMKV } from './createMockMMKV' // Disabled via patch-package for E2E tests + import { getMMKVFactory, getPlatformContext } from '../getMMKVFactory' + + export function createMMKV(configuration?: Configuration): MMKV { +- if (isTest()) { +- // In a test environment, we mock the MMKV instance. +- return createMockMMKV(configuration) +- } ++ //if (isTest()) { ++ // In a test environment, we mock the MMKV instance. ++ // return createMockMMKV(configuration) ++ //} + + const factory = getMMKVFactory() + From c3e9b3cfe57fe6aa04d0f4a5fe1f9f24ba895fd1 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:30:42 +0530 Subject: [PATCH 08/50] mmkv mock update --- __mocks__/react-native-mmkv.js | 300 +++++++++++++++++++++++---------- 1 file changed, 210 insertions(+), 90 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 3288748482c..dec80b1b68a 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -1,20 +1,25 @@ -// Mock for react-native-mmkv -const { useState, useEffect } = require('react'); +// Mock for react-native-mmkv v4 +const { useState, useEffect, useRef, useMemo, useCallback } = require('react'); // Shared storage between instances with the same id const storageInstances = new Map(); +let defaultInstance = null; export const Mode = { - SINGLE_PROCESS: 1, - MULTI_PROCESS: 2 + SINGLE_PROCESS: 'single-process', + MULTI_PROCESS: 'multi-process' }; -export class MMKV { +// MMKV Instance class +class MMKVInstance { constructor(config = {}) { - const { id = 'default', mode, path } = config; + const { id = 'mmkv.default', path, encryptionKey, mode, readOnly } = config; this.id = id; - this.mode = mode; this.path = path; + this.encryptionKey = encryptionKey; + this.mode = mode; + this.isReadOnly = readOnly || false; + this._size = 0; // Share storage between instances with the same id if (!storageInstances.has(this.id)) { @@ -29,8 +34,16 @@ export class MMKV { this.listeners = instance.listeners; } + get size() { + return this._size; + } + set(key, value) { + if (this.isReadOnly) { + throw new Error('Cannot set value in read-only instance'); + } this.storage.set(key, value); + this._size = this.storage.size; this.notifyListeners(key); } @@ -49,13 +62,22 @@ export class MMKV { return typeof value === 'boolean' ? value : undefined; } + getBuffer(key) { + const value = this.storage.get(key); + return value instanceof ArrayBuffer ? value : undefined; + } + contains(key) { return this.storage.has(key); } - delete(key) { + remove(key) { + if (this.isReadOnly) { + throw new Error('Cannot remove value in read-only instance'); + } const deleted = this.storage.delete(key); if (deleted) { + this._size = this.storage.size; this.notifyListeners(key); } return deleted; @@ -66,11 +88,33 @@ export class MMKV { } clearAll() { + if (this.isReadOnly) { + throw new Error('Cannot clear read-only instance'); + } this.storage.clear(); + this._size = 0; // Notify about clear (pass undefined to indicate clear all) this.notifyListeners(undefined); } + recrypt(key) { + this.encryptionKey = key; + } + + trim() { + // No-op for mock + } + + importAllFrom(other) { + let count = 0; + for (const [key, value] of other.storage.entries()) { + this.storage.set(key, value); + count++; + } + this._size = this.storage.size; + return count; + } + addOnValueChangedListener(callback) { this.listeners.push(callback); return { @@ -94,106 +138,182 @@ export class MMKV { } } -// Export Configuration type for TypeScript -export const Configuration = {}; - -// React hooks for MMKV -export function useMMKVString(key, mmkvInstance) { - const [value, setValue] = useState(() => mmkvInstance.getString(key)); +// Factory function to create MMKV instances +export function createMMKV(configuration) { + return new MMKVInstance(configuration); +} - useEffect(() => { - const listener = mmkvInstance.addOnValueChangedListener((changedKey) => { - if (changedKey === key || changedKey === undefined) { - setValue(mmkvInstance.getString(key)); - } - }); - return () => listener.remove(); - }, [key, mmkvInstance]); +// Get default instance +function getDefaultMMKVInstance() { + if (defaultInstance == null) { + defaultInstance = createMMKV(); + } + return defaultInstance; +} - const setStoredValue = (newValue) => { - if (newValue === undefined) { - mmkvInstance.delete(key); - } else { - mmkvInstance.set(key, newValue); - } - setValue(newValue); - }; +// Top-level functions +export function existsMMKV(id) { + return storageInstances.has(id); +} - return [value, setStoredValue]; +export function deleteMMKV(id) { + return storageInstances.delete(id); } -export function useMMKVNumber(key, mmkvInstance) { - const [value, setValue] = useState(() => mmkvInstance.getNumber(key)); +// Helper function for configuration comparison +function isConfigurationEqual(left, right) { + if (left == null || right == null) { + return left == null && right == null; + } - useEffect(() => { - const listener = mmkvInstance.addOnValueChangedListener((changedKey) => { - if (changedKey === key || changedKey === undefined) { - setValue(mmkvInstance.getNumber(key)); - } - }); - return () => listener.remove(); - }, [key, mmkvInstance]); + return ( + left.encryptionKey === right.encryptionKey && + left.id === right.id && + left.path === right.path && + left.mode === right.mode + ); +} - const setStoredValue = (newValue) => { - if (newValue === undefined) { - mmkvInstance.delete(key); - } else { - mmkvInstance.set(key, newValue); +/** + * Use the default, shared MMKV instance or a custom instance with configuration + */ +export function useMMKV(configuration) { + return useMemo(() => { + if (configuration == null) { + return getDefaultMMKVInstance(); } - setValue(newValue); - }; - - return [value, setStoredValue]; + return createMMKV(configuration); + }, [ + configuration + ]); } -export function useMMKVBoolean(key, mmkvInstance) { - const [value, setValue] = useState(() => mmkvInstance.getBoolean(key)); +/** + * Listen for changes in the given MMKV storage instance + */ +export function useMMKVListener(valueChangedListener, instance) { + const ref = useRef(valueChangedListener); + const mmkv = instance ?? getDefaultMMKVInstance(); useEffect(() => { - const listener = mmkvInstance.addOnValueChangedListener((changedKey) => { - if (changedKey === key || changedKey === undefined) { - setValue(mmkvInstance.getBoolean(key)); - } + ref.current = valueChangedListener; + }, [valueChangedListener]); + + useEffect(() => { + const listener = mmkv.addOnValueChangedListener((changedKey) => { + ref.current(changedKey); }); return () => listener.remove(); - }, [key, mmkvInstance]); + }, [mmkv]); +} - const setStoredValue = (newValue) => { - if (newValue === undefined) { - mmkvInstance.delete(key); - } else { - mmkvInstance.set(key, newValue); - } - setValue(newValue); - }; +/** + * Get a list of all keys that exist in the given MMKV instance + */ +export function useMMKVKeys(instance) { + const mmkv = instance ?? getDefaultMMKVInstance(); + const [allKeys, setKeys] = useState(() => mmkv.getAllKeys()); + + useMMKVListener( + (key) => { + const currentlyHasKey = allKeys.includes(key); + const hasKey = mmkv.contains(key); + if (hasKey !== currentlyHasKey) { + setKeys(() => mmkv.getAllKeys()); + } + }, + mmkv + ); - return [value, setStoredValue]; + return allKeys; } -export function useMMKVObject(key, mmkvInstance) { - const [value, setValue] = useState(() => { - const stored = mmkvInstance.getString(key); - return stored ? JSON.parse(stored) : undefined; - }); - - useEffect(() => { - const listener = mmkvInstance.addOnValueChangedListener((changedKey) => { - if (changedKey === key || changedKey === undefined) { - const stored = mmkvInstance.getString(key); - setValue(stored ? JSON.parse(stored) : undefined); - } - }); - return () => listener.remove(); - }, [key, mmkvInstance]); +/** + * Create a custom MMKV hook for a specific type + */ +function createMMKVHook(getter) { + return (key, instance) => { + const mmkv = instance ?? getDefaultMMKVInstance(); + + const [bump, setBump] = useState(0); + const value = useMemo(() => { + bump; + return getter(mmkv, key); + }, [mmkv, key, bump]); + + const set = useCallback( + (v) => { + const newValue = typeof v === 'function' ? v(getter(mmkv, key)) : v; + switch (typeof newValue) { + case 'number': + case 'string': + case 'boolean': + mmkv.set(key, newValue); + break; + case 'undefined': + mmkv.remove(key); + break; + case 'object': + if (newValue instanceof ArrayBuffer) { + mmkv.set(key, newValue); + break; + } else { + throw new Error( + `MMKV: Type object (${newValue}) is not supported!` + ); + } + default: + throw new Error(`MMKV: Type ${typeof newValue} is not supported!`); + } + }, + [key, mmkv] + ); + + useEffect(() => { + const listener = mmkv.addOnValueChangedListener((changedKey) => { + if (changedKey === key) { + setBump(b => b + 1); + } + }); + return () => listener.remove(); + }, [key, mmkv]); - const setStoredValue = (newValue) => { - if (newValue === undefined) { - mmkvInstance.delete(key); - } else { - mmkvInstance.set(key, JSON.stringify(newValue)); - } - setValue(newValue); + return [value, set]; }; - - return [value, setStoredValue]; } + +/** + * Use the string value of the given key from the given MMKV storage instance + */ +export const useMMKVString = createMMKVHook((instance, key) => + instance.getString(key) +); + +/** + * Use the number value of the given key from the given MMKV storage instance + */ +export const useMMKVNumber = createMMKVHook((instance, key) => + instance.getNumber(key) +); + +/** + * Use the boolean value of the given key from the given MMKV storage instance + */ +export const useMMKVBoolean = createMMKVHook((instance, key) => + instance.getBoolean(key) +); + +/** + * Use the object value (JSON stringified) of the given key from the given MMKV storage instance + */ +export const useMMKVObject = createMMKVHook((instance, key) => { + const stored = instance.getString(key); + return stored ? JSON.parse(stored) : undefined; +}); + +/** + * Use the buffer value of the given key from the given MMKV storage instance + */ +export const useMMKVBuffer = createMMKVHook((instance, key) => + instance.getBuffer(key) +); From cedff4736d8ea41be52d12c69ea4ab866ec9c593 Mon Sep 17 00:00:00 2001 From: Rohit3523 Date: Wed, 18 Feb 2026 14:02:26 +0000 Subject: [PATCH 09/50] chore: format code and fix lint issues --- __mocks__/react-native-mmkv.js | 46 +++++++++++----------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index dec80b1b68a..4ecea828c4f 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -167,10 +167,7 @@ function isConfigurationEqual(left, right) { } return ( - left.encryptionKey === right.encryptionKey && - left.id === right.id && - left.path === right.path && - left.mode === right.mode + left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path && left.mode === right.mode ); } @@ -183,9 +180,7 @@ export function useMMKV(configuration) { return getDefaultMMKVInstance(); } return createMMKV(configuration); - }, [ - configuration - ]); + }, [configuration]); } /** @@ -214,16 +209,13 @@ export function useMMKVKeys(instance) { const mmkv = instance ?? getDefaultMMKVInstance(); const [allKeys, setKeys] = useState(() => mmkv.getAllKeys()); - useMMKVListener( - (key) => { - const currentlyHasKey = allKeys.includes(key); - const hasKey = mmkv.contains(key); - if (hasKey !== currentlyHasKey) { - setKeys(() => mmkv.getAllKeys()); - } - }, - mmkv - ); + useMMKVListener((key) => { + const currentlyHasKey = allKeys.includes(key); + const hasKey = mmkv.contains(key); + if (hasKey !== currentlyHasKey) { + setKeys(() => mmkv.getAllKeys()); + } + }, mmkv); return allKeys; } @@ -258,9 +250,7 @@ function createMMKVHook(getter) { mmkv.set(key, newValue); break; } else { - throw new Error( - `MMKV: Type object (${newValue}) is not supported!` - ); + throw new Error(`MMKV: Type object (${newValue}) is not supported!`); } default: throw new Error(`MMKV: Type ${typeof newValue} is not supported!`); @@ -285,23 +275,17 @@ function createMMKVHook(getter) { /** * Use the string value of the given key from the given MMKV storage instance */ -export const useMMKVString = createMMKVHook((instance, key) => - instance.getString(key) -); +export const useMMKVString = createMMKVHook((instance, key) => instance.getString(key)); /** * Use the number value of the given key from the given MMKV storage instance */ -export const useMMKVNumber = createMMKVHook((instance, key) => - instance.getNumber(key) -); +export const useMMKVNumber = createMMKVHook((instance, key) => instance.getNumber(key)); /** * Use the boolean value of the given key from the given MMKV storage instance */ -export const useMMKVBoolean = createMMKVHook((instance, key) => - instance.getBoolean(key) -); +export const useMMKVBoolean = createMMKVHook((instance, key) => instance.getBoolean(key)); /** * Use the object value (JSON stringified) of the given key from the given MMKV storage instance @@ -314,6 +298,4 @@ export const useMMKVObject = createMMKVHook((instance, key) => { /** * Use the buffer value of the given key from the given MMKV storage instance */ -export const useMMKVBuffer = createMMKVHook((instance, key) => - instance.getBuffer(key) -); +export const useMMKVBuffer = createMMKVHook((instance, key) => instance.getBuffer(key)); From d8ec476253177cc012310f1c19b6acdc03a54e71 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:40:39 +0530 Subject: [PATCH 10/50] rerun --- __mocks__/react-native-mmkv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 4ecea828c4f..7eda7a7a9c4 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -200,7 +200,7 @@ export function useMMKVListener(valueChangedListener, instance) { }); return () => listener.remove(); }, [mmkv]); -} +} /** * Get a list of all keys that exist in the given MMKV instance From e4bf5163cea9b7748d024fb5666d7a9d4cc8a19d Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:40:45 +0530 Subject: [PATCH 11/50] revert --- __mocks__/react-native-mmkv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 7eda7a7a9c4..4ecea828c4f 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -200,7 +200,7 @@ export function useMMKVListener(valueChangedListener, instance) { }); return () => listener.remove(); }, [mmkv]); -} +} /** * Get a list of all keys that exist in the given MMKV instance From 1415283b177a7bf429e9192bea70f4a07db12975 Mon Sep 17 00:00:00 2001 From: Rohit3523 Date: Tue, 24 Mar 2026 15:35:37 +0000 Subject: [PATCH 12/50] chore: format code and fix lint issues --- __mocks__/react-native-mmkv.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 4cfb2cb8426..4a9452ac60a 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -195,7 +195,7 @@ export function useMMKVListener(valueChangedListener, instance) { }, [valueChangedListener]); useEffect(() => { - const listener = mmkv.addOnValueChangedListener((changedKey) => { + const listener = mmkv.addOnValueChangedListener(changedKey => { ref.current(changedKey); }); return () => listener.remove(); @@ -209,7 +209,7 @@ export function useMMKVKeys(instance) { const mmkv = instance ?? getDefaultMMKVInstance(); const [allKeys, setKeys] = useState(() => mmkv.getAllKeys()); - useMMKVListener((key) => { + useMMKVListener(key => { const currentlyHasKey = allKeys.includes(key); const hasKey = mmkv.contains(key); if (hasKey !== currentlyHasKey) { @@ -234,7 +234,7 @@ function createMMKVHook(getter) { }, [mmkv, key, bump]); const set = useCallback( - (v) => { + v => { const newValue = typeof v === 'function' ? v(getter(mmkv, key)) : v; switch (typeof newValue) { case 'number': @@ -260,7 +260,7 @@ function createMMKVHook(getter) { ); useEffect(() => { - const listener = mmkv.addOnValueChangedListener((changedKey) => { + const listener = mmkv.addOnValueChangedListener(changedKey => { if (changedKey === key) { setBump(b => b + 1); } From 1fa540b3b2f3e8fc988d6c9ee658d39ce116a4ae Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:42:49 +0530 Subject: [PATCH 13/50] podfile lock fixed --- ios/Podfile.lock | 62 +++++++++++------------------------------------- 1 file changed, 14 insertions(+), 48 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1b0d533c140..95f2cf9a5a5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -279,12 +279,16 @@ PODS: - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) - NitroMmkv (4.1.2): + - boost - DoubleConversion + - fast_float + - fmt - glog - hermes-engine - MMKVCore (= 2.2.4) - NitroModules - - RCT-Folly (= 2024.11.18.00) + - RCT-Folly + - RCT-Folly/Fabric - RCTRequired - RCTTypeSafety - React-callinvoker @@ -293,7 +297,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -304,12 +307,17 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - SocketRocket - Yoga - NitroModules (0.33.9): + - boost - DoubleConversion + - fast_float + - fmt - glog - hermes-engine - - RCT-Folly (= 2024.11.18.00) + - RCT-Folly + - RCT-Folly/Fabric - RCTRequired - RCTTypeSafety - React-callinvoker @@ -318,7 +326,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -329,6 +336,7 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - SocketRocket - Yoga - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): @@ -2190,39 +2198,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga -<<<<<<< mmkv-v4 - - react-native-netinfo (11.3.1): -======= - - react-native-mmkv (3.3.3): - - boost - - DoubleConversion - - fast_float - - fmt - - glog - - hermes-engine - - RCT-Folly - - RCT-Folly/Fabric - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - SocketRocket - - Yoga - react-native-netinfo (11.4.1): ->>>>>>> develop - React-Core - react-native-restart (0.0.22): - React-Core @@ -3996,15 +3972,11 @@ SPEC CHECKSUMS: libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 -<<<<<<< mmkv-v4 MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df - MobileCrypto: badd466d89e6fb166575c8a5cb74606ee3eec0fe -======= MobileCrypto: 41cd66d5588e979cf95d1ff6ae2eec88eb284ef1 ->>>>>>> develop nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - NitroMmkv: d533317827376527de53faabfebf925cfb3c63df - NitroModules: 61673a8ae8fec5df15bad3cb19d1796d5a63280a + NitroMmkv: 4a2d747ce97a4ae740b3cb3a3853366813faf831 + NitroModules: 18e41c298d86fc753fc754969fa9f84044e70711 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 @@ -4044,14 +4016,8 @@ SPEC CHECKSUMS: react-native-background-timer: 4638ae3bee00320753647900b21260b10587b6f7 react-native-cameraroll: ae31ba7ee17d31c5ee05d7bb248742e3af482783 react-native-cookies: d648ab7025833b977c0b19e142503034f5f29411 -<<<<<<< mmkv-v4 - react-native-keyboard-controller: 9ec7ee23328c30251a399cffd8b54324a00343bf - react-native-netinfo: 2e3c27627db7d49ba412bfab25834e679db41e21 -======= react-native-keyboard-controller: c4ca61f44d66c2f8987a7e67e9b78e80dc965c45 - react-native-mmkv: 7b9c7469fa0a7e463f9411ad3e4fe273bd5ff030 react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 ->>>>>>> develop react-native-restart: f6f591aeb40194c41b9b5013901f00e6cf7d0f29 react-native-safe-area-context: 0a3b034bb63a5b684dd2f5fffd3c90ef6ed41ee8 react-native-slider: 6201419b3e3f7c6b7cf2068e0c01274fa86a1da5 From ece27b0e164a17b735388374391fe589c69ee634 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 01:14:00 +0530 Subject: [PATCH 14/50] ios part done... --- ios/MMKVKeyManager.mm | 31 ++++--- ios/NotificationService/Info.plist | 2 + .../NotificationService-Bridging-Header.h | 4 +- ios/Podfile | 6 ++ ios/Podfile.lock | 7 +- ios/RocketChatRN.xcodeproj/project.pbxproj | 20 ++-- ios/RocketChatRN/Info.plist | 2 + ios/ShareRocketChatRN/Info.plist | 2 + ios/Shared/RocketChat/MMKVBridge.mm | 91 +++++-------------- 9 files changed, 70 insertions(+), 95 deletions(-) diff --git a/ios/MMKVKeyManager.mm b/ios/MMKVKeyManager.mm index 5a26b2f13f0..e251a9335c0 100644 --- a/ios/MMKVKeyManager.mm +++ b/ios/MMKVKeyManager.mm @@ -9,7 +9,7 @@ #import "MMKVKeyManager.h" #import "SecureStorage.h" -#import "Shared/RocketChat/MMKVBridge.h" +#import static NSString *toHex(NSString *str) { if (!str) return @""; @@ -35,45 +35,48 @@ static void Logger(NSString *format, ...) { @implementation MMKVKeyManager + (void)initialize { + if (self != [MMKVKeyManager class]) return; + @try { NSString *mmkvPath = [self initializeMMKV]; if (!mmkvPath) { - Logger(@"Failed to initialize MMKV path"); + Logger(@"Failed to initialize MMKV path - check AppGroupIdentifier in Info.plist"); return; } + // --- CRITICAL CHANGE --- + // In v4, for App Groups, you must set the 2nd parameter (groupDir). + // Signature: initializeMMKV:(NSString*)rootDir groupDir:(NSString*)groupDir logLevel:(MMKVLogLevel)logLevel + [MMKV initializeMMKV:nil groupDir:mmkvPath logLevel:MMKVLogInfo]; + SecureStorage *secureStorage = [[SecureStorage alloc] init]; NSString *alias = toHex(@"com.MMKV.default"); NSString *password = [secureStorage getSecureKey:alias]; if (!password || password.length == 0) { - // Fresh install - generate a new key password = [[NSUUID UUID] UUIDString]; [secureStorage setSecureKey:alias value:password options:nil]; Logger(@"Generated new MMKV encryption key"); - } else { - Logger(@"Existing MMKV encryption key found"); } // Verify MMKV can be opened with this key NSData *cryptKey = [password dataUsingEncoding:NSUTF8StringEncoding]; - MMKVBridge *mmkv = [[MMKVBridge alloc] initWithID:@"default" - cryptKey:cryptKey - rootPath:mmkvPath]; + + // Ensure we use MMKVMultiProcess to match the JS side + MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; if (mmkv) { - NSUInteger keyCount = [mmkv count]; - Logger(@"MMKV initialized with encryption, %lu keys found", (unsigned long)keyCount); - } else { - Logger(@"MMKV instance is nil after initialization"); + Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[[mmkv allKeys] count]); } } @catch (NSException *exception) { - Logger(@"MMKV initialization error: %@ - %@", exception.name, exception.reason); + Logger(@"MMKV initialization error: %@", exception.reason); } } + (NSString *)initializeMMKV { - NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"] + ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + if (!appGroup) return nil; NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroup]; diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index b3ed19645bf..92ca329f62c 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -2,6 +2,8 @@ + AppGroupIdentifier + group.ios.chat.rocket AppGroup group.ios.chat.rocket IS_OFFICIAL diff --git a/ios/NotificationService/NotificationService-Bridging-Header.h b/ios/NotificationService/NotificationService-Bridging-Header.h index 1d63c024204..7dcad1fce77 100644 --- a/ios/NotificationService/NotificationService-Bridging-Header.h +++ b/ios/NotificationService/NotificationService-Bridging-Header.h @@ -1,9 +1,9 @@ // -// Use this file to import your target's public headers that you would like to expose to Swift. +// NotificationService-Bridging-Header.h // #import "SecureStorage.h" -#import "../Shared/RocketChat/MMKVBridge.h" +#import "MMKVBridge.h" #import #import #import diff --git a/ios/Podfile b/ios/Podfile index bb0245ea0c5..f6a1843f903 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -8,6 +8,7 @@ prepare_react_native_project! def all_pods pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true + pod 'MMKV', :modular_headers => true pod 'MMKVCore', :modular_headers => true $RNFirebaseAnalyticsWithoutAdIdSupport = true @@ -45,6 +46,11 @@ pre_install do |installer| def pod.build_type; Pod::BuildType.static_library # >= 1.9 end + if ['MMKV', 'MMKVCore', 'react-native-mmkv', 'react-native-nitro-modules'].include?(pod.name) + def pod.build_type; + Pod::BuildType.dynamic_framework + end + end end end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 95f2cf9a5a5..39557efcb81 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -244,6 +244,8 @@ PODS: - libwebp/sharpyuv (1.5.0) - libwebp/webp (1.5.0): - libwebp/sharpyuv + - MMKV (2.2.4): + - MMKVCore (~> 2.2.4) - MMKVCore (2.2.4) - MobileCrypto (0.2.2): - boost @@ -3536,6 +3538,7 @@ DEPENDENCIES: - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - MMKV - MMKVCore - "MobileCrypto (from `../node_modules/@rocket.chat/mobile-crypto`)" - NitroMmkv (from `../node_modules/react-native-mmkv`) @@ -3656,6 +3659,7 @@ SPEC REPOS: - libavif - libdav1d - libwebp + - MMKV - MMKVCore - nanopb - PromisesObjC @@ -3972,6 +3976,7 @@ SPEC CHECKSUMS: libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 + MMKV: 1a8e7dbce7f9cad02c52e1b1091d07bd843aefaf MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df MobileCrypto: 41cd66d5588e979cf95d1ff6ae2eec88eb284ef1 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 @@ -4083,6 +4088,6 @@ SPEC CHECKSUMS: Yoga: 1e91d83a5286cfd3b725eade59274c92270540d4 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 412ae70eb3129cbf7a7884ff29d42de4e7e19073 +PODFILE CHECKSUM: c45a8f910f77486998cd4dbdb417db6c263833ee COCOAPODS: 1.15.2 diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index a3351d11696..9df5ce67301 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -1839,7 +1839,7 @@ inputFileListPaths = ( ); inputPaths = ( - "$TARGET_BUILD_DIR/$INFOPLIST_PATH", + $TARGET_BUILD_DIR/$INFOPLIST_PATH, ); name = "Upload source maps to Bugsnag"; outputFileListPaths = ( @@ -1859,7 +1859,7 @@ inputFileListPaths = ( ); inputPaths = ( - "$TARGET_BUILD_DIR/$INFOPLIST_PATH", + $TARGET_BUILD_DIR/$INFOPLIST_PATH, ); name = "Upload source maps to Bugsnag"; outputFileListPaths = ( @@ -2614,7 +2614,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -2690,7 +2690,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -2948,6 +2948,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)", + "$(SRCROOT)/Shared/RocketChat", ); INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -3001,6 +3002,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)", + "$(SRCROOT)/Shared/RocketChat", ); INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -3217,10 +3219,7 @@ ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); + OTHER_LDFLAGS = "$(inherited) "; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; @@ -3286,10 +3285,7 @@ MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); + OTHER_LDFLAGS = "$(inherited) "; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index f1a315d6f83..3c882f43fb4 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -2,6 +2,8 @@ + AppGroupIdentifier + group.ios.chat.rocket AppGroup group.ios.chat.rocket IS_OFFICIAL diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index ee6013988cd..891574e017b 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -4,6 +4,8 @@ IS_OFFICIAL + AppGroupIdentifier + group.ios.chat.rocket AppGroup group.ios.chat.rocket bugsnag diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index eb9e8e64872..90a1b326423 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -2,16 +2,12 @@ // MMKVBridge.mm // RocketChatRN // -// Bridge to access react-native-mmkv from Swift -// Requires FORCE_POSIX=1 preprocessor definition -// #import "MMKVBridge.h" -#import "MMKV.h" -#import +#import -@interface MMKVBridge() -@property (nonatomic, assign) MMKV *mmkvInstance; +@interface MMKVBridge () +@property (nonatomic, strong) MMKV *mmkv; @end @implementation MMKVBridge @@ -21,92 +17,55 @@ - (instancetype)initWithID:(NSString *)mmapID rootPath:(nullable NSString *)rootPath { self = [super init]; if (self) { - // Initialize MMKV if needed + // 1. Initialize MMKV path globally if provided (e.g., for App Groups) if (rootPath) { - std::string rootPathStr = [rootPath UTF8String]; - MMKV::initializeMMKV(rootPathStr); + [MMKV initializeMMKV:rootPath logLevel:MMKVLogInfo]; } - std::string mmapIDStr = [mmapID UTF8String]; - - if (cryptKey && [cryptKey length] > 0) { - std::string cryptKeyStr((const char *)[cryptKey bytes], [cryptKey length]); - _mmkvInstance = MMKV::mmkvWithID(mmapIDStr, MMKV_MULTI_PROCESS, &cryptKeyStr); + // 2. Open instance with MMKVMultiProcess mode + // This allows the Main App and Notification Service to share data safely. + if (cryptKey && cryptKey.length > 0) { + _mmkv = [MMKV mmkvWithID:mmapID cryptKey:cryptKey mode:MMKVMultiProcess]; } else { - _mmkvInstance = MMKV::mmkvWithID(mmapIDStr, MMKV_MULTI_PROCESS); + _mmkv = [MMKV mmkvWithID:mmapID mode:MMKVMultiProcess]; } } return self; } - (nullable NSString *)stringForKey:(NSString *)key { - if (!_mmkvInstance) return nil; - - std::string keyStr = [key UTF8String]; - std::string valueStr; - bool hasValue = _mmkvInstance->getString(keyStr, valueStr); - - if (hasValue && !valueStr.empty()) { - return [NSString stringWithUTF8String:valueStr.c_str()]; - } - - return nil; + if (!_mmkv) return nil; + return [_mmkv getStringForKey:key]; } - (BOOL)setString:(NSString *)value forKey:(NSString *)key { - if (!_mmkvInstance) return NO; - - std::string keyStr = [key UTF8String]; - std::string valueStr = [value UTF8String]; - - return _mmkvInstance->set(valueStr, keyStr); + if (!_mmkv) return NO; + return [_mmkv setString:value forKey:key]; } - (nullable NSData *)dataForKey:(NSString *)key { - if (!_mmkvInstance) return nil; - - std::string keyStr = [key UTF8String]; - auto buffer = _mmkvInstance->getBytes(keyStr); - - if (buffer.length() > 0) { - return [NSData dataWithBytes:buffer.getPtr() length:buffer.length()]; - } - - return nil; + if (!_mmkv) return nil; + return [_mmkv getDataForKey:key]; } - (BOOL)setData:(NSData *)value forKey:(NSString *)key { - if (!_mmkvInstance) return NO; - - std::string keyStr = [key UTF8String]; - mmkv::MMBuffer buffer((void *)[value bytes], (size_t)[value length], mmkv::MMBufferNoCopy); - - return _mmkvInstance->set(buffer, keyStr); + if (!_mmkv) return NO; + return [_mmkv setData:value forKey:key]; } - (void)removeValueForKey:(NSString *)key { - if (!_mmkvInstance) return; - - std::string keyStr = [key UTF8String]; - _mmkvInstance->removeValueForKey(keyStr); + if (!_mmkv) return; + [_mmkv removeValueForKey:key]; } - (NSArray *)allKeys { - if (!_mmkvInstance) return @[]; - - auto cppKeys = _mmkvInstance->allKeys(); - NSMutableArray *keys = [NSMutableArray arrayWithCapacity:cppKeys.size()]; - - for (const auto& key : cppKeys) { - [keys addObject:[NSString stringWithUTF8String:key.c_str()]]; - } - - return keys; + if (!_mmkv) return @[]; + return [_mmkv allKeys]; } - (NSUInteger)count { - if (!_mmkvInstance) return 0; - return _mmkvInstance->count(); + if (!_mmkv) return 0; + return [[_mmkv allKeys] count]; } -@end +@end \ No newline at end of file From cd6cd9d18ae04285b97ad9cfa700181156460af4 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 01:51:03 +0530 Subject: [PATCH 15/50] coderabbit suggestions --- __mocks__/react-native-mmkv.js | 36 +++++++++++++++++++++++------ ios/Shared/RocketChat/MMKVBridge.mm | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 4a9452ac60a..59917eeabae 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -157,7 +157,11 @@ export function existsMMKV(id) { } export function deleteMMKV(id) { - return storageInstances.delete(id); + const deleted = storageInstances.delete(id); + if (defaultInstance?.id === id) { + defaultInstance = null; + } + return deleted; } // Helper function for configuration comparison @@ -210,6 +214,11 @@ export function useMMKVKeys(instance) { const [allKeys, setKeys] = useState(() => mmkv.getAllKeys()); useMMKVListener(key => { + if (key === undefined) { + setKeys(() => mmkv.getAllKeys()); + return; + } + const currentlyHasKey = allKeys.includes(key); const hasKey = mmkv.contains(key); if (hasKey !== currentlyHasKey) { @@ -223,7 +232,7 @@ export function useMMKVKeys(instance) { /** * Create a custom MMKV hook for a specific type */ -function createMMKVHook(getter) { +function createMMKVHook(getter, onSet) { return (key, instance) => { const mmkv = instance ?? getDefaultMMKVInstance(); @@ -236,6 +245,10 @@ function createMMKVHook(getter) { const set = useCallback( v => { const newValue = typeof v === 'function' ? v(getter(mmkv, key)) : v; + if (onSet) { + onSet(mmkv, key, newValue); + return; + } switch (typeof newValue) { case 'number': case 'string': @@ -256,7 +269,7 @@ function createMMKVHook(getter) { throw new Error(`MMKV: Type ${typeof newValue} is not supported!`); } }, - [key, mmkv] + [key, mmkv, onSet] ); useEffect(() => { @@ -290,10 +303,19 @@ export const useMMKVBoolean = createMMKVHook((instance, key) => instance.getBool /** * Use the object value (JSON stringified) of the given key from the given MMKV storage instance */ -export const useMMKVObject = createMMKVHook((instance, key) => { - const stored = instance.getString(key); - return stored ? JSON.parse(stored) : undefined; -}); +export const useMMKVObject = createMMKVHook( + (instance, key) => { + const stored = instance.getString(key); + return stored ? JSON.parse(stored) : undefined; + }, + (mmkv, key, value) => { + if (value === undefined) { + mmkv.remove(key); + return; + } + mmkv.set(key, JSON.stringify(value)); + } +); /** * Use the buffer value of the given key from the given MMKV storage instance diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 90a1b326423..a8a4fb9ae93 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -19,7 +19,7 @@ - (instancetype)initWithID:(NSString *)mmapID if (self) { // 1. Initialize MMKV path globally if provided (e.g., for App Groups) if (rootPath) { - [MMKV initializeMMKV:rootPath logLevel:MMKVLogInfo]; + [MMKV initializeMMKV:nil groupDir:rootPath logLevel:MMKVLogInfo]; } // 2. Open instance with MMKVMultiProcess mode From b6e91744b67151597eed1f792449607a36f7f14e Mon Sep 17 00:00:00 2001 From: Rohit3523 Date: Tue, 14 Apr 2026 20:22:58 +0000 Subject: [PATCH 16/50] chore: format code and fix lint issues --- __mocks__/react-native-mmkv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 59917eeabae..38c3c33436d 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -218,7 +218,7 @@ export function useMMKVKeys(instance) { setKeys(() => mmkv.getAllKeys()); return; } - + const currentlyHasKey = allKeys.includes(key); const hasKey = mmkv.contains(key); if (hasKey !== currentlyHasKey) { From 9eb3de445b8b5ae8665d6bcc60ca4623a812792f Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 02:17:01 +0530 Subject: [PATCH 17/50] return mmkv count --- ios/Shared/RocketChat/MMKVBridge.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index a8a4fb9ae93..5b7d383d1ec 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -65,7 +65,7 @@ - (void)removeValueForKey:(NSString *)key { - (NSUInteger)count { if (!_mmkv) return 0; - return [[_mmkv allKeys] count]; + return _mmkv.count; } @end \ No newline at end of file From 1cbedadbc6a92c7e2e24e096abc150f04bc988d8 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:19:25 +0530 Subject: [PATCH 18/50] changes --- __mocks__/react-native-mmkv.js | 2 +- ios/MMKVKeyManager.mm | 4 ++-- .../NotificationService-Bridging-Header.h | 1 + ios/Podfile.lock | 2 +- ios/RocketChatRN.xcodeproj/project.pbxproj | 18 ++++++++++++------ 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 38c3c33436d..f6e1fe57f50 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -1,4 +1,4 @@ -// Mock for react-native-mmkv v4 +// Mock for react-native-mmkv const { useState, useEffect, useRef, useMemo, useCallback } = require('react'); // Shared storage between instances with the same id diff --git a/ios/MMKVKeyManager.mm b/ios/MMKVKeyManager.mm index e251a9335c0..4dc0e796c79 100644 --- a/ios/MMKVKeyManager.mm +++ b/ios/MMKVKeyManager.mm @@ -40,7 +40,7 @@ + (void)initialize { @try { NSString *mmkvPath = [self initializeMMKV]; if (!mmkvPath) { - Logger(@"Failed to initialize MMKV path - check AppGroupIdentifier in Info.plist"); + Logger(@"Failed to initialize MMKV path"); return; } @@ -69,7 +69,7 @@ + (void)initialize { Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[[mmkv allKeys] count]); } } @catch (NSException *exception) { - Logger(@"MMKV initialization error: %@", exception.reason); + Logger(@"MMKV initialization error: %@ - %@", exception.name, exception.reason); } } diff --git a/ios/NotificationService/NotificationService-Bridging-Header.h b/ios/NotificationService/NotificationService-Bridging-Header.h index 7dcad1fce77..c947563b1b4 100644 --- a/ios/NotificationService/NotificationService-Bridging-Header.h +++ b/ios/NotificationService/NotificationService-Bridging-Header.h @@ -1,4 +1,5 @@ // +// Use this file to import your target's public headers that you would like to expose to Swift. // NotificationService-Bridging-Header.h // diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 39557efcb81..0e78784c65e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4088,6 +4088,6 @@ SPEC CHECKSUMS: Yoga: 1e91d83a5286cfd3b725eade59274c92270540d4 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: c45a8f910f77486998cd4dbdb417db6c263833ee +PODFILE CHECKSUM: ea2291dfeb1fa428c3e92bdb226dc929b429e19e COCOAPODS: 1.15.2 diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 9df5ce67301..012f6fc0bb3 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -1839,7 +1839,7 @@ inputFileListPaths = ( ); inputPaths = ( - $TARGET_BUILD_DIR/$INFOPLIST_PATH, + "$TARGET_BUILD_DIR/$INFOPLIST_PATH", ); name = "Upload source maps to Bugsnag"; outputFileListPaths = ( @@ -1859,7 +1859,7 @@ inputFileListPaths = ( ); inputPaths = ( - $TARGET_BUILD_DIR/$INFOPLIST_PATH, + "$TARGET_BUILD_DIR/$INFOPLIST_PATH", ); name = "Upload source maps to Bugsnag"; outputFileListPaths = ( @@ -2614,7 +2614,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - $PODS_CONFIGURATION_BUILD_DIR/Firebase, + "$PODS_CONFIGURATION_BUILD_DIR/Firebase", ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -2690,7 +2690,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - $PODS_CONFIGURATION_BUILD_DIR/Firebase, + "$PODS_CONFIGURATION_BUILD_DIR/Firebase", ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -3219,7 +3219,10 @@ ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; @@ -3285,7 +3288,10 @@ MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; From c0a0c713ce5042db961cffda8fbc02ecfe6c9026 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:30:09 +0530 Subject: [PATCH 19/50] making coderabbit happy --- __mocks__/react-native-mmkv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index f6e1fe57f50..4c4dd2a6819 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -274,7 +274,7 @@ function createMMKVHook(getter, onSet) { useEffect(() => { const listener = mmkv.addOnValueChangedListener(changedKey => { - if (changedKey === key) { + if (changedKey === undefined || changedKey === key) { setBump(b => b + 1); } }); From a9b51d519434e0f984b9715397f9e6e66d70e95f Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:57:56 +0530 Subject: [PATCH 20/50] making coderabbit happy --- __mocks__/react-native-mmkv.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index 4c4dd2a6819..e9ad9133715 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -157,6 +157,10 @@ export function existsMMKV(id) { } export function deleteMMKV(id) { + const instance = storageInstances.get(id); + instance?.storage.clear(); + instance?.listeners.splice(0); + const deleted = storageInstances.delete(id); if (defaultInstance?.id === id) { defaultInstance = null; @@ -213,6 +217,10 @@ export function useMMKVKeys(instance) { const mmkv = instance ?? getDefaultMMKVInstance(); const [allKeys, setKeys] = useState(() => mmkv.getAllKeys()); + useEffect(() => { + setKeys(mmkv.getAllKeys()); + }, [mmkv]); + useMMKVListener(key => { if (key === undefined) { setKeys(() => mmkv.getAllKeys()); From 6f2a7bacd104521d7a1c30a2b464628f3d6be979 Mon Sep 17 00:00:00 2001 From: Rohit3523 Date: Wed, 15 Apr 2026 14:29:47 +0000 Subject: [PATCH 21/50] chore: format code and fix lint issues --- __mocks__/react-native-mmkv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index e9ad9133715..73d2286edac 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -220,7 +220,7 @@ export function useMMKVKeys(instance) { useEffect(() => { setKeys(mmkv.getAllKeys()); }, [mmkv]); - + useMMKVListener(key => { if (key === undefined) { setKeys(() => mmkv.getAllKeys()); From 5663b0fbf38d3a016b887d19c4237df2059c7e34 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:20:55 +0530 Subject: [PATCH 22/50] again making coderabbit happy --- __mocks__/react-native-mmkv.js | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index e9ad9133715..69947ab270c 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -106,12 +106,18 @@ class MMKVInstance { } importAllFrom(other) { + if (this.isReadOnly) { + throw new Error('Cannot import values into read-only instance'); + } let count = 0; for (const [key, value] of other.storage.entries()) { this.storage.set(key, value); count++; } this._size = this.storage.size; + if (count > 0) { + this.notifyListeners(undefined); + } return count; } @@ -175,7 +181,11 @@ function isConfigurationEqual(left, right) { } return ( - left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path && left.mode === right.mode + left.encryptionKey === right.encryptionKey && + left.id === right.id && + left.path === right.path && + left.mode === right.mode && + left.readOnly === right.readOnly ); } @@ -183,12 +193,19 @@ function isConfigurationEqual(left, right) { * Use the default, shared MMKV instance or a custom instance with configuration */ export function useMMKV(configuration) { - return useMemo(() => { - if (configuration == null) { - return getDefaultMMKVInstance(); - } - return createMMKV(configuration); - }, [configuration]); + const configurationRef = useRef(); + const instanceRef = useRef(); + + if (configuration == null) { + return getDefaultMMKVInstance(); + } + + if (!instanceRef.current || !isConfigurationEqual(configurationRef.current, configuration)) { + configurationRef.current = configuration; + instanceRef.current = createMMKV(configuration); + } + + return instanceRef.current; } /** From 5e9587cfbb4db4d6d73d8062b63ad399fcb00d38 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:32:31 +0530 Subject: [PATCH 23/50] again making coderabbit happy --- __mocks__/react-native-mmkv.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js index fb96167ea3e..c0e1cedee61 100644 --- a/__mocks__/react-native-mmkv.js +++ b/__mocks__/react-native-mmkv.js @@ -262,10 +262,7 @@ function createMMKVHook(getter, onSet) { const mmkv = instance ?? getDefaultMMKVInstance(); const [bump, setBump] = useState(0); - const value = useMemo(() => { - bump; - return getter(mmkv, key); - }, [mmkv, key, bump]); + const value = useMemo(() => getter(mmkv, key), [mmkv, key, bump]); const set = useCallback( v => { From 04c31031b82e555029010d2bc15d39b3edeee21c Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 5 May 2026 17:08:54 +0530 Subject: [PATCH 24/50] changes --- ios/AppGroup/AppGroup.swift | 4 +++- ios/Libraries/SecureStorage.m | 5 +++-- ios/NotificationService/Info.plist | 2 -- ios/RocketChatRN/Info.plist | 2 -- ios/ShareRocketChatRN/Info.plist | 2 -- ios/ShareRocketChatRN/ShareRocketChatRN.swift | 4 +++- ios/Shared/Extensions/FileManager+Extensions.swift | 7 +++---- 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ios/AppGroup/AppGroup.swift b/ios/AppGroup/AppGroup.swift index f9f2c8efb0b..d0ee43c2ca9 100644 --- a/ios/AppGroup/AppGroup.swift +++ b/ios/AppGroup/AppGroup.swift @@ -17,7 +17,9 @@ class AppGroup: NSObject { var path = "" var suiteName = "" - if let suite = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String { + let suite = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String + ?? Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String + if let suite = suite { suiteName = suite if let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: suiteName) { path = directory.path diff --git a/ios/Libraries/SecureStorage.m b/ios/Libraries/SecureStorage.m index 652265ba377..68428fd6224 100644 --- a/ios/Libraries/SecureStorage.m +++ b/ios/Libraries/SecureStorage.m @@ -64,8 +64,9 @@ - (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier { NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init]; // this value is shared by main app and extensions, so, is the best to be used here - serviceName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; - + serviceName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"] + ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + if(serviceName == nil){ serviceName = [[NSBundle mainBundle] bundleIdentifier]; } diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index 92ca329f62c..b7e9f4ff75c 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -4,8 +4,6 @@ AppGroupIdentifier group.ios.chat.rocket - AppGroup - group.ios.chat.rocket IS_OFFICIAL CFBundleDevelopmentRegion diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 3b59dd86564..bc441b046b0 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -4,8 +4,6 @@ AppGroupIdentifier group.ios.chat.rocket - AppGroup - group.ios.chat.rocket IS_OFFICIAL bugsnag diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index 891574e017b..045b121e69e 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -6,8 +6,6 @@ AppGroupIdentifier group.ios.chat.rocket - AppGroup - group.ios.chat.rocket bugsnag apiKey diff --git a/ios/ShareRocketChatRN/ShareRocketChatRN.swift b/ios/ShareRocketChatRN/ShareRocketChatRN.swift index 576e536cfac..a9fbb159b68 100644 --- a/ios/ShareRocketChatRN/ShareRocketChatRN.swift +++ b/ios/ShareRocketChatRN/ShareRocketChatRN.swift @@ -177,7 +177,9 @@ class ShareRocketChatRN: UIViewController { } private func saveDataToSharedContainer(data: Data, filename: String) -> URL? { - guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String else { + let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String + ?? Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String + guard let appGroup = appGroup else { return nil } guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { diff --git a/ios/Shared/Extensions/FileManager+Extensions.swift b/ios/Shared/Extensions/FileManager+Extensions.swift index 92f60c92c3d..4d67c2747dc 100644 --- a/ios/Shared/Extensions/FileManager+Extensions.swift +++ b/ios/Shared/Extensions/FileManager+Extensions.swift @@ -2,12 +2,11 @@ import Foundation extension FileManager { func groupDir() -> String { - let applicationGroupIdentifier = Bundle.main.string(forKey: "AppGroup") - - guard let path = containerURL(forSecurityApplicationGroupIdentifier: applicationGroupIdentifier)?.path else { + guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String, + let path = containerURL(forSecurityApplicationGroupIdentifier: appGroup)?.path else { return "" } - + return path } } From 01cfa3093cba411dfd28a8713cdeb9cd82c51b08 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 5 May 2026 17:15:15 +0530 Subject: [PATCH 25/50] make it simple --- ios/AppGroup/AppGroup.swift | 4 +--- ios/Libraries/SecureStorage.m | 3 +-- ios/ShareRocketChatRN/ShareRocketChatRN.swift | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ios/AppGroup/AppGroup.swift b/ios/AppGroup/AppGroup.swift index d0ee43c2ca9..fc41cdb9b21 100644 --- a/ios/AppGroup/AppGroup.swift +++ b/ios/AppGroup/AppGroup.swift @@ -17,9 +17,7 @@ class AppGroup: NSObject { var path = "" var suiteName = "" - let suite = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String - ?? Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String - if let suite = suite { + if let suite = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String { suiteName = suite if let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: suiteName) { path = directory.path diff --git a/ios/Libraries/SecureStorage.m b/ios/Libraries/SecureStorage.m index 68428fd6224..6e465b2eead 100644 --- a/ios/Libraries/SecureStorage.m +++ b/ios/Libraries/SecureStorage.m @@ -64,8 +64,7 @@ - (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier { NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init]; // this value is shared by main app and extensions, so, is the best to be used here - serviceName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"] - ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + serviceName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"]; if(serviceName == nil){ serviceName = [[NSBundle mainBundle] bundleIdentifier]; diff --git a/ios/ShareRocketChatRN/ShareRocketChatRN.swift b/ios/ShareRocketChatRN/ShareRocketChatRN.swift index a9fbb159b68..c5b37acf5a9 100644 --- a/ios/ShareRocketChatRN/ShareRocketChatRN.swift +++ b/ios/ShareRocketChatRN/ShareRocketChatRN.swift @@ -177,9 +177,7 @@ class ShareRocketChatRN: UIViewController { } private func saveDataToSharedContainer(data: Data, filename: String) -> URL? { - let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String - ?? Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String - guard let appGroup = appGroup else { + guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String else { return nil } guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { From 9d2e57ad8ba3ff947aa39d50cae415a808903872 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Mon, 11 May 2026 23:24:34 +0530 Subject: [PATCH 26/50] changes --- ios/Podfile | 2 +- ios/Shared/RocketChat/MMKVBridge.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index f6a1843f903..cf854df7463 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -46,7 +46,7 @@ pre_install do |installer| def pod.build_type; Pod::BuildType.static_library # >= 1.9 end - if ['MMKV', 'MMKVCore', 'react-native-mmkv', 'react-native-nitro-modules'].include?(pod.name) + if ['MMKV', 'MMKVCore', 'NitroMmkv', 'NitroModules'].include?(pod.name) def pod.build_type; Pod::BuildType.dynamic_framework end diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 5b7d383d1ec..2840e261f8c 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -17,7 +17,7 @@ - (instancetype)initWithID:(NSString *)mmapID rootPath:(nullable NSString *)rootPath { self = [super init]; if (self) { - // 1. Initialize MMKV path globally if provided (e.g., for App Groups) + // Initialize MMKV if needed if (rootPath) { [MMKV initializeMMKV:nil groupDir:rootPath logLevel:MMKVLogInfo]; } @@ -68,4 +68,4 @@ - (NSUInteger)count { return _mmkv.count; } -@end \ No newline at end of file +@end From 3c97e39ffc2f1a4f28a2d00b027d47cb33151d71 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 12 May 2026 00:11:35 +0530 Subject: [PATCH 27/50] changes --- ios/Libraries/MMKVKeyManager.mm | 10 +++++---- ios/Shared/RocketChat/MMKVBridge.mm | 34 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index 4dc0e796c79..32f81f6ce6a 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -9,6 +9,7 @@ #import "MMKVKeyManager.h" #import "SecureStorage.h" +#import "../Shared/RocketChat/MMKVBridge.h" #import static NSString *toHex(NSString *str) { @@ -63,10 +64,12 @@ + (void)initialize { NSData *cryptKey = [password dataUsingEncoding:NSUTF8StringEncoding]; // Ensure we use MMKVMultiProcess to match the JS side - MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; + MMKVBridge *mmkv = [[MMKVBridge alloc] initWithID:@"default" + cryptKey:cryptKey + rootPath:mmkvPath]; if (mmkv) { - Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[[mmkv allKeys] count]); + Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[mmkv count]); } } @catch (NSException *exception) { Logger(@"MMKV initialization error: %@ - %@", exception.name, exception.reason); @@ -74,8 +77,7 @@ + (void)initialize { } + (NSString *)initializeMMKV { - NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"] - ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroup"]; + NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"]; if (!appGroup) return nil; diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 2840e261f8c..0ceb240cfd0 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -7,7 +7,7 @@ #import @interface MMKVBridge () -@property (nonatomic, strong) MMKV *mmkv; +@property (nonatomic, strong) MMKV *mmkvInstance; @end @implementation MMKVBridge @@ -25,47 +25,47 @@ - (instancetype)initWithID:(NSString *)mmapID // 2. Open instance with MMKVMultiProcess mode // This allows the Main App and Notification Service to share data safely. if (cryptKey && cryptKey.length > 0) { - _mmkv = [MMKV mmkvWithID:mmapID cryptKey:cryptKey mode:MMKVMultiProcess]; + _mmkvInstance = [MMKV mmkvWithID:mmapID cryptKey:cryptKey mode:MMKVMultiProcess]; } else { - _mmkv = [MMKV mmkvWithID:mmapID mode:MMKVMultiProcess]; + _mmkvInstance = [MMKV mmkvWithID:mmapID mode:MMKVMultiProcess]; } } return self; } - (nullable NSString *)stringForKey:(NSString *)key { - if (!_mmkv) return nil; - return [_mmkv getStringForKey:key]; + if (!_mmkvInstance) return nil; + return [_mmkvInstance getStringForKey:key]; } - (BOOL)setString:(NSString *)value forKey:(NSString *)key { - if (!_mmkv) return NO; - return [_mmkv setString:value forKey:key]; + if (!_mmkvInstance) return NO; + return [_mmkvInstance setString:value forKey:key]; } - (nullable NSData *)dataForKey:(NSString *)key { - if (!_mmkv) return nil; - return [_mmkv getDataForKey:key]; + if (!_mmkvInstance) return nil; + return [_mmkvInstance getDataForKey:key]; } - (BOOL)setData:(NSData *)value forKey:(NSString *)key { - if (!_mmkv) return NO; - return [_mmkv setData:value forKey:key]; + if (!_mmkvInstance) return NO; + return [_mmkvInstance setData:value forKey:key]; } - (void)removeValueForKey:(NSString *)key { - if (!_mmkv) return; - [_mmkv removeValueForKey:key]; + if (!_mmkvInstance) return; + [_mmkvInstance removeValueForKey:key]; } - (NSArray *)allKeys { - if (!_mmkv) return @[]; - return [_mmkv allKeys]; + if (!_mmkvInstance) return @[]; + return [_mmkvInstance allKeys]; } - (NSUInteger)count { - if (!_mmkv) return 0; - return _mmkv.count; + if (!_mmkvInstance) return 0; + return _mmkvInstance.count; } @end From 3690323aaeeab7d849379ea4f056b9a08d6cef37 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 12 May 2026 00:25:41 +0530 Subject: [PATCH 28/50] some comment revert --- ios/Libraries/MMKVKeyManager.mm | 5 +++++ ios/Shared/RocketChat/MMKVBridge.mm | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index 32f81f6ce6a..02e5eaefa55 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -55,9 +55,12 @@ + (void)initialize { NSString *password = [secureStorage getSecureKey:alias]; if (!password || password.length == 0) { + // Fresh install - generate a new key password = [[NSUUID UUID] UUIDString]; [secureStorage setSecureKey:alias value:password options:nil]; Logger(@"Generated new MMKV encryption key"); + } else { + Logger(@"Existing MMKV encryption key found"); } // Verify MMKV can be opened with this key @@ -70,6 +73,8 @@ + (void)initialize { if (mmkv) { Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[mmkv count]); + } else { + Logger(@"MMKV instance is nil after initialization"); } } @catch (NSException *exception) { Logger(@"MMKV initialization error: %@ - %@", exception.name, exception.reason); diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 0ceb240cfd0..2f6e4625d8a 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -6,7 +6,7 @@ #import "MMKVBridge.h" #import -@interface MMKVBridge () +@interface MMKVBridge() @property (nonatomic, strong) MMKV *mmkvInstance; @end From 9517b78acd1b92e2c25c28fc82cfcfd099ca5177 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 12 May 2026 01:15:17 +0530 Subject: [PATCH 29/50] remove duplicate mmkv init --- ios/Shared/RocketChat/MMKVBridge.mm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 2f6e4625d8a..6bbf35b890f 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -17,12 +17,7 @@ - (instancetype)initWithID:(NSString *)mmapID rootPath:(nullable NSString *)rootPath { self = [super init]; if (self) { - // Initialize MMKV if needed - if (rootPath) { - [MMKV initializeMMKV:nil groupDir:rootPath logLevel:MMKVLogInfo]; - } - - // 2. Open instance with MMKVMultiProcess mode + // Open instance with MMKVMultiProcess mode // This allows the Main App and Notification Service to share data safely. if (cryptKey && cryptKey.length > 0) { _mmkvInstance = [MMKV mmkvWithID:mmapID cryptKey:cryptKey mode:MMKVMultiProcess]; From b9c0353f4016d12ab1188f5bf4586244c206d18e Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 12 May 2026 21:22:30 +0530 Subject: [PATCH 30/50] ssl fix for mmkv --- ios/Libraries/Challenge.mm | 11 ++++++++++- ios/Shared/RocketChat/MMKVBridge.mm | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ios/Libraries/Challenge.mm b/ios/Libraries/Challenge.mm index c6f38180caf..9ef23533089 100644 --- a/ios/Libraries/Challenge.mm +++ b/ios/Libraries/Challenge.mm @@ -25,7 +25,16 @@ + (MMKVBridge *)getMMKVInstance { NSString *key = [secureStorage getSecureKey:hexKey]; NSData *cryptKey = (key && [key length] > 0) ? [key dataUsingEncoding:NSUTF8StringEncoding] : nil; - MMKVBridge *mmkvBridge = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:nil]; + + // Use same App Group path as MMKVKeyManager.mm to access shared SSL certificates + NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppGroupIdentifier"]; + NSString *rootPath = nil; + if (appGroup) { + NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroup]; + rootPath = [groupURL path]; + } + + MMKVBridge *mmkvBridge = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:rootPath]; return mmkvBridge; } diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 6bbf35b890f..201820eb8ea 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -17,6 +17,11 @@ - (instancetype)initWithID:(NSString *)mmapID rootPath:(nullable NSString *)rootPath { self = [super init]; if (self) { + // Initialize MMKV root directory if custom path provided (App Group storage) + if (rootPath) { + [MMKV initializeMMKV:nil groupDir:rootPath logLevel:MMKVLogInfo]; + } + // Open instance with MMKVMultiProcess mode // This allows the Main App and Notification Service to share data safely. if (cryptKey && cryptKey.length > 0) { From 59b52256b81354a4e386ec6af5a2155e460ebed1 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 13 May 2026 03:12:17 +0530 Subject: [PATCH 31/50] added path --- ios/Libraries/Challenge.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Libraries/Challenge.mm b/ios/Libraries/Challenge.mm index 9ef23533089..bd6c445063b 100644 --- a/ios/Libraries/Challenge.mm +++ b/ios/Libraries/Challenge.mm @@ -31,7 +31,7 @@ + (MMKVBridge *)getMMKVInstance { NSString *rootPath = nil; if (appGroup) { NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroup]; - rootPath = [groupURL path]; + rootPath = [[groupURL path] stringByAppendingPathComponent:@"mmkv"]; } MMKVBridge *mmkvBridge = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:rootPath]; From d12256b79fd44fcd41285257b0630305b29e398a Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 13 May 2026 03:16:20 +0530 Subject: [PATCH 32/50] podfile fix --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index da6469e6e33..0d24a4cf4db 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4142,6 +4142,6 @@ SPEC CHECKSUMS: Yoga: 1e91d83a5286cfd3b725eade59274c92270540d4 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: ea2291dfeb1fa428c3e92bdb226dc929b429e19e +PODFILE CHECKSUM: fbe94b2f7ea5463c7f58efe8f285d04f555284af COCOAPODS: 1.15.2 From 6f044246400ce9315527dd550ae0fa7d300f9eca Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 13 May 2026 03:24:39 +0530 Subject: [PATCH 33/50] remove path --- ios/Libraries/Challenge.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Libraries/Challenge.mm b/ios/Libraries/Challenge.mm index bd6c445063b..9ef23533089 100644 --- a/ios/Libraries/Challenge.mm +++ b/ios/Libraries/Challenge.mm @@ -31,7 +31,7 @@ + (MMKVBridge *)getMMKVInstance { NSString *rootPath = nil; if (appGroup) { NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroup]; - rootPath = [[groupURL path] stringByAppendingPathComponent:@"mmkv"]; + rootPath = [groupURL path]; } MMKVBridge *mmkvBridge = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:rootPath]; From c533a8494c62ec0c258108d1061777ffea0aad4a Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 13 May 2026 22:47:51 +0530 Subject: [PATCH 34/50] remove dead code --- ios/Podfile | 18 ------------------ ios/Podfile.lock | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index cf854df7463..3b0ff5decea 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -77,24 +77,6 @@ post_install do |installer| config.build_settings['HEADER_SEARCH_PATHS'] ||= ['$(inherited)'] config.build_settings['HEADER_SEARCH_PATHS'] << '$(SRCROOT)/..' end - - # Add FORCE_POSIX for MMKV to expose C++ API properly - if target.name == 'react-native-mmkv' - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)'] - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'FORCE_POSIX=1' - end - end - end - - # Add FORCE_POSIX to main project targets that use MMKV C++ API - installer.aggregate_targets.each do |aggregate_target| - aggregate_target.user_project.targets.each do |target| - if ['NotificationService', 'RocketChatRN', 'Rocket.Chat'].include?(target.name) - target.build_configurations.each do |config| - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)'] - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'FORCE_POSIX=1' unless config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].include?('FORCE_POSIX=1') - end - end end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0d24a4cf4db..908cc094a05 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4142,6 +4142,6 @@ SPEC CHECKSUMS: Yoga: 1e91d83a5286cfd3b725eade59274c92270540d4 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: fbe94b2f7ea5463c7f58efe8f285d04f555284af +PODFILE CHECKSUM: ff6fc86ab36edee5c0f439280965fce89ea9372c COCOAPODS: 1.15.2 From 3b9a9b08b5cfd64fa6df9b9c60cae66bd75e49db Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 13 May 2026 22:53:29 +0530 Subject: [PATCH 35/50] comment --- ios/Libraries/MMKVKeyManager.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index 02e5eaefa55..d6f88f55c91 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -45,9 +45,8 @@ + (void)initialize { return; } - // --- CRITICAL CHANGE --- - // In v4, for App Groups, you must set the 2nd parameter (groupDir). - // Signature: initializeMMKV:(NSString*)rootDir groupDir:(NSString*)groupDir logLevel:(MMKVLogLevel)logLevel + // Initialize MMKV against the App Group container so the main app and + // NotificationService share the same storage. [MMKV initializeMMKV:nil groupDir:mmkvPath logLevel:MMKVLogInfo]; SecureStorage *secureStorage = [[SecureStorage alloc] init]; From 414b288a1e194670e87e03e0b5f7a42a2cffcdb6 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Thu, 14 May 2026 22:12:59 +0530 Subject: [PATCH 36/50] fix... --- ios/Shared/RocketChat/MMKVBridge.mm | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ios/Shared/RocketChat/MMKVBridge.mm b/ios/Shared/RocketChat/MMKVBridge.mm index 201820eb8ea..db48f48476f 100644 --- a/ios/Shared/RocketChat/MMKVBridge.mm +++ b/ios/Shared/RocketChat/MMKVBridge.mm @@ -17,18 +17,23 @@ - (instancetype)initWithID:(NSString *)mmapID rootPath:(nullable NSString *)rootPath { self = [super init]; if (self) { - // Initialize MMKV root directory if custom path provided (App Group storage) - if (rootPath) { - [MMKV initializeMMKV:nil groupDir:rootPath logLevel:MMKVLogInfo]; - } + // Idempotent safety net; react-native-mmkv usually initializes MMKV first from JS. + [MMKV initializeMMKV:nil logLevel:MMKVLogInfo]; - // Open instance with MMKVMultiProcess mode - // This allows the Main App and Notification Service to share data safely. - if (cryptKey && cryptKey.length > 0) { - _mmkvInstance = [MMKV mmkvWithID:mmapID cryptKey:cryptKey mode:MMKVMultiProcess]; - } else { - _mmkvInstance = [MMKV mmkvWithID:mmapID mode:MMKVMultiProcess]; + // Normalize: callers may pass either the App Group container path or + // /mmkv. We always resolve to /mmkv so the file + // matches the relativePath react-native-mmkv writes from JS. + NSString *resolvedRootPath = rootPath; + if (resolvedRootPath.length > 0 && ![resolvedRootPath.lastPathComponent isEqualToString:@"mmkv"]) { + resolvedRootPath = [resolvedRootPath stringByAppendingPathComponent:@"mmkv"]; } + + NSData *finalCryptKey = (cryptKey.length > 0) ? cryptKey : nil; + _mmkvInstance = [MMKV mmkvWithID:mmapID + cryptKey:finalCryptKey + rootPath:resolvedRootPath + mode:MMKVMultiProcess + expectedCapacity:0]; } return self; } From ec8e2fbd50f15db44cb98ef7a6ca3e5e5cb1e3d2 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Thu, 14 May 2026 22:38:40 +0530 Subject: [PATCH 37/50] revert few changes --- ios/Libraries/MMKVKeyManager.mm | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index d6f88f55c91..e126c2dd25a 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -10,7 +10,6 @@ #import "MMKVKeyManager.h" #import "SecureStorage.h" #import "../Shared/RocketChat/MMKVBridge.h" -#import static NSString *toHex(NSString *str) { if (!str) return @""; @@ -36,8 +35,6 @@ static void Logger(NSString *format, ...) { @implementation MMKVKeyManager + (void)initialize { - if (self != [MMKVKeyManager class]) return; - @try { NSString *mmkvPath = [self initializeMMKV]; if (!mmkvPath) { @@ -45,10 +42,6 @@ + (void)initialize { return; } - // Initialize MMKV against the App Group container so the main app and - // NotificationService share the same storage. - [MMKV initializeMMKV:nil groupDir:mmkvPath logLevel:MMKVLogInfo]; - SecureStorage *secureStorage = [[SecureStorage alloc] init]; NSString *alias = toHex(@"com.MMKV.default"); NSString *password = [secureStorage getSecureKey:alias]; @@ -65,13 +58,13 @@ + (void)initialize { // Verify MMKV can be opened with this key NSData *cryptKey = [password dataUsingEncoding:NSUTF8StringEncoding]; - // Ensure we use MMKVMultiProcess to match the JS side MMKVBridge *mmkv = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:mmkvPath]; if (mmkv) { - Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[mmkv count]); + NSUInteger keyCount = [mmkv count]; + Logger(@"MMKV initialized with encryption, %lu keys found", (unsigned long)keyCount); } else { Logger(@"MMKV instance is nil after initialization"); } From f9952cf0796a39e75f4ed5e03bb88fa90598f389 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Thu, 14 May 2026 22:39:24 +0530 Subject: [PATCH 38/50] change --- ios/Libraries/MMKVKeyManager.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index e126c2dd25a..93d36491693 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -57,7 +57,6 @@ + (void)initialize { // Verify MMKV can be opened with this key NSData *cryptKey = [password dataUsingEncoding:NSUTF8StringEncoding]; - MMKVBridge *mmkv = [[MMKVBridge alloc] initWithID:@"default" cryptKey:cryptKey rootPath:mmkvPath]; From 336928883bd0d7763504d3595a642c2b75fdce1c Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Thu, 14 May 2026 23:01:02 +0530 Subject: [PATCH 39/50] revert --- ios/PrivacyInfo.xcprivacy | 86 ++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/ios/PrivacyInfo.xcprivacy b/ios/PrivacyInfo.xcprivacy index 900f2e782b1..9d47fd72367 100644 --- a/ios/PrivacyInfo.xcprivacy +++ b/ios/PrivacyInfo.xcprivacy @@ -2,6 +2,51 @@ + + NSPrivacyTracking + + NSPrivacyCollectedDataTypes + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeAudioData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherUserContactInfo + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeUserID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + NSPrivacyAccessedAPITypes @@ -42,46 +87,5 @@ - NSPrivacyCollectedDataTypes - - - NSPrivacyCollectedDataType - NSPrivacyCollectedDataTypeAudioData - NSPrivacyCollectedDataTypeLinked - - NSPrivacyCollectedDataTypePurposes - - NSPrivacyCollectedDataTypePurposeAppFunctionality - - NSPrivacyCollectedDataTypeTracking - - - - NSPrivacyCollectedDataType - NSPrivacyCollectedDataTypeOtherUserContactInfo - NSPrivacyCollectedDataTypeLinked - - NSPrivacyCollectedDataTypePurposes - - NSPrivacyCollectedDataTypePurposeAppFunctionality - - NSPrivacyCollectedDataTypeTracking - - - - NSPrivacyCollectedDataType - NSPrivacyCollectedDataTypeUserID - NSPrivacyCollectedDataTypeLinked - - NSPrivacyCollectedDataTypePurposes - - NSPrivacyCollectedDataTypePurposeAppFunctionality - - NSPrivacyCollectedDataTypeTracking - - - - NSPrivacyTracking - From 50dfefa76068430dccb22269c7302d8765942cde Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Mon, 18 May 2026 20:39:17 +0530 Subject: [PATCH 40/50] Some changes --- ios/Libraries/MMKVKeyManager.mm | 3 +-- ios/NotificationService/NotificationService-Bridging-Header.h | 3 +-- ios/RocketChatRN.xcodeproj/project.pbxproj | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index 93d36491693..f5be75543ed 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -62,8 +62,7 @@ + (void)initialize { rootPath:mmkvPath]; if (mmkv) { - NSUInteger keyCount = [mmkv count]; - Logger(@"MMKV initialized with encryption, %lu keys found", (unsigned long)keyCount); + Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[mmkv count]); } else { Logger(@"MMKV instance is nil after initialization"); } diff --git a/ios/NotificationService/NotificationService-Bridging-Header.h b/ios/NotificationService/NotificationService-Bridging-Header.h index 7437b957a62..cdcc3493ac5 100644 --- a/ios/NotificationService/NotificationService-Bridging-Header.h +++ b/ios/NotificationService/NotificationService-Bridging-Header.h @@ -1,11 +1,10 @@ // // Use this file to import your target's public headers that you would like to expose to Swift. -// NotificationService-Bridging-Header.h // #import "../Libraries/SecureStorage.h" #import "../Libraries/Challenge.h" -#import "MMKVBridge.h" +#import "../Shared/RocketChat/MMKVBridge.h" #import #import #import diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 7bd8709c15f..f52a37b730f 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -3026,7 +3026,6 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)", - "$(SRCROOT)/Shared/RocketChat", ); INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -3080,7 +3079,6 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", "$(SRCROOT)", - "$(SRCROOT)/Shared/RocketChat", ); INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; From ff2acff731940a7e7e50e4626229b9e12533361b Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Mon, 18 May 2026 21:34:02 +0530 Subject: [PATCH 41/50] revert log... --- ios/Libraries/MMKVKeyManager.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/Libraries/MMKVKeyManager.mm b/ios/Libraries/MMKVKeyManager.mm index f5be75543ed..93d36491693 100644 --- a/ios/Libraries/MMKVKeyManager.mm +++ b/ios/Libraries/MMKVKeyManager.mm @@ -62,7 +62,8 @@ + (void)initialize { rootPath:mmkvPath]; if (mmkv) { - Logger(@"MMKV initialized successfully. Keys: %lu", (unsigned long)[mmkv count]); + NSUInteger keyCount = [mmkv count]; + Logger(@"MMKV initialized with encryption, %lu keys found", (unsigned long)keyCount); } else { Logger(@"MMKV instance is nil after initialization"); } From 396a897bd66cc0879f907cf56b3b2e163b6bb46d Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Mon, 18 May 2026 22:35:07 +0530 Subject: [PATCH 42/50] revert change --- ios/RocketChatRN.xcodeproj/project.pbxproj | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index f52a37b730f..5fa60e9f78f 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -309,6 +309,8 @@ 7A1B58422F5F58FF002A6BDE /* VoipPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1B58402F5F58FF002A6BDE /* VoipPayload.swift */; }; 7A1B58442F5F63DB002A6BDE /* AppDelegate+Voip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1B58432F5F63DB002A6BDE /* AppDelegate+Voip.swift */; }; 7A1B58452F5F63DB002A6BDE /* AppDelegate+Voip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1B58432F5F63DB002A6BDE /* AppDelegate+Voip.swift */; }; + 7AVR00012F5F5900002A6BDE /* VoipRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */; }; + 7AVR00022F5F5900002A6BDE /* VoipRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */; }; 7A3704562F7DB36E009085FC /* VoipPerCallDdpRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3704552F7DB36E009085FC /* VoipPerCallDdpRegistry.swift */; }; 7A3704572F7DB36E009085FC /* VoipPerCallDdpRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3704552F7DB36E009085FC /* VoipPerCallDdpRegistry.swift */; }; 7A37D6FF2F896C360095EBA1 /* MediaCallsAnswerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F98EE33D91A93DF8E69F34 /* MediaCallsAnswerRequest.swift */; }; @@ -317,6 +319,9 @@ 7A610CD527ECE38100B8ABDD /* custom.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7A610CD127ECE38100B8ABDD /* custom.ttf */; }; 7A8B30762BCD9D3F00146A40 /* SSLPinning.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A8B30752BCD9D3F00146A40 /* SSLPinning.mm */; }; 7A8B30772BCD9D3F00146A40 /* SSLPinning.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A8B30752BCD9D3F00146A40 /* SSLPinning.mm */; }; + 7AC0A1E02C000010001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; + 7AC0A1E02C000011001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; + 7AC0A1E02C000012001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; 7AAB3E15257E6A6E00707CF6 /* Sender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E01C8282511304100FEF824 /* Sender.swift */; }; 7AAB3E16257E6A6E00707CF6 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E680ED82512990700C9257A /* Request.swift */; }; 7AAB3E17257E6A6E00707CF6 /* ReplyNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED00BB02513E04400A1331F /* ReplyNotification.swift */; }; @@ -367,16 +372,11 @@ 7AACF8AC2C94B28B0082844E /* DecryptedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AACF8AB2C94B28B0082844E /* DecryptedContent.swift */; }; 7AACF8AD2C94B28B0082844E /* DecryptedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AACF8AB2C94B28B0082844E /* DecryptedContent.swift */; }; 7AACF8AE2C94B28B0082844E /* DecryptedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AACF8AB2C94B28B0082844E /* DecryptedContent.swift */; }; - 7AC0A1E02C000010001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; - 7AC0A1E02C000011001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; - 7AC0A1E02C000012001CAA11 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0A1E02C000002001CAA11 /* Challenge.mm */; }; 7ACD4897222860DE00442C55 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ACD4853222860DE00442C55 /* JavaScriptCore.framework */; }; 7ACFE7D92DDE48760090D9BC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ACFE7D82DDE48760090D9BC /* AppDelegate.swift */; }; 7ACFE7DA2DDE48760090D9BC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ACFE7D82DDE48760090D9BC /* AppDelegate.swift */; }; 7AE10C0628A59530003593CB /* Inter.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7AE10C0528A59530003593CB /* Inter.ttf */; }; 7AE10C0828A59530003593CB /* Inter.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7AE10C0528A59530003593CB /* Inter.ttf */; }; - 7AVR00012F5F5900002A6BDE /* VoipRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */; }; - 7AVR00022F5F5900002A6BDE /* VoipRegion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */; }; 7C91FF6756C0285FA3647829 /* MediaCallsAnswerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F98EE33D91A93DF8E69F34 /* MediaCallsAnswerRequest.swift */; }; 85160EB6C143E0493FE5F014 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194D9A8897F4A486C2C6F89A /* ExpoModulesProvider.swift */; }; A2C6E2DD38F8BEE19BFB2E1D /* SecureStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B215A42CFB843397273C7EA /* SecureStorage.m */; }; @@ -646,6 +646,7 @@ 65B9A7192AFC24190088956F /* ringtone.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = ringtone.mp3; sourceTree = ""; }; 66C270192EBBCB570062725F /* MMKVKeyManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMKVKeyManager.h; sourceTree = ""; }; 66C2701A2EBBCB570062725F /* MMKVKeyManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MMKVKeyManager.mm; sourceTree = ""; }; + 6CE8C7A54627937DB698E839 /* Pods-defaults-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-defaults-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-defaults-NotificationService/Pods-defaults-NotificationService.debug.xcconfig"; sourceTree = ""; }; 6FA7E2362F28A9D300A1D45E /* ExternalInputModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExternalInputModule.h; sourceTree = ""; }; 6FA7E2372F28A9D300A1D45E /* ExternalInputModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExternalInputModule.m; sourceTree = ""; }; 7A0000032F1BAFA700B6B4BD /* VoipService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipService.swift; sourceTree = ""; }; @@ -657,20 +658,20 @@ 7A14FCF3257FEB59005BDCD4 /* Official.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Official.xcassets; sourceTree = ""; }; 7A1B58402F5F58FF002A6BDE /* VoipPayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipPayload.swift; sourceTree = ""; }; 7A1B58432F5F63DB002A6BDE /* AppDelegate+Voip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Voip.swift"; sourceTree = ""; }; + 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipRegion.swift; sourceTree = ""; }; 7A3704552F7DB36E009085FC /* VoipPerCallDdpRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipPerCallDdpRegistry.swift; sourceTree = ""; }; 7A610CD127ECE38100B8ABDD /* custom.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = custom.ttf; sourceTree = ""; }; 7A8B30742BCD9D3F00146A40 /* SSLPinning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSLPinning.h; sourceTree = ""; }; 7A8B30752BCD9D3F00146A40 /* SSLPinning.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SSLPinning.mm; sourceTree = ""; }; + 7AC0A1E02C000001001CAA11 /* Challenge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Challenge.h; sourceTree = ""; }; + 7AC0A1E02C000002001CAA11 /* Challenge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Challenge.mm; sourceTree = ""; }; 7AAA749C23043B1D00F1ADE9 /* RocketChatRN-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RocketChatRN-Bridging-Header.h"; sourceTree = ""; }; 7AAB3E52257E6A6E00707CF6 /* Rocket.Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Rocket.Chat.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7AACF8A72C94AB8B0082844E /* EncryptedContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedContent.swift; sourceTree = ""; }; 7AACF8AB2C94B28B0082844E /* DecryptedContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecryptedContent.swift; sourceTree = ""; }; - 7AC0A1E02C000001001CAA11 /* Challenge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Challenge.h; sourceTree = ""; }; - 7AC0A1E02C000002001CAA11 /* Challenge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Challenge.mm; sourceTree = ""; }; 7ACD4853222860DE00442C55 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 7ACFE7D82DDE48760090D9BC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AE10C0528A59530003593CB /* Inter.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Inter.ttf; sourceTree = ""; }; - 7AVR00002F5F5900002A6BDE /* VoipRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipRegion.swift; sourceTree = ""; }; 83F98EE33D91A93DF8E69F34 /* MediaCallsAnswerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaCallsAnswerRequest.swift; sourceTree = ""; }; 88ED4E003393D3A9256F4EB3 /* Pods_defaults_Rocket_Chat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_defaults_Rocket_Chat.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9B215A42CFB843397273C7EA /* SecureStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = SecureStorage.m; sourceTree = ""; }; From e222e36d891981966c5d49e90bbb3ddae48a59e3 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 00:04:07 +0530 Subject: [PATCH 43/50] change --- ios/Shared/Extensions/FileManager+Extensions.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ios/Shared/Extensions/FileManager+Extensions.swift b/ios/Shared/Extensions/FileManager+Extensions.swift index 4d67c2747dc..4da31dbfac3 100644 --- a/ios/Shared/Extensions/FileManager+Extensions.swift +++ b/ios/Shared/Extensions/FileManager+Extensions.swift @@ -2,8 +2,9 @@ import Foundation extension FileManager { func groupDir() -> String { - guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String, - let path = containerURL(forSecurityApplicationGroupIdentifier: appGroup)?.path else { + let applicationGroupIdentifier = Bundle.main.string(forKey: "AppGroupIdentifier") + + guard let path = containerURL(forSecurityApplicationGroupIdentifier: applicationGroupIdentifier)?.path else { return "" } From 3e3a98df35e2721ccc31571180d312afba788f8f Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 00:05:38 +0530 Subject: [PATCH 44/50] fix new line --- ios/Shared/Extensions/FileManager+Extensions.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/Shared/Extensions/FileManager+Extensions.swift b/ios/Shared/Extensions/FileManager+Extensions.swift index 4da31dbfac3..cd334e5e428 100644 --- a/ios/Shared/Extensions/FileManager+Extensions.swift +++ b/ios/Shared/Extensions/FileManager+Extensions.swift @@ -3,11 +3,10 @@ import Foundation extension FileManager { func groupDir() -> String { let applicationGroupIdentifier = Bundle.main.string(forKey: "AppGroupIdentifier") - guard let path = containerURL(forSecurityApplicationGroupIdentifier: applicationGroupIdentifier)?.path else { return "" } - + return path } } From aae99f80af7f0a3ca719c508fddcc7e61c0857f9 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 01:13:01 +0530 Subject: [PATCH 45/50] lock file update --- pnpm-lock.yaml | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98db3b65a80..d322c59a9a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,7 +89,7 @@ importers: version: 0.31.31 '@rocket.chat/mobile-crypto': specifier: RocketChat/rocket.chat-mobile-crypto - version: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/57deaffbcda0453c34987efb81d722da7e7a4f9e(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@rocket.chat/sdk': specifier: RocketChat/Rocket.Chat.js.SDK#mobile version: https://codeload.github.com/RocketChat/Rocket.Chat.js.SDK/tar.gz/b6d2b3f25b0ff8283dd71faf6dae720c47fecd8f @@ -265,11 +265,14 @@ importers: specifier: 2.3.0 version: 2.3.0 react-native-mmkv: - specifier: 3.3.3 - version: 3.3.3(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + specifier: ^4.1.2 + version: 4.3.1(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-modal: specifier: 13.0.1 version: 13.0.1(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + react-native-nitro-modules: + specifier: ^0.33.9 + version: 0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-notifier: specifier: 1.6.1 version: 1.6.1(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -2450,8 +2453,8 @@ packages: '@rocket.chat/message-parser@0.31.31': resolution: {integrity: sha512-YWHdin2ejndwgQJXlHIzAmQB+xvZLeEOqOkPq8RxdyTjAaGo1DbBCrc0aU7u0LOUnGN+jm3H4grnYdI9SPwitA==} - '@rocket.chat/mobile-crypto@https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/57deaffbcda0453c34987efb81d722da7e7a4f9e': - resolution: {gitHosted: true, tarball: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/57deaffbcda0453c34987efb81d722da7e7a4f9e} + '@rocket.chat/mobile-crypto@https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498': + resolution: {gitHosted: true, integrity: sha512-R0vC6djmuhHEo6mHtMdk7ksdBpIZX4o2mqpro6MXUmOFxIiC/yZQznpmPBM722vfVqsV2Ny6NezngK8IwxtCkw==, tarball: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498} version: 0.2.2 peerDependencies: react: '*' @@ -6484,11 +6487,12 @@ packages: resolution: {integrity: sha512-9l/kkT1QM0i0xAKkOADkP6jIMhqiS+R/eSKBS/lsUmuMYMqboClyrwTFFZwUcaVIN0SpeH4wOKhYTqCnFgRsEw==} engines: {node: '>= 0.6'} - react-native-mmkv@3.3.3: - resolution: {integrity: sha512-GMsfOmNzx0p5+CtrCFRVtpOOMYNJXuksBVARSQrCFaZwjUyHJdQzcN900GGaFFNTxw2fs8s5Xje//RDKj9+PZA==} + react-native-mmkv@4.3.1: + resolution: {integrity: sha512-APyGGaaHtayVgT18dBM8QGGZKr9pGfSTiBwbbPNzhGGfJQSU7awLGRGq879OqYl31HmVks9hOBLCs+qfgacRZg==} peerDependencies: react: '*' react-native: '*' + react-native-nitro-modules: '*' react-native-modal@13.0.1: resolution: {integrity: sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==} @@ -6496,6 +6500,12 @@ packages: react: '*' react-native: '>=0.65.0' + react-native-nitro-modules@0.33.9: + resolution: {integrity: sha512-BM9C5mCGYYjrc8CDWZZ0anLWU/knH2xaEuFzvzogKTOW6fzgS6mmsCdM3ty+AhImJNSYwK19DLrHaqwnrrwEzw==} + peerDependencies: + react: '*' + react-native: '*' + react-native-notifier@1.6.1: resolution: {integrity: sha512-uq58vefWCmgk9B/GU0Z9P6M8Su5IuRBtKmroSX7luISEdh3r8QvJo/G6jgK2sO0QhM5QvJOGWBDm1JGEkYL4IQ==} peerDependencies: @@ -10463,7 +10473,7 @@ snapshots: dependencies: tldts: 5.7.112 - '@rocket.chat/mobile-crypto@https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/57deaffbcda0453c34987efb81d722da7e7a4f9e(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': + '@rocket.chat/mobile-crypto@https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0) @@ -15149,10 +15159,11 @@ snapshots: dependencies: mime-db: 1.37.0 - react-native-mmkv@3.3.3(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + react-native-mmkv@4.3.1(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0) + react-native-nitro-modules: 0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-modal@13.0.1(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: @@ -15161,6 +15172,11 @@ snapshots: react-native: 0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0) react-native-animatable: 1.3.3 + react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-native: 0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0) + react-native-notifier@1.6.1(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 From 49010785679c4885c72f4eda4fe58da2f65d5d5c Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 01:15:04 +0530 Subject: [PATCH 46/50] lock file fixed --- pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d322c59a9a1..510de2a6bf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -266,7 +266,7 @@ importers: version: 2.3.0 react-native-mmkv: specifier: ^4.1.2 - version: 4.3.1(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: 4.1.2(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-modal: specifier: 13.0.1 version: 13.0.1(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -2454,7 +2454,7 @@ packages: resolution: {integrity: sha512-YWHdin2ejndwgQJXlHIzAmQB+xvZLeEOqOkPq8RxdyTjAaGo1DbBCrc0aU7u0LOUnGN+jm3H4grnYdI9SPwitA==} '@rocket.chat/mobile-crypto@https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498': - resolution: {gitHosted: true, integrity: sha512-R0vC6djmuhHEo6mHtMdk7ksdBpIZX4o2mqpro6MXUmOFxIiC/yZQznpmPBM722vfVqsV2Ny6NezngK8IwxtCkw==, tarball: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498} + resolution: {gitHosted: true, tarball: https://codeload.github.com/RocketChat/rocket.chat-mobile-crypto/tar.gz/a6b848345a33be3a1bcfadecde1fb0f516abc498} version: 0.2.2 peerDependencies: react: '*' @@ -6487,8 +6487,8 @@ packages: resolution: {integrity: sha512-9l/kkT1QM0i0xAKkOADkP6jIMhqiS+R/eSKBS/lsUmuMYMqboClyrwTFFZwUcaVIN0SpeH4wOKhYTqCnFgRsEw==} engines: {node: '>= 0.6'} - react-native-mmkv@4.3.1: - resolution: {integrity: sha512-APyGGaaHtayVgT18dBM8QGGZKr9pGfSTiBwbbPNzhGGfJQSU7awLGRGq879OqYl31HmVks9hOBLCs+qfgacRZg==} + react-native-mmkv@4.1.2: + resolution: {integrity: sha512-6LHb2DQBXuo96Aues13EugmlWw/HAYuh3KoJoQNrC4JsBwn3J3KiRYAg2mCm5Je0VYq2YsmbgZG7XJwX/WFYZA==} peerDependencies: react: '*' react-native: '*' @@ -15159,7 +15159,7 @@ snapshots: dependencies: mime-db: 1.37.0 - react-native-mmkv@4.3.1(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + react-native-mmkv@4.1.2(react-native-nitro-modules@0.33.9(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.25.9)(@react-native-community/cli@20.0.0(typescript@5.9.3))(@react-native/metro-config@0.81.5(@babel/core@7.25.9))(@types/react@19.1.17)(react@19.1.0) From 2dfb0c49c74355a2a00921fc0ef9c6b691a04be5 Mon Sep 17 00:00:00 2001 From: Rohit Bansal <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 23:35:09 +0530 Subject: [PATCH 47/50] Update ios/Podfile Co-authored-by: Diego Mello --- ios/Podfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 3b0ff5decea..1091512b006 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -46,11 +46,10 @@ pre_install do |installer| def pod.build_type; Pod::BuildType.static_library # >= 1.9 end - if ['MMKV', 'MMKVCore', 'NitroMmkv', 'NitroModules'].include?(pod.name) - def pod.build_type; + elsif ['MMKV', 'MMKVCore', 'NitroMmkv', 'NitroModules'].include?(pod.name) + def pod.build_type Pod::BuildType.dynamic_framework end - end end end end From c758f94dd49f8d6d4a76429153bc8485fc753121 Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Tue, 19 May 2026 23:35:44 +0530 Subject: [PATCH 48/50] requested changes --- app/lib/methods/userPreferences.test.ts | 23 +++++++++++++++++++++++ app/lib/methods/userPreferences.ts | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 app/lib/methods/userPreferences.test.ts diff --git a/app/lib/methods/userPreferences.test.ts b/app/lib/methods/userPreferences.test.ts new file mode 100644 index 00000000000..d43c0c2521d --- /dev/null +++ b/app/lib/methods/userPreferences.test.ts @@ -0,0 +1,23 @@ +import userPreferences from './userPreferences'; + +describe('UserPreferences', () => { + beforeEach(() => userPreferences.clearAll()); + + it('getBool returns false for stored false', () => { + userPreferences.setBool('k', false); + expect(userPreferences.getBool('k')).toBe(false); + }); + + it('getBool returns null for unset key', () => { + expect(userPreferences.getBool('missing')).toBeNull(); + }); + + it('getNumber returns 0 for stored 0', () => { + userPreferences.setNumber('k', 0); + expect(userPreferences.getNumber('k')).toBe(0); + }); + + it('getNumber returns null for unset key', () => { + expect(userPreferences.getNumber('missing')).toBeNull(); + }); +}); diff --git a/app/lib/methods/userPreferences.ts b/app/lib/methods/userPreferences.ts index 2ff9544fd99..806d124317b 100644 --- a/app/lib/methods/userPreferences.ts +++ b/app/lib/methods/userPreferences.ts @@ -106,7 +106,7 @@ class UserPreferences { getBool(key: string): boolean | null { try { - return this.mmkv.getBoolean(key) || null; + return this.mmkv.getBoolean(key) ?? null; } catch { return null; } @@ -135,7 +135,7 @@ class UserPreferences { getNumber(key: string): number | null { try { - return this.mmkv.getNumber(key) || null; + return this.mmkv.getNumber(key) ?? null; } catch { return null; } From 18a0737870213dff8797a3129018087f04e707fd Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 20 May 2026 00:25:22 +0530 Subject: [PATCH 49/50] podfile fix --- ios/Podfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 1091512b006..920a87db925 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -46,10 +46,6 @@ pre_install do |installer| def pod.build_type; Pod::BuildType.static_library # >= 1.9 end - elsif ['MMKV', 'MMKVCore', 'NitroMmkv', 'NitroModules'].include?(pod.name) - def pod.build_type - Pod::BuildType.dynamic_framework - end end end end From 1bfb186a138d0046268272ec8607a5705876de1c Mon Sep 17 00:00:00 2001 From: Rohit <40559587+Rohit3523@users.noreply.github.com> Date: Wed, 20 May 2026 00:38:41 +0530 Subject: [PATCH 50/50] sync checksum --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 908cc094a05..4c1a14d9919 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4142,6 +4142,6 @@ SPEC CHECKSUMS: Yoga: 1e91d83a5286cfd3b725eade59274c92270540d4 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: ff6fc86ab36edee5c0f439280965fce89ea9372c +PODFILE CHECKSUM: 02cbfc92458eddfe5b3aa3acd6023cbc9c5ee22f COCOAPODS: 1.15.2