1

I want to include ARKit in an app designed for iOS10+ where I replace ARKit with SceneKit if the iOS version is <11.

Unfortunately it seems like there is no way to currently do this?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
XCode
  • 89
  • 5
  • 2
    This is like saying "I want to use a 2017 iPhone in the year 1966." – matt Jul 26 '17 at 16:22
  • @matt No trouble there. Also, I have a DeLorean I'm looking to sell. ;) – rickster Jul 26 '17 at 19:27
  • 1
    No this is like saying I want to support the 4 million people who currently use my app and may not necessarily have a device that supports ARKit. – XCode Jul 28 '17 at 14:34

3 Answers3

7

Depending on how you've set your expectations, it is possible to use SceneKit as a "fallback" from ARKit -- specifically, from ARSCNView.

What you can easily do is create a 3D content experience that appears "in the real world" via AR when running on an ARKit capable device, and in an entirely virtual setting (that is, rendered in 3D without a camera feed as background) when running without ARKit.

Note: ARKit support isn't just an iOS 11 thing -- you also need an A9 device. So you might think about a fallback experience for older hardware on iOS 11, not just for older iOS versions.

To do that, you'll need to be able to swap out your view class at runtime. That means not creating ARSCNView in a storyboard, but initializing one and adding it to your view controller's root view in code.

override func viewDidLoad() {
    super.viewDidLoad()
    let sceneView = ARSCNView(frame: view.bounds)
    sceneView.scene = // ... set up your SceneKit scene ...
    view.addSubview(sceneView)
}

Once you're doing something like that, you can wrap the critical part in a conditional that uses ARSCNView when available and SCNView otherwise. Actually, you might want to set up a handy function for that...

var canUseARKit: Bool {
    if #available(iOS 11.0, *) {
        return ARWorldTrackingSessionConfiguration.isSupported
    } else {
        return false
    }
}

Then you can conditionalize your view setup:

override func viewDidLoad() {
    super.viewDidLoad()
    let sceneView: SCNView
    if canUseARKit {
        sceneView = ARSCNView(frame: view.bounds)
    } else {
        sceneView = SCNView(frame: view.bounds)
    }
    sceneView.scene = // ... set up your SceneKit scene ...
    view.addSubview(sceneView)
}

Of course, there's still more to do after that:

  • When you're using ARKit, you get camera control "for free"; when you're using SceneKit on its own you'll have to think about where to place the camera and how to let the user control it. (Check the WWDC17 SceneKit session for some tips on new iOS 11 camera controls.)
  • When you're using SceneKit on its own, your 3D content defines "the world" that the user interacts with -- that is, you place cameras and such in relation to your content. When using ARKit, you have to think about where and how to place your content relative to the real world.

But aside from such concerns, working with SceneKit content within ARSCNView is no different from working with SceneKit content in SCNView, so for the rest of your app/game you can share a lot of code and assets between AR and non-AR user experiences.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • 1
    On the other hand, if you're looking to fall back from using SceneKit to render an ARKit-based AR experience (where supported) to using SceneKit to render an AR experience without ARKit, you have a lot more work cut out for you. – rickster Jul 26 '17 at 20:42
  • 1
    Again this is straightforward but you can't use this as its not possible to gate the import statements in Swift 4. – XCode Jul 28 '17 at 14:33
  • You don't need to "gate the import statements". Again I ask: what problem are you actually having? – matt Jul 28 '17 at 15:33
  • @matt "No such module ARKit" – XCode Aug 03 '17 at 19:53
  • 1
    @XCode Under what circumstances do you get that? If you build against iOS 11 with deployment target iOS 10 you won't any such error. – matt Aug 03 '17 at 20:18
3

You can conditionally choose to include features using the following syntax:

if #available(iOS 11.0, *) {
    // Use ARKit
} else {
   // Use SceneKit
}
kgaidis
  • 14,259
  • 4
  • 79
  • 93
0

Like any framework, ARKit exists in the system version(s) where it exists, and in no other system versions. ARKit exists in iOS 11, not in iOS 10 or before. An iOS 10 user can never use ARKit (without upgrading to iOS 11).

(And even then, ARKit will be usable only on a subset of devices running iOS 11, as its features are highly hardware-dependent.)

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 2
    It's also worth noting that ARKit is only available on a subset of iOS 11 supported devices, not all of them. – JAL Jul 26 '17 at 16:21
  • @JAL Nice, I'll add that. – matt Jul 26 '17 at 16:22
  • 1
    @matt did you actually read the question? I didn't ask if an iOS10 user can use ARKit, I asked if I can include ARKit in an app for iOS10+ users and use SceneKit as a fallback. – XCode Jul 28 '17 at 14:32
  • Then I don't see what the problem is. Nothing stops you from importing ARKit even if the app is to run on iOS 10. And you know about availability checks, presumably. So what's the hard part? – matt Jul 28 '17 at 15:32