@@ -36,6 +36,35 @@ struct NativeApiJsiSignature {
3636 unsigned int implicitArgumentCount = 0 ;
3737};
3838
39+ enum class NativeApiJsiCallbackThreadPolicy {
40+ Default,
41+ UI ,
42+ JS ,
43+ };
44+
45+ NativeApiJsiCallbackThreadPolicy readJsiCallbackThreadPolicy (
46+ Runtime& runtime, Object& functionObject) {
47+ constexpr const char * propertyName = " __nativeScriptCallbackThread" ;
48+ try {
49+ if (!functionObject.hasProperty (runtime, propertyName)) {
50+ return NativeApiJsiCallbackThreadPolicy::Default;
51+ }
52+ Value policyValue = functionObject.getProperty (runtime, propertyName);
53+ if (!policyValue.isString ()) {
54+ return NativeApiJsiCallbackThreadPolicy::Default;
55+ }
56+ std::string policy = policyValue.asString (runtime).utf8 (runtime);
57+ if (policy == " ui" ) {
58+ return NativeApiJsiCallbackThreadPolicy::UI ;
59+ }
60+ if (policy == " js" ) {
61+ return NativeApiJsiCallbackThreadPolicy::JS ;
62+ }
63+ } catch (const std::exception&) {
64+ }
65+ return NativeApiJsiCallbackThreadPolicy::Default;
66+ }
67+
3968bool selectorEndsWithNSErrorParam (const std::string& selectorName) {
4069 constexpr const char * suffix = " error:" ;
4170 size_t suffixLength = std::strlen (suffix);
@@ -304,13 +333,17 @@ class NativeApiJsiCallback final
304333 NativeApiJsiCallback (Runtime& runtime,
305334 std::shared_ptr<NativeApiJsiBridge> bridge,
306335 std::shared_ptr<NativeApiJsiSignature> signature,
307- Function function, bool block, bool bindThis = false )
336+ Function function, bool block,
337+ NativeApiJsiCallbackThreadPolicy threadPolicy =
338+ NativeApiJsiCallbackThreadPolicy::Default,
339+ bool bindThis = false )
308340 : runtimeOwner_(retainNativeApiJsiRuntime(runtime)),
309341 runtime_ (runtimeOwner_.get()),
310342 bridge_(std::move(bridge)),
311343 signature_(std::move(signature)),
312344 function_(std::make_shared<Function>(std::move(function))),
313345 block_(block),
346+ threadPolicy_(threadPolicy),
314347 bindThis_(bindThis) {
315348 closure_ = static_cast <ffi_closure*>(
316349 ffi_closure_alloc (sizeof (ffi_closure), &executable_));
@@ -421,6 +454,66 @@ class NativeApiJsiCallback final
421454 const auto & jsThreadCallbackInvoker = bridge_->jsThreadCallbackInvoker ();
422455 bool currentThreadIsJs =
423456 std::this_thread::get_id () == bridge_->jsThreadId ();
457+
458+ auto callOnNativeCallerThread = [&]() {
459+ ScopedNativeCallerThreadJsiCallback callbackScope;
460+ call ();
461+ };
462+ auto callOnUIThread = [&]() {
463+ auto runOnUIThread = [&]() {
464+ bool previous = gExecutingDispatchedUINativeCall ;
465+ gExecutingDispatchedUINativeCall = true ;
466+ callOnNativeCallerThread ();
467+ gExecutingDispatchedUINativeCall = previous;
468+ };
469+ if ([NSThread isMainThread]) {
470+ runOnUIThread ();
471+ } else {
472+ dispatch_sync (dispatch_get_main_queue (), ^{
473+ runOnUIThread ();
474+ });
475+ }
476+ };
477+ auto callOnJSThread = [&]() {
478+ if (currentThreadIsJs) {
479+ call ();
480+ return ;
481+ }
482+ if (jsThreadCallbackInvoker) {
483+ jsThreadCallbackInvoker (call);
484+ return ;
485+ }
486+ if (auto scheduler = bridge_->scheduler ()) {
487+ dispatch_semaphore_t done = dispatch_semaphore_create (0 );
488+ scheduler->invokeOnJS ([call, done]() mutable {
489+ call ();
490+ dispatch_semaphore_signal (done);
491+ });
492+ dispatch_semaphore_wait (done, DISPATCH_TIME_FOREVER );
493+ return ;
494+ }
495+ error = " Native callback was invoked off the JS thread without a JS scheduler." ;
496+ };
497+
498+ if (threadPolicy_ == NativeApiJsiCallbackThreadPolicy::UI ) {
499+ callOnUIThread ();
500+ if (!error.empty ()) {
501+ if (!recordNativeCallbackException (error)) {
502+ throwNativeApiJsiCallbackException (error);
503+ }
504+ }
505+ return ;
506+ }
507+ if (threadPolicy_ == NativeApiJsiCallbackThreadPolicy::JS ) {
508+ callOnJSThread ();
509+ if (!error.empty ()) {
510+ if (!recordNativeCallbackException (error)) {
511+ throwNativeApiJsiCallbackException (error);
512+ }
513+ }
514+ return ;
515+ }
516+
424517 bool returnsVoid = signature_->returnType .kind == metagen::mdTypeVoid;
425518 bool activeSynchronousNativeInvocation =
426519 gActiveSynchronousNativeInvocationDepth .load (
@@ -439,8 +532,7 @@ class NativeApiJsiCallback final
439532 gActiveNativeThreadJsiCallbacks .load (std::memory_order_acquire) > 0 ;
440533 if (direct && !waitForNativeThreadCallback) {
441534 if (nativeCallerThreadCallback) {
442- ScopedNativeCallerThreadJsiCallback callbackScope;
443- call ();
535+ callOnNativeCallerThread ();
444536 } else {
445537 call ();
446538 }
@@ -626,6 +718,8 @@ class NativeApiJsiCallback final
626718 std::shared_ptr<NativeApiJsiSignature> signature_;
627719 std::shared_ptr<Function> function_;
628720 bool block_ = false ;
721+ NativeApiJsiCallbackThreadPolicy threadPolicy_ =
722+ NativeApiJsiCallbackThreadPolicy::Default;
629723 bool bindThis_ = false ;
630724 ffi_closure* closure_ = nullptr ;
631725 void * executable_ = nullptr ;
@@ -1444,7 +1538,9 @@ bool signatureSupportedForJsiCallback(const NativeApiJsiSignature& signature) {
14441538
14451539std::shared_ptr<NativeApiJsiCallback> createJsiCallback (
14461540 Runtime& runtime, const std::shared_ptr<NativeApiJsiBridge>& bridge,
1447- const NativeApiJsiType& type, Function function, bool block) {
1541+ const NativeApiJsiType& type, Function function, bool block,
1542+ NativeApiJsiCallbackThreadPolicy threadPolicy =
1543+ NativeApiJsiCallbackThreadPolicy::Default) {
14481544 if (bridge == nullptr || bridge->metadata () == nullptr ||
14491545 type.signatureOffset == MD_SECTION_OFFSET_NULL ) {
14501546 throw facebook::jsi::JSError (
@@ -1461,7 +1557,8 @@ std::shared_ptr<NativeApiJsiCallback> createJsiCallback(
14611557 auto signature =
14621558 std::make_shared<NativeApiJsiSignature>(std::move (*parsed));
14631559 auto callback = std::make_shared<NativeApiJsiCallback>(
1464- runtime, bridge, std::move (signature), std::move (function), block);
1560+ runtime, bridge, std::move (signature), std::move (function), block,
1561+ threadPolicy);
14651562 if (!block) {
14661563 bridge->retainJsiLifetime (callback);
14671564 }
@@ -1489,7 +1586,8 @@ std::shared_ptr<NativeApiJsiCallback> createJsiMethodCallback(
14891586 auto signature =
14901587 std::make_shared<NativeApiJsiSignature>(std::move (*parsed));
14911588 auto callback = std::make_shared<NativeApiJsiCallback>(
1492- runtime, bridge, std::move (signature), std::move (function), false , true );
1589+ runtime, bridge, std::move (signature), std::move (function), false ,
1590+ NativeApiJsiCallbackThreadPolicy::Default, true );
14931591 bridge->retainJsiLifetime (callback);
14941592 return callback;
14951593}
@@ -1509,7 +1607,7 @@ std::shared_ptr<NativeApiJsiCallback> createJsiMethodCallback(
15091607 std::make_shared<NativeApiJsiSignature>(std::move (signature));
15101608 auto callback = std::make_shared<NativeApiJsiCallback>(
15111609 runtime, bridge, std::move (sharedSignature), std::move (function), false ,
1512- true );
1610+ NativeApiJsiCallbackThreadPolicy::Default, true );
15131611 bridge->retainJsiLifetime (callback);
15141612 return callback;
15151613}
0 commit comments