title: Importing Swift ViewController to React Native
body: <p>I'm trying to integrate this feature <a href="https://github.com/heinrisch/faceid-to-stl" rel="nofollow noreferrer">https://github.com/heinrisch/faceid-to-stl</a> into my react native app. The repo is written in swift and I basically want to display the ViewController class into my react native app but I'm not sure how to. Wanted to try this out first and then eventually I want to integrate the StandardCyborg SDK <a href="https://standardcyborg.com/" rel="nofollow noreferrer">https://standardcyborg.com/</a> instead to do 3D face scanning for a React Native app.</p>
  
  <p>I've tried multiple posts about bridging native modules and functions and I've been able to do that. But I'm thinking ViewControllers are a bit different since they're not UI Components? Or are they? Very new to bridging native modules and not familiar with swift. Any help is much appreciated.</p>
  
  <p>ViewController.m</p>
  
  <pre class="lang-c prettyprint-override"><code>#import &lt;Foundation/Foundation.h&gt;
  
  #import &lt;React/RCTBridgeModule.h&gt;
  #import &lt;React/RCTViewManager.h&gt;
  #import &lt;React/RCTEventEmitter.h&gt;
  
  @interface RCT_EXTERN_MODULE(Mask, NSObject)
  RCT_EXTERN_METHOD(init)
  RCT_EXTERN_METHOD(init?)
  RCT_EXTERN_METHOD(update)
  @end
  
  @interface RCT_EXTERN_MODULE(ViewController, NSObject)
  RCT_EXTERN_METHOD(viewDidLoad)
  RCT_EXTERN_METHOD(renderer)
  RCT_EXTERN_METHOD(renderer)
  RCT_EXTERN_METHOD(startSession)
  RCT_EXTERN_METHOD(capture)
  RCT_EXTERN_METHOD(presentShareSheet)
  RCT_EXTERN_METHOD(createSTL)
  RCT_EXTERN_METHOD(generateURL)
  @end
  
  </code></pre>
  
  <p>oxygen-Bridging-Header.h</p>
  
  <pre class="lang-c prettyprint-override"><code>
  #import &lt;React/RCTBridgeModule.h&gt;
  
  
  </code></pre>
  
  <p>AppDelegate.m</p>
  
  <pre class="lang-c prettyprint-override"><code>#import "AppDelegate.h"
  
  #import &lt;React/RCTBridge.h&gt;
  #import &lt;React/RCTBundleURLProvider.h&gt;
  #import &lt;React/RCTRootView.h&gt;
  
  @implementation AppDelegate
  
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
    RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                     moduleName:@"oxygen"
                                              initialProperties:nil];
  
    rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
  
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *rootViewController = [UIViewController new];
    rootViewController.view = rootView;
    self.window.rootViewController = rootViewController;
    [self.window makeKeyAndVisible];
    return YES;
  }
  
  - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
  {
  #if DEBUG
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
  #endif
  }
  
  @end
  
  </code></pre>
  
  <p>AppDelegate.h</p>
  
  <pre><code>
  #import &lt;React/RCTBridgeDelegate.h&gt;
  #import &lt;UIKit/UIKit.h&gt;
  
  @interface AppDelegate : UIResponder &lt;UIApplicationDelegate, RCTBridgeDelegate&gt;
  
  @property (nonatomic, strong) UIWindow *window;
  
  @end
  
  </code></pre>
  
  <p>ViewController.swift</p>
  
  <pre class="lang-swift prettyprint-override"><code>@objc(ViewController)
  class ViewController: UIViewController, ARSCNViewDelegate {
  
    @objc @IBOutlet var sceneView: ARSCNView!
    @objc private var isPresentingShareSheet = false
    @objc private var mask: Mask?
    @objc private var lastFaceAnchor: ARFaceAnchor?
  
    @objc
    static func requiresMainQueueSetup() -&gt; Bool {
      return true
    }
  
    @objc
    override func viewDidLoad() {
      print("ViewController loaded...")
      super.viewDidLoad()
  
      sceneView.delegate = self
      startSession()
  
      let button = UIButton(type: .custom)
      button.setTitle("Capture", for: .normal)
      button.tintColor = .black
      button.titleLabel?.textColor = .black
      button.backgroundColor = .lightGray
      button.addTarget(self, action: #selector(capture), for: .touchUpInside)
      button.layer.cornerRadius = 12
      view.addSubview(button)
  
      button.translatesAutoresizingMaskIntoConstraints = false
      let constraints: [NSLayoutConstraint] = [
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        button.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -40),
        button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
        button.heightAnchor.constraint(equalToConstant: 55)
      ]
      view.addConstraints(constraints)
    }
  
    @objc
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
      //        let device = sceneView.device!
      //        let maskGeometry = ARSCNFaceGeometry(device: device)!
      //        mask = Mask(geometry: maskGeometry)
      let device = MTLCreateSystemDefaultDevice()
      let maskGeometry = ARSCNFaceGeometry(device: device!)!
      mask = Mask(geometry: maskGeometry)
      node.addChildNode(mask!)
  
    }
  
    @objc
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
      guard let faceAnchor = anchor as? ARFaceAnchor else { return }
      mask?.update(withFaceAnchor: faceAnchor)
  
      if let faceAnchor = anchor as? ARFaceAnchor {
        lastFaceAnchor = faceAnchor
      }
    }
  
    @objc
    private func startSession() {
      sceneView.scene.rootNode.childNodes.forEach {
        $0.removeFromParentNode()
      }
  
      let configuration = ARFaceTrackingConfiguration()
      configuration.isLightEstimationEnabled = true
      sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }
  
    @objc
    private func capture() {
      guard let faceAnchor = lastFaceAnchor else {
        return
      }
  
      let data = createSTL(from: faceAnchor)
      let url = generateURL(for: data)
      presentShareSheet(with: url)
    }
  
    @objc
    private func createSTL(from faceAnchor: ARFaceAnchor) -&gt; Data {
  
      let mapped = faceAnchor.geometry.triangleIndices.map { i in
        return faceAnchor.geometry.vertices[Int(i)]
      }
  
      var out: [String] = ["solid face"]
      mapped.enumerated().forEach { i, vertex in
        if i % 3 == 0 {
          out.append("facet normal 0 0 0")
          out.append("\touter loop")
        }
  
        out.append("\t\tvertex \(vertex.x) \(vertex.y) \(vertex.z)")
  
        if i % 3 == 2 {
          out.append("\tendloop")
        }
      }
  
      out.append("endsolid face")
  
      let file = out.joined(separator: "\n")
      let data = file.data(using: .ascii)!
      return data
    }
  
    @objc
    private func generateURL(for data: Data) -&gt; URL {
      let url = URL(fileURLWithPath: NSTemporaryDirectory() + "face.stl")
      try! data.write(to: url)
      return url
    }
  
    @objc
    private func presentShareSheet(with url: URL) {
      self.isPresentingShareSheet = true
      DispatchQueue.main.async {
        let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
        activityViewController.completionWithItemsHandler = { _, _, _, _ in
          self.isPresentingShareSheet = false
        }
        self.present(activityViewController, animated: true, completion: nil)
      }
    }
  }
  </code></pre>