Skip to Content
Quick StartReact Native

React Native

This page show several ways to integrate ARCloud native module to React Native project.

TL;DR

The sample repository demonstrates a React Native bridge. Use the iOS example below to integrate Graffity AR Cloud 5.1.1.

Step 1 - Clone this git repo

Github - Graffity-Technologies/arcloud-sample-react-native

Step 2 - Put YOUR_ACCESS_TOKEN in ios/ARCloudIos.swift

iOS Bridge

The iOS bridge below uses the 5.1.1 public API. Set your iOS deployment target to 18.0+, install the GraffityARCloud product, and add both permission descriptions.

Copy the complete ARExperienceViewController UIKit example into your iOS target. It owns the SDK, embeds its view, and provides a native Close button that shuts down the session.

This example uses React Native’s Objective-C native-module bridge. Add these Swift/Objective-C files to your iOS app target; ensure React’s bridge headers are available.

ARCloudIos.swift
import UIKit import React @objc(ARCloudIos) final class ARCloudIos: NSObject { @MainActor private weak var arHost: ARExperienceViewController? @objc static func requiresMainQueueSetup() -> Bool { true } @objc(open:resolver:rejecter:) func open( _ accessToken: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock ) { Task { @MainActor in guard arHost == nil else { reject("AR_ALREADY_OPEN", "Close the current AR session first.", nil) return } guard let presenter = RCTPresentedViewController() else { reject("NO_PRESENTER", "No view controller is available.", nil) return } do { let host = try ARExperienceViewController(accessToken: accessToken) host.modalPresentationStyle = .fullScreen arHost = host presenter.present(host, animated: true) { resolve(nil) } } catch { reject("AR_INIT_FAILED", error.localizedDescription, error as NSError) } } } @objc(close:rejecter:) func close( _ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock ) { Task { @MainActor in guard let host = arHost else { resolve(nil) return } await host.endSession() host.dismiss(animated: true) { resolve(nil) } arHost = nil } } }

The presented controller retains its SDK. The bridge uses a weak host reference, which clears when the user closes the native view.

ARCloudIos.m
#import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(ARCloudIos, NSObject) RCT_EXTERN_METHOD(open:(NSString *)accessToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(close:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) @end

Include React headers in your app’s Swift bridging header if your target requires one:

App-Bridging-Header.h
#import <React/RCTBridgeModule.h> #import <React/RCTViewManager.h>

Call the module from JavaScript and handle initialization failures:

import React from 'react'; import { Alert, Button, NativeModules } from 'react-native'; const { ARCloudIos } = NativeModules; export function OpenARButton({ accessToken }) { const open = async () => { try { await ARCloudIos.open(accessToken); } catch (error) { Alert.alert('Unable to open AR', error.message); } }; return <Button title="Open AR" onPress={open} />; } // Use ARCloudIos.close() for a programmatic exit. // The native host also provides its own Close button.

The open promise confirms presentation, not successful VPS localization. Runtime events need a separate event bridge based on GraffityARCloudDelegate. Apps using a different React Native architecture can reuse the same SDK host and lifecycle in their native-module implementation. See React Native’s iOS native-module guide .

Android Bridge

Install Android SDK 5.0.2, set API 28+ as your minimum, and add the manifest permissions and Activity declaration.

Copy the complete GraffityARActivity host and layout into your Android app package. That Activity creates the SDK, requests permissions, checks ARCore installation, and shuts down when the user presses Close or Back.

The following React Native bridge launches that host with a token:

GraffityARModule.kt
package com.example.app import android.content.Intent import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.UiThreadUtil class GraffityARModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { override fun getName(): String = "GraffityARCloud" @ReactMethod fun open(accessToken: String, promise: Promise) { if (accessToken.isBlank()) { promise.reject("INVALID_TOKEN", "An access token is required.") return } UiThreadUtil.runOnUiThread { val activity = currentActivity if (activity == null) { promise.reject("NO_ACTIVITY", "No Activity is available to present AR.") return@runOnUiThread } try { val intent = Intent(activity, GraffityARActivity::class.java) .putExtra(GraffityARActivity.EXTRA_ACCESS_TOKEN, accessToken) activity.startActivity(intent) promise.resolve(null) } catch (error: Exception) { promise.reject("AR_LAUNCH_FAILED", error.message, error) } } } }

Register the module through a ReactPackage:

GraffityARPackage.kt
package com.example.app import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager class GraffityARPackage : ReactPackage { override fun createNativeModules(context: ReactApplicationContext): List<NativeModule> = listOf(GraffityARModule(context)) override fun createViewManagers(context: ReactApplicationContext): List<ViewManager<*, *>> = emptyList() }

Add GraffityARPackage() to your app’s React Native package list. See React Native’s Android native-module guide  for registration in your host setup.

import React from 'react'; import { Alert, Button, NativeModules } from 'react-native'; const { GraffityARCloud } = NativeModules; export function AndroidARButton({ accessToken }) { const open = async () => { try { await GraffityARCloud.open(accessToken); } catch (error) { Alert.alert('Unable to open AR', error.message); } }; return <Button title="Open AR" onPress={open} />; }

The promise confirms Activity launch, not permission approval, SDK initialization, or successful localization. The host handles those steps and provides its native Close button. Add an event bridge backed by GraffityARCloudListener if JavaScript needs runtime events. Other native-module implementations can use the same Activity and SDK lifecycle.

React Native Common Errors

  • Xcode node command not found - make sure you have node installed in your machine before running the command below:
ln -s $(which node) /usr/local/bin/node
  • enum clockid_t error - make sure you have no empty space in your $PWD path
// DO /Users/JohnDoe/ReactProject/ArApp // DON'T - somehow it got this error when space in your path /Users/John Doe/React Project/ArApp