skip to Main Content

We are upgrading a react native project from 0.66.4 to 0.69.6.

The project uses an AppDelegate.swift file but the react native upgrade helper uses the AppDelegate.m class in its upgrade example and instructs to delete it and replace it with a AppDelegate.mm class. See Upgrade helper

To my understanding this allows the compiler to compile C and C++ code.

My question is how do we keep the logic in our AppDelegate swift class? Do we have to use the AppDelegate.mm and integrate the swift code into it or is there a better way?

Content from AppDelegate.swift:

import UIKit
import Firebase
import Adyen
import GoogleCast
import Didomi
import os
import FBSDKCoreKit

#if DEBUG
// #if FB_SONARKIT_ENABLED
import FlipperKit
// #endif
#endif

@UIApplicationMain

  class AppDelegate: UIResponder, RCTBridgeDelegate, UIApplicationDelegate,
  UNUserNotificationCenterDelegate, RNAppAuthAuthorizationFlowManager {

  private func initializeFlipper(with application: UIApplication) {
    #if DEBUG
    // Check if FB_SONARKIT_ENABLED  and commented pluggins work in RN 0.67+ versions
    // #if FB_SONARKIT_ENABLED
    let client = FlipperClient.shared()
    let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
    // FlipperKitLayoutComponentKitSupport.setUpWith(layoutDescriptorMapper)
    client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))
    client?.add(FKUserDefaultsPlugin(suiteName: nil))
    client?.add(FlipperKitReactPlugin())
    client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
    // client?.add(FlipperReactPerformancePlugin.sharedInstance())
    client?.start()
    // #endif
    #endif
  }

  func sourceURL(for bridge: RCTBridge!) -> URL! {
    #if DEBUG
      return RCTBundleURLProvider.sharedSettings()?.jsBundleURL(forBundleRoot: "index", fallbackResource: nil)
    #else
      return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
    #endif
  }

  var window: UIWindow?
  var bridge: RCTBridge!
  var orientationLock: UIInterfaceOrientationMask = .portrait
  var rootView: RCTRootView?
  var isScreenRecordingEnabled: Bool?
  var isCaptured: Bool?
  public weak var authorizationFlowManagerDelegate: RNAppAuthAuthorizationFlowManagerDelegate?

  func application(_ application: UIApplication,
                   willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
   
    _ = localizedString(LocalizationKey(key: "adyen.card.expiryItem.title"), nil)

    //  Start screen recording in a disabled state
    isScreenRecordingEnabled = false
    let config = ReactNativeConfig.env()!
    WonderPush.setClientId((config["WONDERPUSH_CLIENT_ID"] as? String)!,
                           secret: (config["WONDERPUSH_CLIENT_SECRET"] as? String)!)
    WonderPush.setupDelegateForUserNotificationCenter()
    WonderPush.setRequiresUserConsent(false)
    WonderPush.setUserConsent(true)

    return true
  }
  // swiftlint:disable block_based_kvo
  // swiftlint:disable colon
  override func observeValue(forKeyPath keyPath: String?, of object: Any?,
                             change: [NSKeyValueChangeKey : Any]?,
                             context: UnsafeMutableRawPointer?) {
    if #available(iOS 11.0, *) {
      if keyPath == "captured" {
        isCaptured = UIScreen.main.isCaptured
        if !isScreenRecordingEnabled! {
          if isCaptured! {
            rootView?.isHidden = true
          }
          if !isCaptured! && rootView?.isHidden == true {
            rootView?.isHidden = false
          }
        }
      }
    }
  }

  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // swiftlint:disable force_cast
    launchDidomi(apiKey: ReactNativeConfig.env()!["DIDOMI_API_KEY"] as! String)
    FirebaseApp.configure()
    initializeFlipper(with: application)

    let receiverAppID = kGCKDefaultMediaReceiverApplicationID // or "ABCD1234"
    let criteria = GCKDiscoveryCriteria(applicationID: receiverAppID)
    let options = GCKCastOptions(discoveryCriteria: criteria)
    GCKCastContext.setSharedInstanceWith(options)
    GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true

    self.bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
    guard let bridge = self.bridge else {
      return false
    }

    let props: [AnyHashable: Any] = [
      "APP_INFO": (Bundle.main.infoDictionary?["APP_INFO"] as? String) ?? "",
      "VERSION": (Bundle.main.infoDictionary?["CFBundleShortVersionString"]) ?? ""
    ]

    rootView = RCTRootView(bridge: bridge, moduleName: "PSG", initialProperties: props)

    rootView?.backgroundColor = UIColor(red: 22.0/255.0, green: 33.0/255.0, blue: 45.0/255.0, alpha: 1.0)

    self.window = UIWindow(frame: UIScreen.main.bounds)
    let rootViewController = UIViewController()
    rootViewController.view = rootView
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()

    RNSplashScreen.show()

    WonderPush.application(application, didFinishLaunchingWithOptions: launchOptions)
    UIScreen.main.addObserver(self, forKeyPath: "captured", options: .new, context: nil)

    
    NotificationCenter.default.addObserver(self, selector: #selector(self.disableScreenRecording(notification:)), name: Notification.Name("DisableScreenRecording"), object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.enableScreenRecording(notification:)), name: Notification.Name("EnableScreenRecording"), object: nil)
    return true
  }

  private func launchDidomi(apiKey: String) {
    Didomi.shared.setLogLevel(minLevel: OSLogType.info.rawValue)

    Didomi.shared.initialize(
      apiKey: apiKey,
      localConfigurationPath: nil,
      remoteConfigurationURL: nil,
      providerId: nil,
      disableDidomiRemoteConfig: false
    )
  }

  @objc func disableScreenRecording(notification: NSNotification) {
    isScreenRecordingEnabled = false
    DispatchQueue.main.async {
      if self.isCaptured ?? false {
        self.rootView?.isHidden = true
      }
    }
  }
  @objc func enableScreenRecording(notification: NSNotification) {
    isScreenRecordingEnabled = true
  }
  func application(
      _ application: UIApplication,
      continue userActivity: NSUserActivity,
      restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
  ) -> Bool {
    // https://firebase.google.com/docs/dynamic-links/ios/receive#open-dynamic-links-in-your-app step 6
    let handled = DynamicLinks.dynamicLinks()
      .handleUniversalLink(userActivity.webpageURL!) { dynamiclink, error in
        _ = dynamiclink
        _ = error
        // no-op
      }

    return handled || RCTLinkingManager.application(
        application,
        continue: userActivity,
        restorationHandler: restorationHandler)
  }
  
  func application(_ app: UIApplication,
                   open url: URL,
                   options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // https://firebase.google.com/docs/dynamic-links/ios/receive#open-dynamic-links-in-your-app step 7
    if DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) != nil {
     
      return true
    }

    RCTLinkingManager.application(app, open: url, options: options)
    if ApplicationDelegate.shared.application(app, open: url, options: options) {
      return true
    }
    // swiftlint:enable colon
    if Adyen.RedirectComponent.applicationDidOpen(from: url) { return true }

    return authorizationFlowManagerDelegate?.resumeExternalUserAgentFlow(with: url) ?? false
  }

  // swiftlint:disable colon
  func application(_ application: UIApplication,
                   didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
    // swiftlint:enable colon
    WonderPush.application(application,
                           didReceiveRemoteNotification: userInfo)
  }

  func application(_ application: UIApplication,
                   didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    WonderPush.application(application,
                           didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
  }

  func application(_ application: UIApplication,
                   didFailToRegisterForRemoteNotificationsWithError error: Error) {
    WonderPush.application(application,
                           didFailToRegisterForRemoteNotificationsWithError: error)
  }

  // swiftlint:disable colon
  func application(_ application: UIApplication,
                   didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                   fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    // swiftlint:enable colon
    WonderPush.application(application,
                           didReceiveRemoteNotification: userInfo,
                           fetchCompletionHandler: completionHandler)
  }

  func applicationDidBecomeActive(_ application: UIApplication) {
    WonderPush.applicationDidBecomeActive(application)
  }

  func applicationDidEnterBackground(_ application: UIApplication) {
    WonderPush.applicationDidEnterBackground(application)
  }

  func application(_ application: UIApplication,
                   supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return orientationLock
  }
}

How would an AppDelegate.mm file that includes this functionality would look like?

2

Answers


  1. React Native is experimenting with a new rendering system written in c++. C++ is not directly usable via Swift – and thats why they’re recommending using .mm file. .mm file is an Objective c++ file which can have c++ code in it. Using Objective c++ is one way to bridge c++ code to Swift (the other is to write a C wrapper). So to initialize Fabric you need to have the AppDelegate written in objective c++.

    If you prefer to work in swift, then we can write a base class in objective c++, and override relevant methods in swift. Something like this should work.

    Add a new file: AppDelegateBase.h:

    #import <UIKit/UIKit.h>
    
    @interface AppDelegateBase : UIResponder <UIApplicationDelegate>
    
    - (NSDictionary *)prepareInitialProps;
    
    @end
    

    Add another new file: AppDelegateBase.mm – (Based on AppDelegate.mm from react diff project)

    
    #import "AppDelegateBase.h"
    
    #import <React/RCTBundleURLProvider.h>
    #import <React/RCTBridge.h>
    #import <React/RCTRootView.h>
    
    #import <React/RCTAppSetupUtils.h>
    
    #if RCT_NEW_ARCH_ENABLED
    #import <React/CoreModulesPlugins.h>
    #import <React/RCTCxxBridgeDelegate.h>
    #import <React/RCTFabricSurfaceHostingProxyRootView.h>
    #import <React/RCTSurfacePresenter.h>
    #import <React/RCTSurfacePresenterBridgeAdapter.h>
    #import <ReactCommon/RCTTurboModuleManager.h>
    
    #import <react/config/ReactNativeConfig.h>
    
    static NSString *const kRNConcurrentRoot = @"concurrentRoot";
    
    @interface AppDelegateBase () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
      RCTTurboModuleManager *_turboModuleManager;
      RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
      std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
      facebook::react::ContextContainer::Shared _contextContainer;
    }
    @end
    #endif
    
    @implementation AppDelegateBase
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      RCTAppSetupPrepareApp(application);
    
      RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
    
    #if RCT_NEW_ARCH_ENABLED
      _contextContainer = std::make_shared<facebook::react::ContextContainer const>();
      _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
      _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
      _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
      bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
    #endif
    
      self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
      [self.window makeKeyAndVisible];
      return YES;
    }
    
    /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
    ///
    /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
    /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
    /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
    - (BOOL)concurrentRootEnabled
    {
      // Switch this bool to turn on and off the concurrent root
      return true;
    }
    
    - (NSDictionary *)prepareInitialProps
    {
      NSMutableDictionary *initProps = [NSMutableDictionary new];
    
    #ifdef RCT_NEW_ARCH_ENABLED
      initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
    #endif
    
      return initProps;
    }
    
    #if RCT_NEW_ARCH_ENABLED
    
    #pragma mark - RCTCxxBridgeDelegate
    
    - (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
    {
      _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
                                                                 delegate:self
                                                                jsInvoker:bridge.jsCallInvoker];
      return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
    }
    
    #pragma mark RCTTurboModuleManagerDelegate
    
    - (Class)getModuleClassFromName:(const char *)name
    {
      return RCTCoreModulesClassProvider(name);
    }
    
    - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                          jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
    {
      return nullptr;
    }
    
    - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                         initParams:
                                                             (const facebook::react::ObjCTurboModule::InitParams &)params
    {
      return nullptr;
    }
    
    - (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
    {
      return RCTAppSetupDefaultModuleFromClass(moduleClass);
    }
    
    #endif
    
    @end
    

    Update your AppDelegate.swift.. Have marked the changes with >>>.

    
    import UIKit
    import Firebase
    import Adyen
    import GoogleCast
    import Didomi
    import os
    import FBSDKCoreKit
    
    #if DEBUG
    // #if FB_SONARKIT_ENABLED
    import FlipperKit
    // #endif
    #endif
    
    @UIApplicationMain
    class AppDelegate: AppDelegateBase, // >>> subclassing base class 
    UNUserNotificationCenterDelegate, 
    RCTBridgeDelegate, 
    RNAppAuthAuthorizationFlowManager {
    
      private func initializeFlipper(with application: UIApplication) {
        #if DEBUG
        // Check if FB_SONARKIT_ENABLED  and commented pluggins work in RN 0.67+ versions
        // #if FB_SONARKIT_ENABLED
        let client = FlipperClient.shared()
        let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
        // FlipperKitLayoutComponentKitSupport.setUpWith(layoutDescriptorMapper)
        client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))
        client?.add(FKUserDefaultsPlugin(suiteName: nil))
        client?.add(FlipperKitReactPlugin())
        client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
        // client?.add(FlipperReactPerformancePlugin.sharedInstance())
        client?.start()
        // #endif
        #endif
      }
    
      func sourceURL(for bridge: RCTBridge!) -> URL! {
        #if DEBUG
          return RCTBundleURLProvider.sharedSettings()?.jsBundleURL(forBundleRoot: "index", fallbackResource: nil)
        #else
          return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
        #endif
      }
    
      // var window: UIWindow? // >>> window created in Base class
      var bridge: RCTBridge!
      var orientationLock: UIInterfaceOrientationMask = .portrait
      var rootView: RCTRootView?
      var isScreenRecordingEnabled: Bool?
      var isCaptured: Bool?
      public weak var authorizationFlowManagerDelegate: RNAppAuthAuthorizationFlowManagerDelegate?
    
      func application(_ application: UIApplication,
                       willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
       
        _ = localizedString(LocalizationKey(key: "adyen.card.expiryItem.title"), nil)
    
        //  Start screen recording in a disabled state
        isScreenRecordingEnabled = false
        let config = ReactNativeConfig.env()!
        WonderPush.setClientId((config["WONDERPUSH_CLIENT_ID"] as? String)!,
                               secret: (config["WONDERPUSH_CLIENT_SECRET"] as? String)!)
        WonderPush.setupDelegateForUserNotificationCenter()
        WonderPush.setRequiresUserConsent(false)
        WonderPush.setUserConsent(true)
    
        return true
      }
      // swiftlint:disable block_based_kvo
      // swiftlint:disable colon
      override func observeValue(forKeyPath keyPath: String?, of object: Any?,
                                 change: [NSKeyValueChangeKey : Any]?,
                                 context: UnsafeMutableRawPointer?) {
        if #available(iOS 11.0, *) {
          if keyPath == "captured" {
            isCaptured = UIScreen.main.isCaptured
            if !isScreenRecordingEnabled! {
              if isCaptured! {
                rootView?.isHidden = true
              }
              if !isCaptured! && rootView?.isHidden == true {
                rootView?.isHidden = false
              }
            }
          }
        }
      }
    
      override func application(_ application: UIApplication,
                                didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // >>> important to call super.application(_, didFinishLaunchingWithOptions) that is in AppDelegateBase **
        super.application(application, didFinishLaunchingWithOptions: launchOptions)
        // swiftlint:disable force_cast
        launchDidomi(apiKey: ReactNativeConfig.env()!["DIDOMI_API_KEY"] as! String)
        FirebaseApp.configure()
        initializeFlipper(with: application)
    
        let receiverAppID = kGCKDefaultMediaReceiverApplicationID // or "ABCD1234"
        let criteria = GCKDiscoveryCriteria(applicationID: receiverAppID)
        let options = GCKCastOptions(discoveryCriteria: criteria)
        GCKCastContext.setSharedInstanceWith(options)
        GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
    
        self.bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
        guard let bridge = self.bridge else {
          return false
        }
        // >>> props created from AppDelegateBase
        var props: [AnyHashable: Any] = prepareInitialProps()
        props["APP_INFO"] = (Bundle.main.infoDictionary?["APP_INFO"] as? String) ?? ""
        props["VERSION"]: (Bundle.main.infoDictionary?["CFBundleShortVersionString"]) ?? ""
    
        rootView = RCTRootView(bridge: bridge, moduleName: "PSG", initialProperties: props)
    
        rootView?.backgroundColor = UIColor(red: 22.0/255.0, green: 33.0/255.0, blue: 45.0/255.0, alpha: 1.0)
        
        // >>> self.window is created in AppDelegateBase
        let rootViewController = UIViewController()
        rootViewController.view = rootView
        self.window?.rootViewController = rootViewController
        self.window?.makeKeyAndVisible()
    
        RNSplashScreen.show()
    
        WonderPush.application(application, didFinishLaunchingWithOptions: launchOptions)
        UIScreen.main.addObserver(self, forKeyPath: "captured", options: .new, context: nil)
    
        
        NotificationCenter.default.addObserver(self, selector: #selector(self.disableScreenRecording(notification:)), name: Notification.Name("DisableScreenRecording"), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.enableScreenRecording(notification:)), name: Notification.Name("EnableScreenRecording"), object: nil)
        return true
      }
    
      private func launchDidomi(apiKey: String) {
        Didomi.shared.setLogLevel(minLevel: OSLogType.info.rawValue)
    
        Didomi.shared.initialize(
          apiKey: apiKey,
          localConfigurationPath: nil,
          remoteConfigurationURL: nil,
          providerId: nil,
          disableDidomiRemoteConfig: false
        )
      }
    
      @objc func disableScreenRecording(notification: NSNotification) {
        isScreenRecordingEnabled = false
        DispatchQueue.main.async {
          if self.isCaptured ?? false {
            self.rootView?.isHidden = true
          }
        }
      }
      @objc func enableScreenRecording(notification: NSNotification) {
        isScreenRecordingEnabled = true
      }
      func application(
          _ application: UIApplication,
          continue userActivity: NSUserActivity,
          restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
      ) -> Bool {
        // https://firebase.google.com/docs/dynamic-links/ios/receive#open-dynamic-links-in-your-app step 6
        let handled = DynamicLinks.dynamicLinks()
          .handleUniversalLink(userActivity.webpageURL!) { dynamiclink, error in
            _ = dynamiclink
            _ = error
            // no-op
          }
    
        return handled || RCTLinkingManager.application(
            application,
            continue: userActivity,
            restorationHandler: restorationHandler)
      }
      
      func application(_ app: UIApplication,
                       open url: URL,
                       options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        // https://firebase.google.com/docs/dynamic-links/ios/receive#open-dynamic-links-in-your-app step 7
        if DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) != nil {
         
          return true
        }
    
        RCTLinkingManager.application(app, open: url, options: options)
        if ApplicationDelegate.shared.application(app, open: url, options: options) {
          return true
        }
        // swiftlint:enable colon
        if Adyen.RedirectComponent.applicationDidOpen(from: url) { return true }
    
        return authorizationFlowManagerDelegate?.resumeExternalUserAgentFlow(with: url) ?? false
      }
    
      // swiftlint:disable colon
      func application(_ application: UIApplication,
                       didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        // swiftlint:enable colon
        WonderPush.application(application,
                               didReceiveRemoteNotification: userInfo)
      }
    
      func application(_ application: UIApplication,
                       didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        WonderPush.application(application,
                               didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
      }
    
      func application(_ application: UIApplication,
                       didFailToRegisterForRemoteNotificationsWithError error: Error) {
        WonderPush.application(application,
                               didFailToRegisterForRemoteNotificationsWithError: error)
      }
    
      // swiftlint:disable colon
      func application(_ application: UIApplication,
                       didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                       fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // swiftlint:enable colon
        WonderPush.application(application,
                               didReceiveRemoteNotification: userInfo,
                               fetchCompletionHandler: completionHandler)
      }
    
      func applicationDidBecomeActive(_ application: UIApplication) {
        WonderPush.applicationDidBecomeActive(application)
      }
    
      func applicationDidEnterBackground(_ application: UIApplication) {
        WonderPush.applicationDidEnterBackground(application)
      }
    
      func application(_ application: UIApplication,
                       supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return orientationLock
      }
    }
    

    This should automatically create a Bridging header for your project.
    Add this to your bridging header:

    #include "AppDelegateBase.h"
    
    Login or Signup to reply.
  2. As per react native doc https://reactnative.dev/docs/new-architecture-app-intro

    TurboModules can be written using Objective-C or C++. In order to support both cases, any source files that include C++ code should use the .mm file extension. This extension corresponds to Objective-C++, a language variant that allows for the use of a combination of C++ and Objective-C in source files.

    Read all doc related to iOS carefully

    AND

    Implement this method in swift

    #pragma mark - RCTCxxBridgeDelegate
    
        - (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
        {
          return std::make_unique<facebook::react::HermesExecutorFactory>(facebook::react::RCTJSIExecutorRuntimeInstaller([bridge](facebook::jsi::Runtime &runtime) {
              if (!bridge) {
                return;
              }
            })
          );
        }
    

    Make sure to mark above method as @objc method

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search