Turbo Native in 15 Minutes
Tags: programming, turbonative
Published: 2023-10-08 18:45:07

## Overview

This are my notes while watching Joe Masilotti's youtube video on "Turbo Native in 15 minutes"

## Resources

* [Turbo Native in 15 minutes](https://www.youtube.com/@joemasilotti) - Joe Masilotti - Learn how to get up and running with Turbo Native on iOS in 15 minutes. All you need to get started is a free copy of Xcode downloaded from the App Store.

## Create Barebones Xcode Project

* Open Xcode

* File - New Project

 * Select Interface "Story Board"

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xv1feozpg7sj0gdi4i7.png)

* Should launch to blank app.

### Remove Boiler Plate

* From File Navigator, Delete main.storyboard

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hy9elthbo6cpsfus37tg.png)

* From Info PList, Expand keys, Delete Storyboard Name

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gjqozssvbq34mvfcxmsz.png)

* Remove Storyboard Reference From Build Settings

 * From Navigator Pane, Open Project

 * Click Target

 * Build Settings Tab

 * Delete UIKit Main Storybaord

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd0m0ea5zgdvaxyo8k73.png)

### Setup Scene 

 * Open SceneDelegte from Navigation Pane

 * Delete everything except func scene

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    self.window = UIWindow(windowScene: windowScene)
    self.window?.rootViewController = UIViewController()
    self.window?.rootViewController?.view.backgroundColor = .orange
    self.window?.makeKeyAndVisible()
}
```

## Build TurboNative App

### Get TurboNative Dependency

Alternatively to CocoaPods or Carpet? this is built into Xcode.  Similar to Gems.

* Open File Explorer

* Click on Project in File Explorer

  * Click Project (Not Target)

  * Package Dependencies

  * Click +

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mof2kfp0cq7ycfo49vsl.png)

 * Enter URL in top right Search Box

 * https://github.com/hotwired/turbo-ios

### Use TurboNative Package in Scene

Update SceneDelegate to use NavigationController and Introduce concept of pushViewController

```swift
private let navigationController = UINavigationController()

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    self.window = UIWindow(windowScene: windowScene)
    self.window?.rootViewController = navigationController
    self.window?.rootViewController?.view.backgroundColor = .orange
    self.window?.makeKeyAndVisible()

    visit()
}

private func visit() {
    let controller = UIViewController()
    controller.view.backgroundColor = .green
    navigationController.pushViewController(controller, animated: true)
}
```

Now instead of UIViewController, let's use Turbo's VisitableViewController

```swift
private func visit() {
    let url = URL(string: "http://localhost:3000")!
    let controller = VisitableViewController(url: url)
    navigationController.pushViewController(controller, animated: true)
}
```

But we also need Turbo's Session.  Next to the navigationController at top of file add:

```swift
private let session = Session()
```

And update func visit 

```swift
private func visit() {
    let url = URL(string: "http://localhost:3000")!
    let controller = VisibleViewController(url: url)
    session.visit(controller, .advance)
  navigationController.pushViewController(controller, animated: true)
}
```

## Activate Links

Update session

```swift
private lazy var session: Session = {
    let session = Session()
    session.delegate = self
    return session
}()
```

But that will warn, because `self` doesn't quack like a delegate.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zqwc1djp5zo3cqrnvnk8.png)

So we an use extensions to extend SceneDelegate.  For some reason, you gotta click fix twice.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hfl7fuj8gr2kldgd8vd1.png)

```swift
    func session(_ session: Turbo.Session, didProposeVisit proposal: Turbo.VisitProposal) {
        let controller = VisitableViewController(url: proposal.url)
        session.visit(controller, action: .advance)
        navigationController.pushViewController(controller, animated: true)
    }
```

## Remove WebView Elements Not Relevant to TurboNative

The strategy here is to let Rails know we are TurboNative app by setting the UserAgent Name.

```swift
private lazy var session: Session = {
    let configuration = WKWebViewConfiguration()
    configuration.applicationNameForUserAgent = "Turbo Native iOS"
    let session = Session()
    session.delegate = self
    return session
}()
```

In Rails app you can conditionally render content based on turbo_native_app?