expo-modules-core 0.11.0 → 0.11.3

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.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,24 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.11.3 — 2022-07-18
14
+
15
+ ### 💡 Others
16
+
17
+ - Changed access levels in the Logger and fixed the timer to log milliseconds instead of seconds. ([#18271](https://github.com/expo/expo/pull/18271) by [@douglowder](https://github.com/douglowder))
18
+
19
+ ## 0.11.2 — 2022-07-16
20
+
21
+ ### 🐛 Bug fixes
22
+
23
+ - Fix dangling pointer in the fbjni from the MethodMetadata::createPromiseBody on Android. ([#18206](https://github.com/expo/expo/pull/18206) by [@lukmccall](https://github.com/lukmccall))
24
+
25
+ ## 0.11.1 — 2022-07-11
26
+
27
+ ### 🐛 Bug fixes
28
+
29
+ - Fixed a crash when remote debugging is enabled on Android. ([#18165](https://github.com/expo/expo/pull/18165) by [@kudo](https://github.com/kudo))
30
+
13
31
  ## 0.11.0 — 2022-07-07
14
32
 
15
33
  ### 🎉 New features
@@ -6,7 +6,7 @@ apply plugin: 'maven-publish'
6
6
  apply plugin: "de.undercouch.download"
7
7
 
8
8
  group = 'host.exp.exponent'
9
- version = '0.11.0'
9
+ version = '0.11.3'
10
10
 
11
11
  buildscript {
12
12
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -144,7 +144,7 @@ android {
144
144
  targetSdkVersion safeExtGet("targetSdkVersion", 31)
145
145
  consumerProguardFiles 'proguard-rules.pro'
146
146
  versionCode 1
147
- versionName "0.11.0"
147
+ versionName "0.11.3"
148
148
 
149
149
  testInstrumentationRunner "expo.modules.TestRunner"
150
150
 
@@ -22,6 +22,8 @@ void CachedReferencesRegistry::loadJClasses(JNIEnv *env) {
22
22
  loadJClass(env, "com/facebook/react/bridge/PromiseImpl", {
23
23
  {"<init>", "(Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V"}
24
24
  });
25
+
26
+ loadJClass(env, "java/lang/Object", {});
25
27
  }
26
28
 
27
29
  void CachedReferencesRegistry::loadJClass(
@@ -1,30 +1,30 @@
1
1
  // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
2
 
3
3
  #include "JNIFunctionBody.h"
4
+ #include "CachedReferencesRegistry.h"
4
5
 
5
6
  namespace jni = facebook::jni;
6
7
  namespace react = facebook::react;
7
8
 
8
9
  namespace expo {
9
10
  jni::local_ref<react::ReadableNativeArray::javaobject>
10
- JNIFunctionBody::invoke(jni::local_ref<jni::JArrayClass<jobject>> &&args) {
11
+ JNIFunctionBody::invoke(jobjectArray args) {
11
12
  // Do NOT use getClass here!
12
13
  // Method obtained from `getClass` will point to the overridden version of the method.
13
14
  // Because of that, it can't be cached - we will try to invoke the nonexistent method
14
15
  // if we receive an object of a different class than the one used to obtain the method id.
15
16
  // The only cacheable method id can be obtain from the base class.
16
17
  static const auto method = jni::findClassLocal("expo/modules/kotlin/jni/JNIFunctionBody")
17
- ->getMethod<
18
- react::ReadableNativeArray::javaobject(jni::local_ref<jni::JArrayClass<jobject>>)
19
- >(
20
- "invoke"
18
+ ->getMethod<jni::local_ref<react::ReadableNativeArray::javaobject>(jobjectArray)>(
19
+ "invoke",
20
+ "([Ljava/lang/Object;)Lcom/facebook/react/bridge/ReadableNativeArray;"
21
21
  );
22
22
 
23
23
  return method(this->self(), args);
24
24
  }
25
25
 
26
26
  void JNIAsyncFunctionBody::invoke(
27
- jni::local_ref<jni::JArrayClass<jobject>> &&args,
27
+ jobjectArray args,
28
28
  jobject promise
29
29
  ) {
30
30
  // Do NOT use getClass here!
@@ -34,9 +34,10 @@ void JNIAsyncFunctionBody::invoke(
34
34
  // The only cacheable method id can be obtain from the base class.
35
35
  static const auto method = jni::findClassLocal("expo/modules/kotlin/jni/JNIAsyncFunctionBody")
36
36
  ->getMethod<
37
- void(jni::local_ref<jni::JArrayClass<jobject>>, jobject)
37
+ void(jobjectArray , jobject)
38
38
  >(
39
- "invoke"
39
+ "invoke",
40
+ "([Ljava/lang/Object;Ljava/lang/Object;)V"
40
41
  );
41
42
 
42
43
  method(this->self(), args, promise);
@@ -24,7 +24,7 @@ public:
24
24
  * @return result of the Kotlin function
25
25
  */
26
26
  jni::local_ref<react::ReadableNativeArray::javaobject> invoke(
27
- jni::local_ref<jni::JArrayClass<jobject>> &&args
27
+ jobjectArray args
28
28
  );
29
29
  };
30
30
 
@@ -43,7 +43,7 @@ public:
43
43
  * @param promise that will be resolve or rejected in the Kotlin's implementation
44
44
  */
45
45
  void invoke(
46
- jni::local_ref<jni::JArrayClass<jobject>> &&args,
46
+ jobjectArray args,
47
47
  jobject promise
48
48
  );
49
49
  };
@@ -87,10 +87,10 @@ jsi::Runtime *JavaScriptRuntime::get() {
87
87
  jni::local_ref<JavaScriptValue::javaobject>
88
88
  JavaScriptRuntime::evaluateScript(const std::string &script) {
89
89
  auto scriptBuffer = std::make_shared<jsi::StringBuffer>(script);
90
- std::shared_ptr<jsi::Value> result;
91
90
  try {
92
- result = std::make_shared<jsi::Value>(
93
- runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>")
91
+ return JavaScriptValue::newObjectCxxArgs(
92
+ weak_from_this(),
93
+ std::make_shared<jsi::Value>(runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>"))
94
94
  );
95
95
  } catch (const jsi::JSError &error) {
96
96
  jni::throwNewJavaException(
@@ -107,8 +107,6 @@ JavaScriptRuntime::evaluateScript(const std::string &script) {
107
107
  ).get()
108
108
  );
109
109
  }
110
-
111
- return JavaScriptValue::newObjectCxxArgs(weak_from_this(), result);
112
110
  }
113
111
 
114
112
  jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::global() {
@@ -80,49 +80,65 @@ std::vector<jvalue> MethodMetadata::convertJSIArgsToJNI(
80
80
  JNIEnv *env,
81
81
  jsi::Runtime &rt,
82
82
  const jsi::Value *args,
83
- size_t count
83
+ size_t count,
84
+ bool returnGlobalReferences
84
85
  ) {
85
86
  std::vector<jvalue> result(count);
86
87
 
88
+ auto makeGlobalIfNecessary = [env, returnGlobalReferences](jobject obj) -> jobject {
89
+ if (returnGlobalReferences) {
90
+ return env->NewGlobalRef(obj);
91
+ }
92
+ return obj;
93
+ };
94
+
87
95
  for (unsigned int argIndex = 0; argIndex < count; argIndex++) {
88
96
  const jsi::Value *arg = &args[argIndex];
89
97
  jvalue *jarg = &result[argIndex];
90
98
  int desiredType = desiredTypes[argIndex];
91
99
 
92
100
  if (desiredType & CppType::JS_VALUE) {
93
- jarg->l = JavaScriptValue::newObjectCxxArgs(
94
- moduleRegistry->runtimeHolder->weak_from_this(),
95
- // TODO(@lukmccall): make sure that copy here is necessary
96
- std::make_shared<jsi::Value>(jsi::Value(rt, *arg))
97
- ).release();
101
+ jarg->l = makeGlobalIfNecessary(
102
+ JavaScriptValue::newObjectCxxArgs(
103
+ moduleRegistry->runtimeHolder->weak_from_this(),
104
+ // TODO(@lukmccall): make sure that copy here is necessary
105
+ std::make_shared<jsi::Value>(jsi::Value(rt, *arg))
106
+ ).release()
107
+ );
98
108
  } else if (desiredType & CppType::JS_OBJECT) {
99
- jarg->l = JavaScriptObject::newObjectCxxArgs(
100
- moduleRegistry->runtimeHolder->weak_from_this(),
101
- std::make_shared<jsi::Object>(arg->getObject(rt))
102
- ).release();
109
+ jarg->l = makeGlobalIfNecessary(
110
+ JavaScriptObject::newObjectCxxArgs(
111
+ moduleRegistry->runtimeHolder->weak_from_this(),
112
+ std::make_shared<jsi::Object>(arg->getObject(rt))
113
+ ).release()
114
+ );
103
115
  } else if (arg->isNull() || arg->isUndefined()) {
104
116
  jarg->l = nullptr;
105
117
  } else if (arg->isNumber()) {
106
118
  auto &doubleClass = CachedReferencesRegistry::instance()
107
119
  ->getJClass("java/lang/Double");
108
120
  jmethodID doubleConstructor = doubleClass.getMethod("<init>", "(D)V");
109
- jarg->l = env->NewObject(doubleClass.clazz, doubleConstructor, arg->getNumber());
121
+ jarg->l = makeGlobalIfNecessary(
122
+ env->NewObject(doubleClass.clazz, doubleConstructor, arg->getNumber()));
110
123
  } else if (arg->isBool()) {
111
124
  auto &booleanClass = CachedReferencesRegistry::instance()
112
125
  ->getJClass("java/lang/Boolean");
113
126
  jmethodID booleanConstructor = booleanClass.getMethod("<init>", "(Z)V");
114
- jarg->l = env->NewObject(booleanClass.clazz, booleanConstructor, arg->getBool());
127
+ jarg->l = makeGlobalIfNecessary(
128
+ env->NewObject(booleanClass.clazz, booleanConstructor, arg->getBool()));
115
129
  } else if (arg->isString()) {
116
- jarg->l = env->NewStringUTF(arg->getString(rt).utf8(rt).c_str());
130
+ jarg->l = makeGlobalIfNecessary(env->NewStringUTF(arg->getString(rt).utf8(rt).c_str()));
117
131
  } else if (arg->isObject()) {
118
132
  const jsi::Object object = arg->getObject(rt);
119
133
 
120
134
  // TODO(@lukmccall): stop using dynamic
121
135
  auto dynamic = jsi::dynamicFromValue(rt, *arg);
122
136
  if (arg->getObject(rt).isArray(rt)) {
123
- jarg->l = react::ReadableNativeArray::newObjectCxxArgs(std::move(dynamic)).release();
137
+ jarg->l = makeGlobalIfNecessary(
138
+ react::ReadableNativeArray::newObjectCxxArgs(std::move(dynamic)).release());
124
139
  } else {
125
- jarg->l = react::ReadableNativeMap::createWithContents(std::move(dynamic)).release();
140
+ jarg->l = makeGlobalIfNecessary(
141
+ react::ReadableNativeMap::createWithContents(std::move(dynamic)).release());
126
142
  }
127
143
  } else {
128
144
  // TODO(@lukmccall): throw an exception
@@ -202,18 +218,23 @@ jsi::Value MethodMetadata::callSync(
202
218
  */
203
219
  jni::JniLocalScope scope(env, (int) count);
204
220
 
205
- std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
221
+ std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count,
222
+ false);
206
223
 
207
224
  // TODO(@lukmccall): Remove this temp array
208
- auto tempArray = jni::JArrayClass<jobject>::newArray(count);
225
+ auto tempArray = env->NewObjectArray(
226
+ convertedArgs.size(),
227
+ CachedReferencesRegistry::instance()->getJClass("java/lang/Object").clazz,
228
+ nullptr
229
+ );
209
230
  for (size_t i = 0; i < convertedArgs.size(); i++) {
210
- tempArray->setElement(i, convertedArgs[i].l);
231
+ env->SetObjectArrayElement(tempArray, i, convertedArgs[i].l);
211
232
  }
212
233
 
213
234
  // Cast in this place is safe, cause we know that this function is promise-less.
214
235
  auto syncFunction = jni::static_ref_cast<JNIFunctionBody>(this->jBodyReference);
215
236
  auto result = syncFunction->invoke(
216
- std::move(tempArray)
237
+ tempArray
217
238
  );
218
239
 
219
240
  if (result == nullptr) {
@@ -248,20 +269,14 @@ jsi::Function MethodMetadata::toAsyncFunction(
248
269
  * all LocalReferences are deleted.
249
270
  */
250
271
  jni::JniLocalScope scope(env, (int) count);
251
-
252
- std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count);
253
-
254
- // TODO(@lukmccall): Remove this temp array
255
- auto tempArray = jni::JArrayClass<jobject>::newArray(count);
256
- for (size_t i = 0; i < convertedArgs.size(); i++) {
257
- tempArray->setElement(i, convertedArgs[i].l);
258
- }
272
+ std::vector<jvalue> convertedArgs = convertJSIArgsToJNI(moduleRegistry, env, rt, args, count,
273
+ true);
259
274
 
260
275
  auto Promise = rt.global().getPropertyAsFunction(rt, "Promise");
261
276
  // Creates a JSI promise
262
277
  jsi::Value promise = Promise.callAsConstructor(
263
278
  rt,
264
- createPromiseBody(rt, moduleRegistry, std::move(tempArray))
279
+ createPromiseBody(rt, moduleRegistry, std::move(convertedArgs))
265
280
  );
266
281
  return promise;
267
282
  }
@@ -271,7 +286,7 @@ jsi::Function MethodMetadata::toAsyncFunction(
271
286
  jsi::Function MethodMetadata::createPromiseBody(
272
287
  jsi::Runtime &runtime,
273
288
  JSIInteropModuleRegistry *moduleRegistry,
274
- jni::local_ref<jni::JArrayClass<jobject>::javaobject> &&args
289
+ std::vector<jvalue> &&args
275
290
  ) {
276
291
  return jsi::Function::createFromHostFunction(
277
292
  runtime,
@@ -320,10 +335,21 @@ jsi::Function MethodMetadata::createPromiseBody(
320
335
  reject
321
336
  );
322
337
 
338
+ auto argsSize = args.size();
339
+ // TODO(@lukmccall): Remove this temp array
340
+ auto tempArray = env->NewObjectArray(
341
+ argsSize,
342
+ CachedReferencesRegistry::instance()->getJClass("java/lang/Object").clazz,
343
+ nullptr
344
+ );
345
+ for (size_t i = 0; i < argsSize; i++) {
346
+ env->SetObjectArrayElement(tempArray, i, args[i].l);
347
+ }
348
+
323
349
  // Cast in this place is safe, cause we know that this function expects promise.
324
350
  auto asyncFunction = jni::static_ref_cast<JNIAsyncFunctionBody>(this->jBodyReference);
325
351
  asyncFunction->invoke(
326
- args,
352
+ tempArray,
327
353
  promise
328
354
  );
329
355
 
@@ -332,6 +358,11 @@ jsi::Function MethodMetadata::createPromiseBody(
332
358
  // the ownership to the `JNIAsyncFunctionBody`.
333
359
  env->DeleteLocalRef(promise);
334
360
 
361
+ for (const auto &arg: args) {
362
+ env->DeleteGlobalRef(arg.l);
363
+ }
364
+ env->DeleteLocalRef(tempArray);
365
+
335
366
  return jsi::Value::undefined();
336
367
  }
337
368
  );
@@ -117,7 +117,7 @@ private:
117
117
  jsi::Function createPromiseBody(
118
118
  jsi::Runtime &runtime,
119
119
  JSIInteropModuleRegistry *moduleRegistry,
120
- jni::local_ref<jni::JArrayClass<jobject>::javaobject> &&args
120
+ std::vector<jvalue> &&args
121
121
  );
122
122
 
123
123
  std::vector<jvalue> convertJSIArgsToJNI(
@@ -125,7 +125,8 @@ private:
125
125
  JNIEnv *env,
126
126
  jsi::Runtime &rt,
127
127
  const jsi::Value *args,
128
- size_t count
128
+ size_t count,
129
+ bool returnGlobalReferences
129
130
  );
130
131
  };
131
132
  } // namespace expo
@@ -89,13 +89,15 @@ class AppContext(
89
89
  fun installJSIInterop() {
90
90
  jsiInterop = JSIInteropModuleRegistry(this)
91
91
  val reactContext = reactContextHolder.get() ?: return
92
- reactContext.javaScriptContextHolder?.get()?.let {
93
- jsiInterop.installJSI(
94
- it,
95
- reactContext.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
96
- reactContext.catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
97
- )
98
- }
92
+ reactContext.javaScriptContextHolder?.get()
93
+ ?.takeIf { it != 0L }
94
+ ?.let {
95
+ jsiInterop.installJSI(
96
+ it,
97
+ reactContext.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl,
98
+ reactContext.catalystInstance.nativeCallInvokerHolder as CallInvokerHolderImpl
99
+ )
100
+ }
99
101
  }
100
102
 
101
103
  /**
@@ -266,6 +268,12 @@ class AppContext(
266
268
 
267
269
  // region AppContextActivityResultCaller
268
270
 
271
+ /**
272
+ * For the time being [fallbackCallback] is not working.
273
+ * There are some problems with saving and restoring the state of [activityResultsManager]
274
+ * connected with [Activity]'s lifecycle and [AppContext] lifespan. So far, we've failed with identifying
275
+ * what parts of the application outlives the Activity destruction (especially [AppContext] and other [Bridge]-related parts).
276
+ */
269
277
  @MainThread
270
278
  override suspend fun <I : Serializable, O> registerForActivityResult(
271
279
  contract: AppContextActivityResultContract<I, O>,
@@ -1,6 +1,7 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ExpoModulesCore/EXJSIInstaller.h>
4
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
4
5
  #import <ExpoModulesCore/ExpoModulesHostObject.h>
5
6
  #import <ExpoModulesCore/Swift.h>
6
7
 
@@ -14,6 +15,7 @@ static NSString *expoModulesHostObjectPropertyName = @"ExpoModules";
14
15
  @interface RCTBridge (ExpoBridgeWithRuntime)
15
16
 
16
17
  - (void *)runtime;
18
+ - (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
17
19
 
18
20
  @end
19
21
 
@@ -201,9 +201,10 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
201
201
 
202
202
  - (void)setBridge:(RCTBridge *)bridge
203
203
  {
204
- _appContext = [(ExpoBridgeModule *)[bridge moduleForClass:ExpoBridgeModule.class] appContext];
205
- [_appContext setLegacyModuleRegistry:_exModuleRegistry];
206
- [_appContext setLegacyModulesProxy:self];
204
+ ExpoBridgeModule* expoBridgeModule = [bridge moduleForClass:ExpoBridgeModule.class];
205
+ [expoBridgeModule legacyProxyDidSetBridgeWithLegacyModulesProxy:self
206
+ legacyModuleRegistry:_exModuleRegistry];
207
+ _appContext = [expoBridgeModule appContext];
207
208
 
208
209
  if (!_bridge) {
209
210
  // The `setBridge` can be called during module setup or after. Registering more modules
@@ -389,7 +390,7 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
389
390
  {
390
391
  // Hacky way to get a dictionary with `RCTComponentData` from UIManager.
391
392
  NSMutableDictionary<NSString *, RCTComponentData *> *componentDataByName = [bridge.uiManager valueForKey:@"_componentDataByName"];
392
- NSString *className = NSStringFromClass(moduleClass);
393
+ NSString *className = [moduleClass moduleName] ?: NSStringFromClass(moduleClass);
393
394
 
394
395
  if ([moduleClass isSubclassOfClass:[RCTViewManager class]] && !componentDataByName[className]) {
395
396
  RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass bridge:bridge eventDispatcher:bridge.eventDispatcher];
@@ -28,11 +28,9 @@ public final class AppContext: NSObject {
28
28
  /**
29
29
  The legacy module registry with modules written in the old-fashioned way.
30
30
  */
31
- @objc
32
- public weak var legacyModuleRegistry: EXModuleRegistry?
31
+ internal weak var legacyModuleRegistry: EXModuleRegistry?
33
32
 
34
- @objc
35
- public weak var legacyModulesProxy: LegacyNativeModulesProxy?
33
+ internal weak var legacyModulesProxy: LegacyNativeModulesProxy?
36
34
 
37
35
  /**
38
36
  React bridge of the context's app. Can be `nil` when the bridge
@@ -12,7 +12,7 @@ public struct ClassComponentElementsBuilder<OwnerType> {
12
12
  /**
13
13
  Default implementation without any constraints that just returns type-erased element.
14
14
  */
15
- static func buildExpression<ElementType: ClassComponentElement>(
15
+ public static func buildExpression<ElementType: ClassComponentElement>(
16
16
  _ element: ElementType
17
17
  ) -> AnyClassComponentElement {
18
18
  return element
@@ -23,7 +23,7 @@ public struct ClassComponentElementsBuilder<OwnerType> {
23
23
  we need to instruct the function to pass `this` to the closure
24
24
  as the first argument and deduct it from `argumentsCount`.
25
25
  */
26
- static func buildExpression<ElementType: ClassComponentElement>(
26
+ public static func buildExpression<ElementType: ClassComponentElement>(
27
27
  _ element: ElementType
28
28
  ) -> AnyClassComponentElement where ElementType.OwnerType == OwnerType {
29
29
  if var function = element as? AnyFunction {
@@ -20,8 +20,7 @@ public final class ExpoBridgeModule: NSObject, RCTBridgeModule {
20
20
  architecture of Expo modules and the app itself.
21
21
  */
22
22
  override init() {
23
- appContext = AppContext().useModulesProvider("ExpoModulesProvider")
24
- appContext.moduleRegistry.register(moduleType: NativeModulesProxyModule.self)
23
+ appContext = AppContext()
25
24
  super.init()
26
25
 
27
26
  // Listen to React Native notifications posted just before the JS is executed.
@@ -50,6 +49,21 @@ public final class ExpoBridgeModule: NSObject, RCTBridgeModule {
50
49
  appContext.reactBridge = bridge
51
50
  }
52
51
  }
52
+
53
+ /**
54
+ This should be called inside EXNativeModulesProxy.setBridge()
55
+ */
56
+ @objc
57
+ public func legacyProxyDidSetBridge(legacyModulesProxy: LegacyNativeModulesProxy,
58
+ legacyModuleRegistry: EXModuleRegistry) {
59
+ appContext.legacyModuleRegistry = legacyModuleRegistry
60
+ appContext.legacyModulesProxy = legacyModulesProxy
61
+
62
+ // we need to register all the modules after the legacy module registry is set
63
+ // otherwise legacy modules (e.g. permissions) won't be available in OnCreate { }
64
+ appContext.useModulesProvider("ExpoModulesProvider")
65
+ appContext.moduleRegistry.register(moduleType: NativeModulesProxyModule.self)
66
+ }
53
67
 
54
68
  // MARK: - Notifications
55
69
 
@@ -45,7 +45,7 @@ public enum LogType: Int {
45
45
  Maps the log types to the log types used by the `os.log` logger.
46
46
  */
47
47
  @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
48
- func toOSLogType() -> OSLogType {
48
+ public func toOSLogType() -> OSLogType {
49
49
  switch self {
50
50
  case .trace, .timer, .stacktrace, .debug:
51
51
  return .debug
@@ -139,7 +139,7 @@ public class Logger {
139
139
  }
140
140
  let endTime = DispatchTime.now()
141
141
  let diff = Double(endTime.uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000
142
- log(type: .timer, "Timer '\(id)' has finished in: \(diff) seconds")
142
+ log(type: .timer, "Timer '\(id)' has finished in: \(diff) ms")
143
143
  timers.removeValue(forKey: id)
144
144
  }
145
145
 
@@ -183,11 +183,14 @@ public class Logger {
183
183
  }
184
184
  }
185
185
 
186
- fileprivate func reformatStackSymbol(_ symbol: String) -> String {
186
+ private func reformatStackSymbol(_ symbol: String) -> String {
187
187
  return symbol.replacingOccurrences(of: #"^\d+\s+"#, with: "", options: .regularExpression)
188
188
  }
189
189
 
190
- fileprivate func describe(value: Any) -> String {
190
+ private func describe(value: Any) -> String {
191
+ if let value = value as? String {
192
+ return value
193
+ }
191
194
  if let value = value as? CustomDebugStringConvertible {
192
195
  return value.debugDescription
193
196
  }
@@ -22,7 +22,11 @@ public struct Promise: AnyArgument {
22
22
  }
23
23
 
24
24
  public func reject(_ error: Error) {
25
- rejecter(UnexpectedException(error))
25
+ if let exception = error as? Exception {
26
+ rejecter(exception)
27
+ } else {
28
+ rejecter(UnexpectedException(error))
29
+ }
26
30
  }
27
31
 
28
32
  public func reject(_ error: Exception) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "0.11.0",
3
+ "version": "0.11.3",
4
4
  "description": "The core of Expo Modules architecture",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -42,5 +42,5 @@
42
42
  "@testing-library/react-hooks": "^7.0.1",
43
43
  "expo-module-scripts": "^2.0.0"
44
44
  },
45
- "gitHead": "6e131f2da851a47c3a24eb3d6fc971a1a7822086"
45
+ "gitHead": "5d900179d047d9f4d89c0b9953b7121a1f1df8a2"
46
46
  }