Nicoleta Pop
Jun 7 · 8 min read

We all know that these two giants, Apple and Google, are competing against each other very hard in terms of achieving the best market place in the tech community, especially in the field that they are heavily banking on, namely Augmented Reality. But, in this tutorial, we’re going to see them working together in building an application that can add airplanes into the current environment and… they can be seen even when the user closes and reopens the app! Isn’t that pretty cool?

Before we start this tutorial, you should be aware that we will not cover the basic aspects, theoretically and practically speaking, of Apple’s ARKit, so if you want to fulfill this prerequisite, I’ll suggest you take a look at my other articles: Augmented Reality Must Knows in terms of developing iOS applications and ARKit Tutorial: Infest your room!. The latter also contains more information about the 3D graphics library that we are also going to use, and, for further investigation, you can use Apple’s official documentation on SceneKit.


The app that we are going to build will not require any external 3D model at all because the default airplane will be used. All we have to do is to place an airplane on every anchor that does not correspond to a detected plane, by using user touches events on the scene called hitTests.

The thing is, we want to persist those positions in which we have rendered those objects when, let’s say, we accidentally close the app. So, here is where the so-called Cloud Anchors, courtesy of Google’s ARCore, come in handy. These can also help multiple users share the exact same experience in different positions of their cameras, not only by iOS users, just like ARKit 2.0 offers, but even those using Android devices! This is where the Cloud comes in because it will save these anchors, persist them for approximately 24 hours, time period in which anyone could retrieve them in the exact same position by only a button tap! Pretty much something that can ease communication between opposite platforms, undoubtedly a huge weight off of any dev’s shoulders.


The technical concepts of storing and retrieving anchors from the Cloud are hosting (ten seconds after positioning the camera in the point of interest) and resolving (no farther than 10 meters and no more than 24 hours since hosting), respectively. “Cloud Anchors are similar in behavior and function to anchors, but differ in that they’re hosted on Google servers. This hosting enables users to shared experiences”, from ARCore’s iOS SDK official documentation.

All that said, let’s get this started!

Firstly, we’re going to create an iOS application using AR template, with SceneKit as the graphics library:

Xcode ARKit template

Then, we have to decide on a service that can help us share the ids of anchors across different devices. We’re going to use Firebase for that, so go create a Firebase project on firebase.google.com and create a project with the project name that you gave to the iOS project and add the iOS app to it. Also, to use Firebase in your Xcode project, you have to properly configure it and finally, add GoogleService-Info.plist, next to the Info.plist file. The steps for configuring a Firebase project are pretty straightforward on the official website, so go ahead and do that by yourself and get back when you’re ready to move on :).

Ok, so after configuring your project to integrate Firebase, you should definitely enable the Realtime Database from the list of services (or use any for storing Cloud Anchors IDs) and, for the learning purpose, select Start in test mode (all read/write rights are enabled globally, so be aware to change that setting when you push your app to production).

Next, using Cocoapods, we should add to the Podfile the following pods:

pod ‘ARCore’pod ‘Firebase/Core’pod ‘Firebase/Database’

The process of configuring Firebase into the project requires adding the core pod of it. I chose to use Firebase Realtime Database for storing hosted anchors ids, so the database pod must also be there. Finally, the pod corresponding to the ARCore library is included.

Run ‘pod install’ and let it be created a .xcworkspace project for you.

One more step after we start the coding process is to enable ARCore API from the Google Cloud Platform and follow the steps of creating an API Key that we are going to use in our project to pair our ARSession to Google’s. See Setting up API keys and Enable ARCore Club Anchor API for more information on how to do this. Before that, you should create a project with the same bundle ID as the one from Xcode and Firebase because specific APIs would be activated in projects of interest.

Google Cloud platform projects

After enabling the service, you should see a sandwich menu on the left side of the page in which you have to select the Credentials item. Then, hit the Create credentials button and you should see a drop-down menu from which you need to select API Key.

A dialog will appear to inform you that a new API Key was created for your best excitement in using Google in your everyday projects :).

Google Cloud project credentials

Don’t forget to add in the AppDelegate’s didFinishLaunchingWithOptions method the FirebaseApp.configure() in order to successfully connect to these Google services. Now, after checking that our project communicates with the Google servers and seeing that everything works as planned, we should finally start writing some code.

The UIViewController class comes predefined with a view of type ARSCNView (because we’re using SceneKit) and because we’re going to use some renderer methods when an anchor is detected by the application, the following line of code should not be erased:

sceneView.delegate = self

The most important class to be used in the setup process with ARCore is definitely GARSession, which is the doppelgänger of the classic ARSession class, with the difference that it is managed by the Google servers. Because we’re going to handle connection and update events from both sessions, the class has to conform to the ARSessionDelegate and GARSessionDelegate.

Creating a GARSession object is a piece of cake:

garSession = try! GARSession(apiKey: “INSERT_YOUR_API_KEY”, bundleIdentifier: nil)garSession.delegate = self

The main flow is that the user will tap on the screen (with already enabled camera session) and the touches will be used to hitTest AR view in order to place an airplane model and then host it into the Google Cloud servers:

let hitResults = sceneView.hitTest(touchLocation, types: [.existingPlane, .existingPlaneUsingExtent, .estimatedHorizontalPlane])if let firstResult = hitResults.first {hostAnchor(transform: firstResult.worldTransform)}

In this example, the location of the touching event will be determined using the following conditions: on a detected plane without (.existingPlane) and with (.existingPlaneUsingExtent) an estimated size, and it has to be a horizontal one (.estimatedHorizontalPlane).

On the first result of the hitTest, the airplane will be placed on the scene and the corresponding anchor will be saved on the Google Cloud platform:

private func hostAnchor(transform: matrix_float4x4) {let anchor = ARAnchor(transform: transform)sceneView.session.add(anchor)do {try garSession.hostCloudAnchor(anchor)}catch {// handle error}}

The adding planes operation itself will be performed on the delegate method that attaches a node to the newly added anchor:

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {if !(anchor is ARPlaneAnchor) {let scene = SCNScene(named: “art.scnassets/ship.scn”)!return scene.rootNode.childNode(withName: “ship”, recursively: false)}return nil}

At the beginning of every AR session, the hosted anchors will be retrieved locally in the application in order to successfully return them for reliving the experience. The container used for doing this will be an array of String that stores the Cloud ID of the hosted anchors:

private func fetchAnchors() {firebaseDbRoot.observe(.value) { (dataSnapshot) in//handle dataSnapshot valuelet values = snapshotValue.valuesvalues.forEach({ (value) inif let dict = value as? [String: Any], let anchorId = dict[“hosted_anchor_id”] as? String {self.anchorIDList.append(anchorId)}})}}

This way, all anchors that were hosted and not already retrieved back into the AR experience will be saved on the Firebase Realtime Database and also the local array of the app. The actual Firebase db saving is done in the delegate method of successfully hosted an anchor:

func session(_ session: GARSession, didHostAnchor anchor: GARAnchor) {}

To resolve the hosted anchors (that are persistent on the Cloud for a maximum of 24 hours), the app will provide a button that will call the specific method:

app UI
private func resolveAnchors() {self.anchorIDList.forEach { (anchorID) indo {try garSession.resolveCloudAnchor(withIdentifier: anchorID)} catch {// handle error}}self.anchorIDList.removeAll()self.firebaseDbRoot.removeValue()}

There is a delegate method that handles the fact that the anchor was successfully resolved, in which the specific anchor will be added into the scene:

func session(_ session: GARSession, didResolve anchor:GARAnchor) {let anchor = ARAnchor(transform: anchor.transform)sceneView.session.add(anchor: anchor)}

Also, there is a delegate method that handles errors when hosting/resolving anchors are coming back negative, meaning session(_:, didFailToHostAnchor:) and session(_:, didFailToResolve:).

Gathering all this code up, we should obtain a totally basic functioning app that undoubtedly demonstrates the usage of ARCore’s features for the iOS platform.

I know you’ve been pretty much losing your patience while waiting, but the Cloud Anchors ID do need to be saved into the Firebase Database in order to properly retrieve them from the Cloud Platform and that needs a few extra time :) (approximately 10 seconds after finishing hosting, and 10 seconds before resolving them in order to properly determine and understand the scene).

That was it for now! Thank you for reading this article and don’t forget to hit the claps button if you liked it. The entire code can be found on Github. This was a pretty basic functionality, inspired by the official ARCore Demo, that fully demonstrates Google’s contribution and communion with the ARKit library. See below the demo video I’ve prepared for you and… Stay tuned for more!


Zipper Studios is a group of passionate engineers helping startups and well-established companies build their mobile products. Our clients are leaders in the fields of health and fitness, AI, and Machine Learning. We love to talk to likeminded people who want to innovate in the world of mobile so drop us a line here.

Zipper Studios

At Zipper Studios we help startups and well established companies build their mobile products. (www.zipperstudios.co)

Thanks to Filip Marusca

Nicoleta Pop

Written by

iOS Developer @ Zipper Studios co.

Zipper Studios

At Zipper Studios we help startups and well established companies build their mobile products. (www.zipperstudios.co)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade