diff --git a/native/android/app/src/cpp/CommSecureStore.cpp b/native/android/app/src/cpp/CommSecureStore.cpp new file mode 100644 index 0000000000..71987e96a4 --- /dev/null +++ b/native/android/app/src/cpp/CommSecureStore.cpp @@ -0,0 +1,39 @@ +#include "CommSecureStore.h" +#include + +using namespace facebook::jni; + +class CommSecureStoreJavaClass : public JavaClass { +public: + static auto constexpr kJavaDescriptor = + "Lapp/comm/android/fbjni/CommSecureStore;"; + + static void set(std::string key, std::string value) { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod("set"); + method(cls, key, value); + } + + static folly::Optional get(std::string key) { + static const auto cls = javaClassStatic(); + static auto method = + cls->getStaticMethod("get"); + const auto result = method(cls, key); + return (result) ? folly::Optional(result->toStdString()) + : folly::none; + } +}; + +namespace comm { + +void CommSecureStore::set(const std::string key, const std::string value) + const { + CommSecureStoreJavaClass::set(key, value); +} + +folly::Optional CommSecureStore::get(const std::string key) const { + return CommSecureStoreJavaClass::get(key); +} + +} // namespace comm diff --git a/native/android/app/src/main/java/app/comm/android/CommCoreJSIModulePackage.java b/native/android/app/src/main/java/app/comm/android/CommCoreJSIModulePackage.java index 80ad4d6615..7795871a0c 100644 --- a/native/android/app/src/main/java/app/comm/android/CommCoreJSIModulePackage.java +++ b/native/android/app/src/main/java/app/comm/android/CommCoreJSIModulePackage.java @@ -1,15 +1,16 @@ package app.comm.android; -import com.facebook.react.bridge.JSIModulePackage; import com.facebook.react.bridge.JSIModuleSpec; import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.ReactApplicationContext; import java.util.Collections; import java.util.List; import app.comm.android.fbjni.CommHybrid; + import com.swmansion.reanimated.ReanimatedJSIModulePackage; public class CommCoreJSIModulePackage extends ReanimatedJSIModulePackage { + @Override public List getJSIModules( ReactApplicationContext reactApplicationContext, diff --git a/native/android/app/src/main/java/app/comm/android/MainApplication.java b/native/android/app/src/main/java/app/comm/android/MainApplication.java index 0c44dfe355..dbb4253490 100644 --- a/native/android/app/src/main/java/app/comm/android/MainApplication.java +++ b/native/android/app/src/main/java/app/comm/android/MainApplication.java @@ -1,5 +1,6 @@ package app.comm.android; +import app.comm.android.fbjni.CommSecureStore; import app.comm.android.generated.BasePackageList; import androidx.multidex.MultiDexApplication; @@ -9,19 +10,16 @@ import org.unimodules.adapters.react.ModuleRegistryAdapter; import org.unimodules.adapters.react.ReactModuleRegistryProvider; -import org.unimodules.core.interfaces.SingletonModule; import com.facebook.react.PackageList; -import com.facebook.hermes.reactexecutor.HermesExecutorFactory; -import com.facebook.react.bridge.JavaScriptExecutorFactory; import com.facebook.react.bridge.JSIModulePackage; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; +import expo.modules.securestore.SecureStoreModule; import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage; @@ -70,6 +68,10 @@ protected String getJSMainModuleName() { @Override protected JSIModulePackage getJSIModulePackage() { + SecureStoreModule secureStoreModule = (SecureStoreModule) + mModuleRegistryProvider.get(getApplicationContext()) + .getExportedModuleOfClass(SecureStoreModule.class); + CommSecureStore.getInstance().initialize(secureStoreModule); return new CommCoreJSIModulePackage(); } }; diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/CommSecureStore.java b/native/android/app/src/main/java/app/comm/android/fbjni/CommSecureStore.java new file mode 100644 index 0000000000..1a14997649 --- /dev/null +++ b/native/android/app/src/main/java/app/comm/android/fbjni/CommSecureStore.java @@ -0,0 +1,86 @@ +package app.comm.android.fbjni; + +import org.unimodules.core.Promise; +import org.unimodules.core.arguments.MapArguments; +import org.unimodules.core.arguments.ReadableArguments; + +import expo.modules.securestore.SecureStoreModule; + +public class CommSecureStore { + + private static final CommSecureStore instance = new CommSecureStore(); + private SecureStoreModule secureStoreModule = null; + private final ReadableArguments readableArguments; + + private CommSecureStore() { + this.readableArguments = new MapArguments(); + } + + public static CommSecureStore getInstance() { + return CommSecureStore.instance; + } + + public void initialize(SecureStoreModule secureStoreModule) { + this.secureStoreModule = secureStoreModule; + } + + private void checkModule() { + if (this.secureStoreModule == null) { + throw new RuntimeException( + "secure store module has not been initialized" + ); + } + } + + private void internalSet(String key, String value) { + this.checkModule(); + Promise promise = new Promise() { + @Override + public void resolve(Object value) {} + + @Override + public void reject(String code, String message, Throwable e) { + throw new RuntimeException("secure store set error: " + message); + } + }; + this.secureStoreModule.setValueWithKeyAsync( + value, + key, + this.readableArguments, + promise + ); + } + + private String internalGet(String key) { + this.checkModule(); + final String[] result = {null}; + + Promise promise = new Promise() { + @Override + public void resolve(Object value) { + result[0] = (String)value; + } + + @Override + public void reject(String code, String message, Throwable e) { + throw new RuntimeException("secure store get error: " + message); + } + }; + // The following call will resolve the promise before it returns + this.secureStoreModule.getValueWithKeyAsync( + key, + this.readableArguments, + promise + ); + + return result[0]; + } + + public static void set(String key, String value) { + getInstance().internalSet(key, value); + } + + public static String get(String key) { + return getInstance().internalGet(key); + } +}