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-nativeStep 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.
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.
#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)
@endInclude React headers in your app’s Swift bridging header if your target requires one:
#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:
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:
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
nodecommand not found - make sure you have node installed in your machine before running the command below:
ln -s $(which node) /usr/local/bin/nodeenum clockid_terror - make sure you have no empty space in your$PWDpath
// DO
/Users/JohnDoe/ReactProject/ArApp
// DON'T - somehow it got this error when space in your path
/Users/John Doe/React Project/ArApp