We've worked on projects where developers tried to embed AR directly through ARKit and ARCore integrations, only to end up with code that ran on half the devices. AR Foundation (Unity) enables cross-platform AR app development with one codebase and two builds. But that doesn't make the feature sets identical—LiDAR occlusion works only on iOS Pro devices, and ML-based Depth API is an Android exclusive on chips without ToF. Writing AR Foundation without understanding these differences leads to runtime exceptions on half the devices. Our experience shows that checking capabilities via descriptor and implementing fallback mechanisms prevents 90% of crashes. We offer a comprehensive solution—from audit to publishing—with quality assurance and support at every stage. Contact us for a consultation on your project. AR Foundation integration starts at $1,500 for basic plane detection and object placement on both platforms, saving up to $10,000 in development time compared to native implementation.
AR Foundation Solves Cross-Platform Challenges
AR Foundation version 6.x (latest Unity LTS) covers all key features of both platforms: plane detection, image tracking, face tracking, mesh classification, point clouds. However, the underlying implementation differs, and some flags only work if the platform backend supports them. Below is a typical verification code:
[SerializeField] AROcclusionManager occlusionManager;
void Start()
{
if (occlusionManager.descriptor?.supportsEnvironmentDepthImage == true)
{
occlusionManager.requestedEnvironmentDepthMode = EnvironmentDepthMode.Fastest;
occlusionManager.requestedOcclusionPreferenceMode = OcclusionPreferenceMode.PreferEnvironmentOcclusion;
}
else
{
occlusionManager.enabled = false;
}
}
Without checking descriptor, you get a NotSupportedException on a Pixel 5 (no ToF). Our engineers always include such checks.
Scene Architecture Is Critical for Stability
AR Foundation builds on components tied to ARSession and XROrigin:
-
ARPlaneManager— plane detection and tracking -
ARRaycastManager— raycasting against tracked geometry -
ARTrackedImageManager— marker-based tracking -
ARAnchorManager— anchor lifecycle management
Correct object placement via tap using ARRaycastManager:
[SerializeField] ARRaycastManager raycastManager;
[SerializeField] ARAnchorManager anchorManager;
[SerializeField] GameObject prefabToPlace;
private List<ARRaycastHit> hits = new List<ARRaycastHit>();
void Update()
{
if (Input.touchCount == 0) return;
var touch = Input.GetTouch(0);
if (touch.phase != TouchPhase.Began) return;
if (raycastManager.Raycast(touch.position, hits, TrackableType.PlaneWithinPolygon))
{
var hitPose = hits[0].pose;
var anchor = anchorManager.AttachAnchor(
hits[0].trackable as ARPlane,
hitPose
);
Instantiate(prefabToPlace, anchor.transform);
}
}
AttachAnchor binds the object to a specific plane—if the plane updates its geometry (ARKit continually refines shapes), the object stays anchored. Without anchor attachment, the object drifts.
Image Tracking: Reference Library
Images are compiled into XRReferenceImageLibrary via Unity Editor. Limitations: ARKit allows up to 100 images in the library with concurrent tracking of up to 4. ARCore has nearly unlimited images, but simultaneously tracks up to 20 at most.
[SerializeField] ARTrackedImageManager trackedImageManager;
void OnEnable() => trackedImageManager.trackablesChanged.AddListener(OnImageChanged);
void OnDisable() => trackedImageManager.trackablesChanged.RemoveListener(OnImageChanged);
void OnImageChanged(ARTrackablesChangedEventArgs<ARTrackedImage> args)
{
foreach (var added in args.added)
{
SpawnContent(added.referenceImage.name, added.transform);
}
foreach (var updated in args.updated)
{
SetVisible(updated.referenceImage.name, updated.trackingState == TrackingState.Tracking);
}
}
Performance: Unity + AR = Proceed with Caution
Unity is not the lightest environment for AR. Typical issues:
Garbage collector pauses. The .NET/Mono GC stops the main thread. At 60 FPS AR session, a 16ms pause means a dropped frame and jittery objects. Solution: use pre-allocated List<T> (pass into Raycast), avoid new inside Update().
DrawCall overhead. Every AR object without batching is a separate draw call. Use GPU Instancing in materials and Static Batching for objects that don't move. On Android, prefer Vulkan backend over OpenGLES for lower CPU overhead.
Texture Compression. ASTC for iOS, ETC2 for Android. In an AR Foundation project targeting both, set up Override for Platform in Texture Import Settings. ASTC on Android requires GPU support (available on all ARCore-compatible devices).
Performance Optimization Tips
| Problem | Solution | |---------|----------| | GC pauses | Pre-allocated List, avoid new in Update | | DrawCall overhead | GPU Instancing, Static Batching, Vulkan on Android | | Texture Compression | ASTC for iOS, ETC2 for Android, Override for platform |Build and Publishing
AR Foundation requires specific Player Settings:
- iOS:
Camera Usage Descriptionmandatory (App Store requirement),ARKitcapability - Android:
CAMERApermission in AndroidManifest,com.google.ar.corein dependencies
ARCore checks for AR Services on launch—you must handle ARUnavailableException. Without it, the app silently crashes on incompatible devices.
What’s Included in Our Work
Deliverables include: requirements analysis and stack selection (Unity LTS, AR Foundation 6.x, StoreKit 2 / Billing 6 for purchases), implementation with device capability checks and fallback logic, performance optimization (GC, batching, textures), build and publishing setup (App Store Connect / Google Play Console), API and configuration documentation, team training and 2 weeks post-release support.
Our team consists of certified Unity developers with 10+ years of experience and over 50 AR projects delivered. Get a consultation for your project—write to us.
Timelines
Basic AR Foundation integration with plane detection and object placement (iOS + Android): from 5 days. Marker-based AR with image library and custom animations: 1–2 weeks. Full solution with occlusion, face tracking, and publishing to both platforms: 3–6 weeks.
Common AR Foundation Integration Mistakes to Avoid
- Not checking descriptor — crash on devices without ToF.
- Uploading ASTC textures to Android without support — black textures.
- Using
newinsideUpdate— micro-freezes every 10–20 seconds. - Not handling
ARUnavailableException— silent crash on old Android devices. - Missing
Camera Usage Description— App Store rejection.
Comparison of AR Foundation with Other Approaches
| Approach | Development Time (iOS + Android) | Codebase | Performance |
|---|---|---|---|
| Direct ARKit + ARCore | 2–3 weeks | 2 codebases | Maximum |
| AR Foundation | 5–14 days | Single C# | 95–98% of native |
| Vuforia | 7–10 days | Single C# + license | 80–90% |
AR Foundation beats direct integration by cutting development time by 40–50% with minimal performance loss. Contact us to estimate your integration costs—we'll assess the task and propose a solution.
How to Integrate AR Foundation (Step-by-Step)
- Set up Unity project with AR Foundation package.
- Configure XR Plug-in Management for ARCore and ARKit.
- Add AR Session and XR Origin to the scene.
- Implement plane detection with AR Plane Manager.
- Add raycasting for object placement.
- Build and test on devices.







