diff --git a/native/android/app/src/cpp/CommMMKV.cpp b/native/android/app/src/cpp/CommMMKV.cpp --- a/native/android/app/src/cpp/CommMMKV.cpp +++ b/native/android/app/src/cpp/CommMMKV.cpp @@ -37,6 +37,53 @@ } return std::nullopt; } + + static bool setInt(std::string key, int value) { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod<jboolean(std::string, int)>("setInt"); + return method(cls, key, value); + } + + static std::optional<int> getInt(std::string key, int noValue) { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod<JInteger(std::string, int)>("getInt"); + const auto result = method(cls, key, noValue); + if (result) { + return result->value(); + } + return std::nullopt; + } + + static std::vector<std::string> getAllKeys() { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod<JArrayClass<JString>()>("getAllKeys"); + auto methodResult = method(cls); + + std::vector<std::string> result; + for (int i = 0; i < methodResult->size(); i++) { + result.push_back(methodResult->getElement(i)->toStdString()); + } + + return result; + } + + static void removeKeys(const std::vector<std::string> &keys) { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod<void(local_ref<JArrayClass<JString>>)>( + "removeKeys"); + + local_ref<JArrayClass<JString>> keysJava = + JArrayClass<JString>::newArray(keys.size()); + + for (int i = 0; i < keys.size(); i++) { + keysJava->setElement(i, *make_jstring(keys[i])); + } + method(cls, keysJava); + } }; namespace comm { @@ -65,4 +112,29 @@ return result; } +bool CommMMKV::setInt(std::string key, int value) { + bool result; + NativeAndroidAccessProvider::runTask( + [&]() { result = CommMMKVJavaClass::setInt(key, value); }); + return result; +} + +std::optional<int> CommMMKV::getInt(std::string key, int noValue) { + std::optional<int> result; + NativeAndroidAccessProvider::runTask( + [&]() { result = CommMMKVJavaClass::getInt(key, noValue); }); + return result; +} + +std::vector<std::string> CommMMKV::getAllKeys() { + std::vector<std::string> result; + NativeAndroidAccessProvider::runTask( + [&]() { result = CommMMKVJavaClass::getAllKeys(); }); + return result; +} + +void CommMMKV::removeKeys(const std::vector<std::string> &keys) { + NativeAndroidAccessProvider::runTask( + [&]() { CommMMKVJavaClass::removeKeys(keys); }); +} } // namespace comm diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java --- a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java +++ b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java @@ -95,4 +95,31 @@ initialize(); return getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey).decodeString(key); } + + public static boolean setInt(String key, int value) { + initialize(); + return getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey) + .encode(key, value); + } + + public static Integer getInt(String key, int noValue) { + initialize(); + int value = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey) + .decodeInt(key, noValue); + if (value == noValue) { + return null; + } + return value; + } + + public static String[] getAllKeys() { + initialize(); + return getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey).allKeys(); + } + + public static void removeKeys(String[] keys) { + initialize(); + getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey) + .removeValuesForKeys(keys); + } } diff --git a/native/cpp/CommonCpp/Tools/CommMMKV.h b/native/cpp/CommonCpp/Tools/CommMMKV.h --- a/native/cpp/CommonCpp/Tools/CommMMKV.h +++ b/native/cpp/CommonCpp/Tools/CommMMKV.h @@ -2,6 +2,7 @@ #include <optional> #include <string> +#include <vector> namespace comm { class CommMMKV { @@ -11,5 +12,19 @@ static void clearSensitiveData(); static bool setString(std::string key, std::string value); static std::optional<std::string> getString(std::string key); + + static bool setInt(std::string key, int value); + + // MMKV API can't return null when we try to get integer that + // doesn't exist. It allows us to set default value that is + // returned instead in case the integer isn't present. The + // developer should pass as `noValue` the value that they + // know should never be set under certain key. Implementation + // will pass `noValue` as default value and return `std::nullopt` + // in case MMKV returns default value. + static std::optional<int> getInt(std::string key, int noValue); + + static std::vector<std::string> getAllKeys(); + static void removeKeys(const std::vector<std::string> &keys); }; } // namespace comm diff --git a/native/ios/Comm/CommMMKV.mm b/native/ios/Comm/CommMMKV.mm --- a/native/ios/Comm/CommMMKV.mm +++ b/native/ios/Comm/CommMMKV.mm @@ -130,4 +130,62 @@ return std::string([value UTF8String]); } +bool CommMMKV::setInt(std::string key, int value) { + CommMMKV::initialize(); + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + + BOOL result = + [mmkv setInt64:value + forKey:[NSString stringWithCString:key.c_str() + encoding:NSUTF8StringEncoding]]; + + if (!result) { + Logger::log("Attempt to write in background or failure during write."); + } + return result; +} + +std::optional<int> CommMMKV::getInt(std::string key, int noValue) { + CommMMKV::initialize(); + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + + int value = + [mmkv getInt64ForKey:[NSString stringWithCString:key.c_str() + encoding:NSUTF8StringEncoding] + defaultValue:noValue + hasValue:nil]; + + if (value == noValue) { + return std::nullopt; + } + + return value; +} + +std::vector<std::string> CommMMKV::getAllKeys() { + CommMMKV::initialize(); + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + + NSArray<NSString *> *allKeys = [mmkv allKeys]; + std::vector<std::string> result; + + for (NSString *key in allKeys) { + result.emplace_back(std::string([key UTF8String])); + } + + return result; +} + +void CommMMKV::removeKeys(const std::vector<std::string> &keys) { + CommMMKV::initialize(); + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + + NSMutableArray<NSString *> *keysObjC = [[NSMutableArray alloc] init]; + for (const auto &key : keys) { + [keysObjC addObject:[NSString stringWithCString:key.c_str() + encoding:NSUTF8StringEncoding]]; + } + [mmkv removeValuesForKeys:keysObjC]; +} + } // namespace comm