From 11166985ef65b253fcb7080289619c31466ead7a Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Tue, 17 Jul 2018 16:00:21 +0100 Subject: [PATCH] plugin: add app.datadir API to get writable path Adds app.datadir to the bridge to access a writable persistent path from the nodejs-mobile runtime, which should be the FilesDir on Android and the NSDocumentDirectory on iOS. Also sets the os.tmpdir() to the CacheDir on Android. --- android/src/main/cpp/native-lib.cpp | 11 +++++++++ android/src/main/cpp/rn-bridge.cpp | 24 +++++++++++++++++++ android/src/main/cpp/rn-bridge.h | 1 + .../RNNodeJsMobileModule.java | 14 +++++++++++ .../builtin_modules/rn-bridge/index.js | 9 +++++++ ios/NodeRunner.mm | 3 +++ ios/rn-bridge.cpp | 24 +++++++++++++++++++ ios/rn-bridge.h | 1 + 8 files changed, 87 insertions(+) diff --git a/android/src/main/cpp/native-lib.cpp b/android/src/main/cpp/native-lib.cpp index d4e8ecf..f439962 100644 --- a/android/src/main/cpp/native-lib.cpp +++ b/android/src/main/cpp/native-lib.cpp @@ -51,6 +51,17 @@ Java_com_janeasystems_rn_1nodejs_1mobile_RNNodeJsMobileModule_getCurrentABIName( return env->NewStringUTF(CURRENT_ABI_NAME); } +extern "C" +JNIEXPORT void JNICALL +Java_com_janeasystems_rn_1nodejs_1mobile_RNNodeJsMobileModule_registerNodeDataDirPath( + JNIEnv *env, + jobject /* this */, + jstring dataDir) { + const char* nativeDataDir = env->GetStringUTFChars(dataDir, 0); + rn_register_node_data_dir_path(nativeDataDir); + env->ReleaseStringUTFChars(dataDir, nativeDataDir); +} + #define APPNAME "RNBRIDGE" void rcv_message(const char* channel_name, const char* msg) { diff --git a/android/src/main/cpp/rn-bridge.cpp b/android/src/main/cpp/rn-bridge.cpp index 72dc6c5..cc7fbc8 100644 --- a/android/src/main/cpp/rn-bridge.cpp +++ b/android/src/main/cpp/rn-bridge.cpp @@ -181,6 +181,18 @@ class Channel { }; }; +char* datadir_path = NULL; +/* + * Called by the react-native plug-in to register the datadir, + * representing a writable path. Expected to be called once, + * while the plug-in initializes. + */ +void rn_register_node_data_dir_path(const char* path) { + size_t pathLength = strlen(path); + datadir_path = (char*)calloc(sizeof(char), pathLength + 1); + strncpy(datadir_path, path, pathLength); +} + rn_bridge_cb embedder_callback=NULL; /** @@ -304,6 +316,17 @@ napi_value Method_SendMessage(napi_env env, napi_callback_info info) { return nullptr; } +/** + * Get the registered datadir + */ +napi_value Method_GetDataDir(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, datadir_path!=NULL, "Data directory not set from native side."); + napi_value return_datadir; + size_t str_len = strlen(datadir_path); + NAPI_CALL(env, napi_create_string_utf8(env, datadir_path, str_len, &return_datadir)); + return return_datadir; +} + #define DECLARE_NAPI_METHOD(name, func) \ { name, 0, func, 0, 0, 0, napi_default, 0 } @@ -312,6 +335,7 @@ napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_METHOD("sendMessage", Method_SendMessage), DECLARE_NAPI_METHOD("registerChannel", Method_RegisterChannel), + DECLARE_NAPI_METHOD("getDataDir", Method_GetDataDir), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties)); return exports; diff --git a/android/src/main/cpp/rn-bridge.h b/android/src/main/cpp/rn-bridge.h index 3424048..2c357af 100644 --- a/android/src/main/cpp/rn-bridge.h +++ b/android/src/main/cpp/rn-bridge.h @@ -4,5 +4,6 @@ typedef void (*rn_bridge_cb)(const char* channelName, const char* message); void rn_register_bridge_cb(rn_bridge_cb); void rn_bridge_notify(const char* channelName, const char *message); +void rn_register_node_data_dir_path(const char* path); #endif diff --git a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java index 4ec4b23..a89eb8a 100644 --- a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java +++ b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java @@ -18,6 +18,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.SharedPreferences; +import android.system.Os; +import android.system.ErrnoException; import java.io.*; import java.util.*; @@ -74,6 +76,16 @@ public RNNodeJsMobileModule(ReactApplicationContext reactContext) { trashDirPath = filesDirPath + "/" + TRASH_DIR; nativeAssetsPath = BUILTIN_NATIVE_ASSETS_PREFIX + getCurrentABIName(); + // Sets the TMPDIR environment to the cacheDir, to be used in Node as os.tmpdir + try { + Os.setenv("TMPDIR", reactContext.getCacheDir().getAbsolutePath(), true); + } catch (ErrnoException e) { + e.printStackTrace(); + } + + // Register the filesDir as the Node data dir. + registerNodeDataDirPath(filesDirPath); + asyncInit(); } @@ -241,6 +253,8 @@ public void run() { } } + public native void registerNodeDataDirPath(String dataDir); + public native String getCurrentABIName(); public native Integer startNodeWithArguments(String[] arguments, String modulesPath, boolean option_redirectOutputToLogcat); diff --git a/install/resources/nodejs-modules/builtin_modules/rn-bridge/index.js b/install/resources/nodejs-modules/builtin_modules/rn-bridge/index.js index 9c354eb..6133b83 100644 --- a/install/resources/nodejs-modules/builtin_modules/rn-bridge/index.js +++ b/install/resources/nodejs-modules/builtin_modules/rn-bridge/index.js @@ -128,6 +128,8 @@ class SystemEventLock { class SystemChannel extends ChannelSuper { constructor(name) { super(name); + // datadir should not change during runtime, so we cache it. + this._cacheDataDir = null; }; emitWrapper(type) { @@ -163,6 +165,13 @@ class SystemChannel extends ChannelSuper { this.emitWrapper(data); }; + // Get a writable data directory for persistent file storage. + datadir() { + if (this._cacheDataDir === null) { + this._cacheDataDir = NativeBridge.getDataDir(); + } + return this._cacheDataDir; + } }; /** * Manage the registered channels to emit events/messages received by the diff --git a/ios/NodeRunner.mm b/ios/NodeRunner.mm index a9a0504..224230d 100644 --- a/ios/NodeRunner.mm +++ b/ios/NodeRunner.mm @@ -49,6 +49,9 @@ - (id)init { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; + // Register the Documents Directory as the node dataDir. + NSString* nodeDataDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; + rn_register_node_data_dir_path([nodeDataDir UTF8String]); return self; } diff --git a/ios/rn-bridge.cpp b/ios/rn-bridge.cpp index 72dc6c5..cc7fbc8 100644 --- a/ios/rn-bridge.cpp +++ b/ios/rn-bridge.cpp @@ -181,6 +181,18 @@ class Channel { }; }; +char* datadir_path = NULL; +/* + * Called by the react-native plug-in to register the datadir, + * representing a writable path. Expected to be called once, + * while the plug-in initializes. + */ +void rn_register_node_data_dir_path(const char* path) { + size_t pathLength = strlen(path); + datadir_path = (char*)calloc(sizeof(char), pathLength + 1); + strncpy(datadir_path, path, pathLength); +} + rn_bridge_cb embedder_callback=NULL; /** @@ -304,6 +316,17 @@ napi_value Method_SendMessage(napi_env env, napi_callback_info info) { return nullptr; } +/** + * Get the registered datadir + */ +napi_value Method_GetDataDir(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, datadir_path!=NULL, "Data directory not set from native side."); + napi_value return_datadir; + size_t str_len = strlen(datadir_path); + NAPI_CALL(env, napi_create_string_utf8(env, datadir_path, str_len, &return_datadir)); + return return_datadir; +} + #define DECLARE_NAPI_METHOD(name, func) \ { name, 0, func, 0, 0, 0, napi_default, 0 } @@ -312,6 +335,7 @@ napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_METHOD("sendMessage", Method_SendMessage), DECLARE_NAPI_METHOD("registerChannel", Method_RegisterChannel), + DECLARE_NAPI_METHOD("getDataDir", Method_GetDataDir), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties)); return exports; diff --git a/ios/rn-bridge.h b/ios/rn-bridge.h index 3424048..2c357af 100644 --- a/ios/rn-bridge.h +++ b/ios/rn-bridge.h @@ -4,5 +4,6 @@ typedef void (*rn_bridge_cb)(const char* channelName, const char* message); void rn_register_bridge_cb(rn_bridge_cb); void rn_bridge_notify(const char* channelName, const char *message); +void rn_register_node_data_dir_path(const char* path); #endif