@dittolive/ditto 4.9.0-rc.3 → 4.9.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/DittoReactNative.podspec +16 -16
  2. package/LICENSE.md +17 -0
  3. package/README.md +2 -2
  4. package/node/ditto.cjs.js +1 -1
  5. package/node/ditto.darwin-arm64.node +0 -0
  6. package/node/ditto.darwin-x64.node +0 -0
  7. package/node/ditto.linux-arm.node +0 -0
  8. package/node/ditto.linux-arm64.node +0 -0
  9. package/node/ditto.linux-x64.node +0 -0
  10. package/node/ditto.win32-x64.node +0 -0
  11. package/package.json +2 -4
  12. package/react-native/android/CMakeLists.txt +15 -6
  13. package/react-native/android/build.gradle +33 -20
  14. package/react-native/android/cpp-adapter.cpp +89 -113
  15. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.kt +59 -0
  16. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.kt +17 -0
  17. package/react-native/cpp/include/DQL.h +1 -0
  18. package/react-native/cpp/include/GlobalCallInvoker.h +8 -0
  19. package/react-native/cpp/include/Lifecycle.h +1 -1
  20. package/react-native/cpp/include/LiveQuery.h +0 -2
  21. package/react-native/cpp/include/Misc.h +0 -1
  22. package/react-native/cpp/include/Utils.h +1 -1
  23. package/react-native/cpp/include/main.h +5 -4
  24. package/react-native/cpp/src/Attachment.cpp +14 -17
  25. package/react-native/cpp/src/Authentication.cpp +12 -12
  26. package/react-native/cpp/src/Collection.cpp +10 -10
  27. package/react-native/cpp/src/ConnectionRequest.cpp +3 -3
  28. package/react-native/cpp/src/DQL.cpp +22 -7
  29. package/react-native/cpp/src/Document.cpp +9 -9
  30. package/react-native/cpp/src/FFIUtils.cpp +1 -1
  31. package/react-native/cpp/src/GlobalCallInvoker.cpp +4 -0
  32. package/react-native/cpp/src/IO.cpp +2 -2
  33. package/react-native/cpp/src/Lifecycle.cpp +4 -4
  34. package/react-native/cpp/src/LiveQuery.cpp +5 -5
  35. package/react-native/cpp/src/Logger.cpp +2 -5
  36. package/react-native/cpp/src/Misc.cpp +14 -14
  37. package/react-native/cpp/src/Presence.cpp +9 -11
  38. package/react-native/cpp/src/SmallPeerInfo.cpp +7 -7
  39. package/react-native/cpp/src/Transports.cpp +14 -14
  40. package/react-native/cpp/src/Utils.cpp +55 -41
  41. package/react-native/cpp/src/main.cpp +7 -2
  42. package/react-native/ditto.es6.js +1 -1
  43. package/react-native/ios/DittoRNSDK.mm +8 -2
  44. package/web/ditto.es6.js +1 -1
  45. package/web/ditto.umd.js +1 -1
  46. package/web/ditto.wasm +0 -0
  47. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -55
  48. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
@@ -36,21 +36,21 @@ Pod::Spec.new do |s|
36
36
  if respond_to?(:install_modules_dependencies, true)
37
37
  install_modules_dependencies(s)
38
38
  else
39
- s.dependency "React-Core"
39
+ s.dependency "React-Core"
40
40
 
41
- # Don't install the dependencies when we run `pod install` in the old architecture.
42
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
43
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
44
- s.pod_target_xcconfig = {
45
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
46
- "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
47
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
48
- }
49
- s.dependency "React-Codegen"
50
- s.dependency "RCT-Folly"
51
- s.dependency "RCTRequired"
52
- s.dependency "RCTTypeSafety"
53
- s.dependency "ReactCommon/turbomodule/core"
54
- end
55
- end
41
+ # Don't install the dependencies when we run `pod install` in the old architecture.
42
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
43
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
44
+ s.pod_target_xcconfig = {
45
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
46
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
47
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
48
+ }
49
+ s.dependency "React-Codegen"
50
+ s.dependency "RCT-Folly"
51
+ s.dependency "RCTRequired"
52
+ s.dependency "RCTTypeSafety"
53
+ s.dependency "ReactCommon/turbomodule/core"
54
+ end
55
+ end
56
56
  end
package/LICENSE.md CHANGED
@@ -32,3 +32,20 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
32
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
33
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
34
  POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ ### Third-Party Notices
37
+
38
+ This project includes code from the "MockFinalizationRegistry.js" gist by `cray0000`, available at:
39
+ https://gist.github.com/cray0000/abecb1ca71fd28a1d8efff2be9e0f6c5
40
+
41
+ This code is used under the MIT License:
42
+
43
+ MIT License
44
+
45
+ Copyright (c) 2024 cray0000
46
+
47
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
48
+
49
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -3,10 +3,10 @@
3
3
  _Ditto is a cross-platform SDK that allows mobile, web, and IoT apps to sync
4
4
  with and even without connectivity._
5
5
 
6
- Version: **4.9.0-rc.3**
6
+ Version: **4.9.1-rc.1**
7
7
 
8
8
  For more information please visit [ditto.live](https://ditto.live), as well as the
9
- [API Reference](https://software.ditto.live/js/Ditto/4.9.0-rc.3/api-reference/) for this particular version.
9
+ [API Reference](https://software.ditto.live/js/Ditto/4.9.1-rc.1/api-reference/) for this particular version.
10
10
 
11
11
  ---
12
12
 
package/node/ditto.cjs.js CHANGED
@@ -2310,7 +2310,7 @@ class AttachmentToken {
2310
2310
 
2311
2311
  // NOTE: this is patched up with the actual build version by Jake task
2312
2312
  // build:package and has to be a valid semantic version as defined here: https://semver.org.
2313
- const fullBuildVersionString = '4.9.0-rc.3';
2313
+ const fullBuildVersionString = '4.9.1-rc.1';
2314
2314
 
2315
2315
  //
2316
2316
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dittolive/ditto",
3
- "version": "4.9.0-rc.3",
3
+ "version": "4.9.1-rc.1",
4
4
  "description": "Ditto is a cross-platform SDK that allows apps to sync with and even without internet connectivity.",
5
5
  "homepage": "https://ditto.live",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -42,9 +42,7 @@
42
42
  },
43
43
 
44
44
  "dependencies": {
45
- "cbor-redux": "^1.0.0",
46
- "@ungap/weakrefs": "^0.2.0",
47
- "fastestsmallesttextencoderdecoder": "^1.0.22"
45
+ "cbor-redux": "^1.0.0"
48
46
  },
49
47
 
50
48
  "devDependencies": {
@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.9.0)
2
2
 
3
3
  set(PACKAGE_NAME "dittorn")
4
4
  project(PACKAGE_NAME)
5
- set(BUILD_DIR ../../../)
6
5
  set(CMAKE_VERBOSE_MAKEFILE ON)
7
6
  set(CMAKE_CXX_STANDARD 17)
8
7
 
@@ -20,15 +19,25 @@ add_library(
20
19
  )
21
20
 
22
21
  find_package(ReactAndroid REQUIRED CONFIG)
23
- find_library(log-lib log)
22
+ find_library(LOG_LIB log)
23
+ find_package(fbjni REQUIRED CONFIG)
24
24
 
25
25
  add_library(dittoffi SHARED IMPORTED)
26
26
  set_target_properties(dittoffi PROPERTIES IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/dittoffi/libs/${ANDROID_ABI}/libdittoffi.so")
27
27
 
28
- target_link_libraries(
29
- ${PACKAGE_NAME}
28
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
29
+ target_link_libraries(${PACKAGE_NAME} ReactAndroid::reactnative)
30
+ else()
31
+ target_link_libraries(${PACKAGE_NAME}
32
+ ReactAndroid::turbomodulejsijni
33
+ ReactAndroid::react_nativemodule_core
34
+ android
35
+ )
36
+ endif()
37
+
38
+ target_link_libraries(${PACKAGE_NAME}
30
39
  dittoffi
31
- ${log-lib}
40
+ ${LOG_LIB}
32
41
  ReactAndroid::jsi
33
- android
42
+ fbjni::fbjni
34
43
  )
@@ -1,7 +1,9 @@
1
- import java.nio.file.Paths
2
1
  import groovy.json.JsonSlurper
3
2
 
4
3
  buildscript {
4
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
5
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["rnsdk_kotlinVersion"]
6
+
5
7
  repositories {
6
8
  google()
7
9
  mavenCentral()
@@ -9,15 +11,22 @@ buildscript {
9
11
 
10
12
  dependencies {
11
13
  classpath "com.android.tools.build:gradle:7.2.1"
14
+ // noinspection DifferentKotlinGradleVersion
15
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12
16
  }
13
17
  }
14
18
 
19
+ def reactNativeArchitectures() {
20
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
21
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
22
+ }
23
+
15
24
  def isNewArchitectureEnabled() {
16
25
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
17
26
  }
18
27
 
19
28
  apply plugin: "com.android.library"
20
-
29
+ apply plugin: "kotlin-android"
21
30
 
22
31
  if (isNewArchitectureEnabled()) {
23
32
  apply plugin: "com.facebook.react"
@@ -68,7 +77,7 @@ android {
68
77
  cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
69
78
  // ESSENTIAL for adding JSI
70
79
  arguments "-DANDROID_STL=c++_shared"
71
- abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
80
+ abiFilters (*reactNativeArchitectures())
72
81
  }
73
82
  }
74
83
  }
@@ -100,6 +109,8 @@ repositories {
100
109
  google()
101
110
  }
102
111
 
112
+ def kotlin_version = getExtOrDefault("kotlinVersion")
113
+
103
114
  def getVersionFromPackageJson() {
104
115
  def packageJsonPath = file('../../package.json')
105
116
  if (packageJsonPath.exists()) {
@@ -117,34 +128,36 @@ dependencies {
117
128
  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
118
129
  //noinspection GradleDynamicVersion
119
130
  implementation "com.facebook.react:react-native:+"
131
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
120
132
 
121
- def aarFile = file('dittoffi/aar/ditto.aar')
122
- def aarExists = aarFile.exists()
133
+ def aarFile = file('dittoffi/aar/ditto.aar')
134
+ def aarExists = aarFile.exists()
123
135
 
124
136
  if (aarExists) {
125
- implementation files('dittoffi/aar/ditto.aar')
137
+ println "Using local `ditto.aar`."
138
+ implementation files('dittoffi/aar/ditto.aar')
126
139
  } else {
127
140
  implementation "live.ditto:ditto:${project.version}"
128
141
  }
129
142
  }
130
143
 
131
- task downloadBinaries {
132
- doLast {
133
- def defaultArchitectures = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
144
+ tasks.register('downloadBinaries') {
145
+ doLast {
146
+ def defaultArchitectures = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
134
147
 
135
- defaultArchitectures.each { arch ->
136
- def fileUrl = "https://software.ditto.live/react-native/ditto/${project.version}/android/${arch}/libdittoffi.so"
148
+ defaultArchitectures.each { arch ->
149
+ def fileUrl = "https://software.ditto.live/react-native/ditto/${project.version}/android/${arch}/libdittoffi.so"
137
150
 
138
- new File("${project.projectDir}/dittoffi/libs/${arch}").mkdirs()
139
- def localFilePath = "${project.projectDir}/dittoffi/libs/${arch}/libdittoffi.so"
151
+ new File("${project.projectDir}/dittoffi/libs/${arch}").mkdirs()
152
+ def localFilePath = "${project.projectDir}/dittoffi/libs/${arch}/libdittoffi.so"
140
153
 
141
- if (!new File(localFilePath).exists()) {
142
- println "Downloading file for $arch: $fileUrl"
143
- ant.get(src: fileUrl, dest: localFilePath, verbose: true)
144
- } else {
145
- println "File for $arch already exists, skipping download: $localFilePath"
146
- }
147
- }
154
+ if (!new File(localFilePath).exists()) {
155
+ println "Downloading file for $arch: $fileUrl"
156
+ ant.get(src: fileUrl, dest: localFilePath, verbose: true)
157
+ } else {
158
+ println "File for $arch already exists, skipping download: $localFilePath"
159
+ }
148
160
  }
161
+ }
149
162
  }
150
163
  preBuild.dependsOn downloadBinaries
@@ -1,145 +1,103 @@
1
1
  #include <jni.h>
2
- #include <sys/types.h>
3
2
  #include <jsi/jsi.h>
4
3
  #include <pthread.h>
5
-
6
- #include "main.h"
7
- #include "TypedArray.hpp"
8
- #include "dittoffi.h"
9
4
  #include <sstream>
10
5
  #include <string>
11
6
  #include <vector>
12
7
  #include <android/log.h>
8
+ #include <ReactCommon/CallInvokerHolder.h>
9
+
10
+ #include "dittoffi.h"
11
+ #include "main.h"
12
+
13
13
 
14
- using namespace facebook::jsi;
14
+ using namespace facebook;
15
15
 
16
16
  JavaVM *java_vm;
17
- jclass java_class;
18
17
  jobject java_object;
19
18
  jobject java_context;
20
19
 
21
20
  /**
22
- * A simple callback function that allows us to detach current JNI Environment
23
- * when the thread
24
- * See https://stackoverflow.com/a/30026231 for detailed explanation
21
+ * A callback function that detaches the current JNI Environment when the thread exits.
22
+ * See https://stackoverflow.com/a/30026231 for detailed explanation.
25
23
  */
26
-
27
- void DeferThreadDetach(JNIEnv *env)
28
- {
24
+ void DeferThreadDetach(JNIEnv *env) {
29
25
  static pthread_key_t thread_key;
30
26
 
31
- // Set up a Thread Specific Data key, and a callback that
32
- // will be executed when a thread is destroyed.
33
- // This is only done once, across all threads, and the value
34
- // associated with the key for any given thread will initially
35
- // be NULL.
36
- static auto run_once = []
37
- {
38
- const auto err = pthread_key_create(&thread_key, [](void *ts_env)
39
- {
27
+ static auto run_once = [] {
28
+ const auto err = pthread_key_create(&thread_key, [](void *ts_env) {
40
29
  if (ts_env) {
41
30
  java_vm->DetachCurrentThread();
42
- } });
43
- if (err)
44
- {
45
- // Failed to create TSD key. Throw an exception if you want to.
31
+ }
32
+ });
33
+ if (err) {
34
+ // Failed to create TSD key. Handle error if necessary.
46
35
  }
47
36
  return 0;
48
- }();
37
+ };
38
+
39
+ run_once();
49
40
 
50
- // For the callback to actually be executed when a thread exits
51
- // we need to associate a non-NULL value with the key on that thread.
52
- // We can use the JNIEnv* as that value.
53
41
  const auto ts_env = pthread_getspecific(thread_key);
54
- if (!ts_env)
55
- {
56
- if (pthread_setspecific(thread_key, env))
57
- {
58
- // Failed to set thread-specific value for key. Throw an exception if you want to.
42
+ if (!ts_env) {
43
+ if (pthread_setspecific(thread_key, env)) {
44
+ // Failed to set thread-specific value for key. Handle error if necessary.
59
45
  }
60
46
  }
61
47
  }
62
48
 
63
49
  /**
64
- * Get a JNIEnv* valid for this thread, regardless of whether
65
- * we're on a native thread or a Java thread.
66
- * If the calling thread is not currently attached to the JVM
67
- * it will be attached, and then automatically detached when the
68
- * thread is destroyed.
69
- *
70
- * See https://stackoverflow.com/a/30026231 for detailed explanation
50
+ * Gets a JNIEnv* valid for the current thread, attaching to the JVM if necessary.
51
+ * See https://stackoverflow.com/a/30026231 for detailed explanation.
71
52
  */
72
- JNIEnv *GetJniEnv()
73
- {
53
+ JNIEnv *GetJniEnv() {
74
54
  JNIEnv *env = nullptr;
75
- // We still call GetEnv first to detect if the thread already
76
- // is attached. This is done to avoid setting up a DetachCurrentThread
77
- // call on a Java thread.
78
-
79
- // g_vm is a global.
80
55
  auto get_env_result = java_vm->GetEnv((void **)&env, JNI_VERSION_1_6);
81
- if (get_env_result == JNI_EDETACHED)
82
- {
83
- if (java_vm->AttachCurrentThread(&env, NULL) == JNI_OK)
84
- {
56
+ if (get_env_result == JNI_EDETACHED) {
57
+ if (java_vm->AttachCurrentThread(&env, NULL) == JNI_OK) {
85
58
  DeferThreadDetach(env);
59
+ } else {
60
+ // Failed to attach thread. Handle error if necessary.
86
61
  }
87
- else
88
- {
89
- // Failed to attach thread. Throw an exception if you want to.
90
- }
91
- }
92
- else if (get_env_result == JNI_EVERSION)
93
- {
94
- // Unsupported JNI version. Throw an exception if you want to.
62
+ } else if (get_env_result == JNI_EVERSION) {
63
+ // Unsupported JNI version. Handle error if necessary.
95
64
  }
96
65
  return env;
97
66
  }
98
67
 
99
- void install(Runtime &jsiRuntime)
100
- {
101
- auto defaultDeviceName = Function::createFromHostFunction(jsiRuntime,
102
- PropNameID::forAscii(jsiRuntime,
103
- "defaultDeviceName"),
104
- 0,
105
- [](Runtime &runtime,
106
- const Value &thisValue,
107
- const Value *arguments,
108
- size_t count) -> Value
109
- {
110
- JNIEnv *jniEnv = GetJniEnv();
111
-
112
- java_class = jniEnv->GetObjectClass(
113
- java_object);
114
- jmethodID defaultDeviceName = jniEnv->GetMethodID(
115
- java_class, "defaultDeviceName",
116
- "()Ljava/lang/String;");
117
- jobject result = jniEnv->CallObjectMethod(
118
- java_object, defaultDeviceName);
119
- const char *str = jniEnv->GetStringUTFChars(
120
- (jstring)result, NULL);
121
-
122
- return Value(runtime,
123
- String::createFromUtf8(
124
- runtime, str));
125
- });
68
+ void install(Runtime &jsiRuntime) {
69
+ auto defaultDeviceName = Function::createFromHostFunction(
70
+ jsiRuntime,
71
+ PropNameID::forAscii(jsiRuntime, "defaultDeviceName"),
72
+ 0,
73
+ [](Runtime &runtime, const Value &thisValue, const Value *arguments, size_t count) -> Value {
74
+ JNIEnv *jniEnv = GetJniEnv();
75
+
76
+ jclass local_java_class = jniEnv->GetObjectClass(java_object);
77
+ jmethodID defaultDeviceNameMethod = jniEnv->GetMethodID(
78
+ local_java_class, "defaultDeviceName", "()Ljava/lang/String;");
79
+ jobject result = jniEnv->CallObjectMethod(java_object, defaultDeviceNameMethod);
80
+
81
+ const char *str = jniEnv->GetStringUTFChars((jstring)result, NULL);
82
+ Value returnValue = Value(runtime, String::createFromUtf8(runtime, str));
83
+
84
+ jniEnv->ReleaseStringUTFChars((jstring)result, str);
85
+ jniEnv->DeleteLocalRef(result);
86
+ jniEnv->DeleteLocalRef(local_java_class);
87
+
88
+ return returnValue;
89
+ });
126
90
 
127
91
  jsiRuntime.global().setProperty(jsiRuntime, "defaultDeviceName", std::move(defaultDeviceName));
128
92
 
129
- auto ditto_sdk_transports_set_android_context = Function::createFromHostFunction(jsiRuntime,
130
- PropNameID::forUtf8(
131
- jsiRuntime,
132
- "ditto_sdk_transports_set_android_context"),
133
- 1,
134
- [](Runtime &runtime,
135
- const Value &thisArg,
136
- const Value *args,
137
- size_t count) -> Value {
138
-
139
- return ::ditto_sdk_transports_set_android_context(
140
- GetJniEnv(),
141
- java_context);
142
- });
93
+ auto ditto_sdk_transports_set_android_context = Function::createFromHostFunction(
94
+ jsiRuntime,
95
+ PropNameID::forUtf8(jsiRuntime, "ditto_sdk_transports_set_android_context"),
96
+ 1,
97
+ [](Runtime &runtime, const Value &thisArg, const Value *args, size_t count) -> Value {
98
+ int result = ::ditto_sdk_transports_set_android_context(GetJniEnv(), java_context);
99
+ return Value(result);
100
+ });
143
101
 
144
102
  jsiRuntime.global().setProperty(jsiRuntime, "ditto_sdk_transports_set_android_context",
145
103
  std::move(ditto_sdk_transports_set_android_context));
@@ -148,11 +106,8 @@ void install(Runtime &jsiRuntime)
148
106
  jsiRuntime,
149
107
  PropNameID::forUtf8(jsiRuntime, "ditto_sdk_transports_android_missing_permissions"),
150
108
  1,
151
- [](Runtime &runtime,
152
- const Value &thisArg,
153
- const Value *args,
154
- size_t count) -> Value {
155
- char *result = ::ditto_sdk_transports_android_missing_permissions();
109
+ [](Runtime &runtime, const Value &thisArg, const Value *args, size_t count) -> Value {
110
+ const char *result = ::ditto_sdk_transports_android_missing_permissions();
156
111
  std::vector<std::string> lines;
157
112
  std::stringstream ss(result);
158
113
  std::string line;
@@ -165,6 +120,8 @@ void install(Runtime &jsiRuntime)
165
120
  jsiArray.setValueAtIndex(runtime, i, String::createFromUtf8(runtime, lines[i]));
166
121
  }
167
122
 
123
+ free(const_cast<char*>(result));
124
+
168
125
  return jsiArray;
169
126
  });
170
127
 
@@ -172,21 +129,40 @@ void install(Runtime &jsiRuntime)
172
129
  std::move(ditto_sdk_transports_android_missing_permissions));
173
130
  }
174
131
 
175
- extern "C" JNIEXPORT void JNICALL
176
- Java_com_dittolive_rnsdk_DittoRNSDKModule_nativeInstall(JNIEnv *env, jobject thiz, jobject context,
177
- jlong jsiPtr, jstring defaultDir) {
132
+
133
+ extern "C"
134
+ JNIEXPORT void JNICALL
135
+ Java_com_dittolive_rnsdk_DittoRNSDKModule_nativeInstall(JNIEnv *env, jobject thiz, jobject context, jobject callInvokerHolderObj,
136
+ jlong jsi_ptr, jstring default_dir)
137
+ {
178
138
  // Save context, module, java_vm objects globally (thread-safe, as opposed to JNIEnv)
179
139
  java_context = env->NewGlobalRef(context);
180
140
  java_object = env->NewGlobalRef(thiz);
181
141
  env->GetJavaVM(&java_vm);
182
142
 
183
- Runtime &runtime = *(reinterpret_cast<Runtime *>(jsiPtr));
143
+ Runtime &runtime = *(reinterpret_cast<Runtime *>(jsi_ptr));
144
+
145
+ // We knew we need to pass the callInvoker from Java to JNI and eventually
146
+ // access the cthis() method to get the actual CallInvoker object, just like
147
+ // in the video: https://youtu.be/oLmGInjKU2U?feature=shared&t=1220
148
+ // The details on how to do this were not documented, though.
149
+ // We have to figure a way to get the actual CallInvoker object using the fbjni library.
150
+ //
151
+ // jni::alias_ref<> is a wrapper provided by the React Native JNI layer.
152
+ // It creates an “alias” reference type which helps in managing the
153
+ // lifecycle of JNI references more safely. The alias_ref ensures that the
154
+ // reference is valid within the current scope and automatically deletes
155
+ // the local reference when going out of scope to prevent memory leaks.
156
+ auto callInvokerHolderObjRef = reinterpret_cast<react::CallInvokerHolder::javaobject>(callInvokerHolderObj);
157
+ auto jsCallInvokerHolder = jni::alias_ref<react::CallInvokerHolder::javaobject>(callInvokerHolderObjRef)->cthis();
158
+ auto jsCallInvoker = jsCallInvokerHolder->getCallInvoker();
184
159
 
185
160
  Object parameters(runtime);
186
- const char *str = env->GetStringUTFChars(defaultDir, NULL);
161
+ const char *str = env->GetStringUTFChars(default_dir, NULL);
187
162
  String defaultDirStr = String::createFromUtf8(runtime, str);
188
163
  parameters.setProperty(runtime, "defaultDirectory", defaultDirStr);
164
+ env->ReleaseStringUTFChars(default_dir, str);
189
165
 
190
- sharedjsi::install(runtime, parameters);
166
+ sharedjsi::install(runtime, jsCallInvoker, parameters);
191
167
  install(runtime);
192
168
  }
@@ -0,0 +1,59 @@
1
+ package com.dittolive.rnsdk
2
+
3
+ import android.os.Build
4
+ import android.util.Log
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
7
+ import com.facebook.react.module.annotations.ReactModule
8
+ import com.facebook.react.bridge.ReactMethod
9
+ import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder
10
+
11
+
12
+ @ReactModule(name = DittoRNSDKModule.NAME)
13
+ class DittoRNSDKModule(private val reactContext: ReactApplicationContext) :
14
+ ReactContextBaseJavaModule(reactContext) {
15
+ companion object {
16
+ const val NAME = "DittoRNSDK"
17
+ }
18
+
19
+ private external fun nativeInstall(
20
+ context: ReactApplicationContext,
21
+ callInvoker: CallInvokerHolder,
22
+ jsiPtr: Long,
23
+ defaultDir: String
24
+ )
25
+
26
+ override fun getName(): String = NAME
27
+
28
+ @ReactMethod(isBlockingSynchronousMethod = true)
29
+ fun install(): Boolean {
30
+ return try {
31
+ System.loadLibrary("dittorn")
32
+
33
+ val jsContextHolder = reactContext.javaScriptContextHolder
34
+ val jsCallInvokerHolder = reactContext.catalystInstance.jsCallInvokerHolder
35
+
36
+ if (jsContextHolder != null && jsCallInvokerHolder != null) {
37
+ nativeInstall(
38
+ reactContext,
39
+ jsCallInvokerHolder,
40
+ jsContextHolder.get(),
41
+ reactContext.filesDir.absolutePath
42
+ )
43
+ true
44
+ } else {
45
+ Log.e("ReactNative", "JavaScript context or call invoker holder is null.")
46
+ false
47
+ }
48
+ } catch (exception: Exception) {
49
+ Log.e("ReactNative", "Failed to load library or initialize: ${exception.message}", exception)
50
+ false
51
+ }
52
+ }
53
+
54
+ fun defaultDeviceName(): String {
55
+ val manufacturer = Build.MANUFACTURER
56
+ val model = Build.MODEL
57
+ return if (model.startsWith(manufacturer)) model else "$manufacturer $model"
58
+ }
59
+ }
@@ -0,0 +1,17 @@
1
+ package com.dittolive.rnsdk
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+
9
+ class DittoRNSDKPackage : ReactPackage {
10
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
+ return listOf(DittoRNSDKModule(reactContext))
12
+ }
13
+
14
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
+ return emptyList()
16
+ }
17
+ }
@@ -16,6 +16,7 @@ Function dittoffi_query_result_mutated_document_id_count(Runtime &runtime);
16
16
  Function dittoffi_query_result_mutated_document_id_at(Runtime &runtime);
17
17
  Function dittoffi_query_result_item_cbor(Runtime &runtime);
18
18
  Function dittoffi_query_result_item_json(Runtime &runtime);
19
+ Function dittoffi_query_result_free(Runtime &runtime);
19
20
  }
20
21
 
21
22
  #endif /* DQL_H */
@@ -0,0 +1,8 @@
1
+ #ifndef GlobalCallInvoker_H
2
+ #define GlobalCallInvoker_H
3
+
4
+ #include "ReactCommon/CallInvoker.h"
5
+
6
+ extern std::shared_ptr<facebook::react::CallInvoker> globalCallInvoker;
7
+
8
+ #endif // GlobalCallInvoker_H
@@ -13,4 +13,4 @@ Function ditto_free(Runtime &runtime);
13
13
  Function ditto_make(Runtime &runtime);
14
14
  }
15
15
 
16
- #endif /* Document_H */
16
+ #endif /* Lifecycle_H */
@@ -10,8 +10,6 @@ namespace sharedjsi
10
10
  Function ditto_live_query_signal_available_next(Runtime &runtime);
11
11
  Function ditto_live_query_start(Runtime &runtime);
12
12
  Function ditto_live_query_stop(Runtime &runtime);
13
- Function ditto_live_query_register_str_detached(Runtime &runtime);
14
- void v_live_query_update(void *ctx, c_cb_params_t params);
15
13
  }
16
14
 
17
15
  #endif /* LiveQuery_H */