RCTNativeModule.mm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTNativeModule.h"
  8. #import <React/RCTBridge.h>
  9. #import <React/RCTBridgeMethod.h>
  10. #import <React/RCTBridgeModule.h>
  11. #import <React/RCTCxxUtils.h>
  12. #import <React/RCTFollyConvert.h>
  13. #import <React/RCTLog.h>
  14. #import <React/RCTProfile.h>
  15. #import <React/RCTUtils.h>
  16. #ifdef WITH_FBSYSTRACE
  17. #include <fbsystrace.h>
  18. #endif
  19. namespace facebook {
  20. namespace react {
  21. static MethodCallResult
  22. invokeInner(RCTBridge *bridge, RCTModuleData *moduleData, unsigned int methodId, const folly::dynamic &params);
  23. RCTNativeModule::RCTNativeModule(RCTBridge *bridge, RCTModuleData *moduleData)
  24. : m_bridge(bridge), m_moduleData(moduleData)
  25. {
  26. }
  27. std::string RCTNativeModule::getName()
  28. {
  29. return [m_moduleData.name UTF8String];
  30. }
  31. std::vector<MethodDescriptor> RCTNativeModule::getMethods()
  32. {
  33. std::vector<MethodDescriptor> descs;
  34. for (id<RCTBridgeMethod> method in m_moduleData.methods) {
  35. descs.emplace_back(method.JSMethodName, RCTFunctionDescriptorFromType(method.functionType));
  36. }
  37. return descs;
  38. }
  39. folly::dynamic RCTNativeModule::getConstants()
  40. {
  41. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTNativeModule getConstants] moduleData.exportedConstants", nil);
  42. NSDictionary *constants = m_moduleData.exportedConstants;
  43. folly::dynamic ret = convertIdToFollyDynamic(constants);
  44. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  45. return ret;
  46. }
  47. void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &&params, int callId)
  48. {
  49. // capture by weak pointer so that we can safely use these variables in a callback
  50. __weak RCTBridge *weakBridge = m_bridge;
  51. __weak RCTModuleData *weakModuleData = m_moduleData;
  52. // The BatchedBridge version of this buckets all the callbacks by thread, and
  53. // queues one block on each. This is much simpler; we'll see how it goes and
  54. // iterate.
  55. dispatch_block_t block = [weakBridge, weakModuleData, methodId, params = std::move(params), callId] {
  56. #ifdef WITH_FBSYSTRACE
  57. if (callId != -1) {
  58. fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
  59. }
  60. #else
  61. (void)(callId);
  62. #endif
  63. invokeInner(weakBridge, weakModuleData, methodId, std::move(params));
  64. };
  65. dispatch_queue_t queue = m_moduleData.methodQueue;
  66. if (queue == RCTJSThread) {
  67. block();
  68. } else if (queue) {
  69. dispatch_async(queue, block);
  70. }
  71. #ifdef RCT_DEV
  72. if (!queue) {
  73. RCTLog(
  74. @"Attempted to invoke `%u` (method ID) on `%@` (NativeModule name) without a method queue.",
  75. methodId,
  76. m_moduleData.name);
  77. }
  78. #endif
  79. }
  80. MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &&params)
  81. {
  82. return invokeInner(m_bridge, m_moduleData, reactMethodId, params);
  83. }
  84. static MethodCallResult
  85. invokeInner(RCTBridge *bridge, RCTModuleData *moduleData, unsigned int methodId, const folly::dynamic &params)
  86. {
  87. if (!bridge || !bridge.valid || !moduleData) {
  88. return folly::none;
  89. }
  90. id<RCTBridgeMethod> method = moduleData.methods[methodId];
  91. if (RCT_DEBUG && !method) {
  92. RCTLogError(@"Unknown methodID: %ud for module: %@", methodId, moduleData.name);
  93. }
  94. NSArray *objcParams = convertFollyDynamicToId(params);
  95. @try {
  96. id result = [method invokeWithBridge:bridge module:moduleData.instance arguments:objcParams];
  97. return convertIdToFollyDynamic(result);
  98. } @catch (NSException *exception) {
  99. // Pass on JS exceptions
  100. if ([exception.name hasPrefix:RCTFatalExceptionName]) {
  101. @throw exception;
  102. }
  103. #if RCT_DEBUG
  104. NSString *message = [NSString
  105. stringWithFormat:@"Exception '%@' was thrown while invoking %s on target %@ with params %@\ncallstack: %@",
  106. exception,
  107. method.JSMethodName,
  108. moduleData.name,
  109. objcParams,
  110. exception.callStackSymbols];
  111. RCTFatal(RCTErrorWithMessage(message));
  112. #else
  113. RCTFatalException(exception);
  114. #endif
  115. }
  116. return folly::none;
  117. }
  118. }
  119. }