Create a SwiftUI Application

Mix.install(
  [
    {:kino_live_view_native, github: "liveview-native/kino_live_view_native"}
  ],
  config: [
    live_view_native: [plugins: [LiveViewNativeSwiftUi]]
  ]
)

KinoLiveViewNative.start([])

Overview

For most projects, it's simpler to use the mix lvn.install command as described in the Installation Guide in an existing Phoenix project to create a new IOS application and configure the Phoenix project for LiveView Native.

However, we're going to walk through the steps of manually setting up an Xcode IOS project to better understand how the IOS side of a LiveView Native application works.

In future lessons, we'll use this IOS application to view IOS examples in the Xcode simulator (or a physical device if you prefer.)

Prerequisites

First, make sure you have followed the Getting Started guide. Then evaluate the smart cell below and visit http://localhost:4000 to ensure the Phoenix server is running properly. You should see the text Hello from LiveView!

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule MyApp.HomeLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{platform_id: :swiftui} = assigns) do
    ~SWIFTUI"""
    <Text>
      Hello again from LiveView Native!
    </Text>
    """
  end

  def render(assigns) do
    ~H"""
    <div>Hello from LiveView!</div>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
:ok

Create the IOS Application

Open XCode and select Create New Project new project.

XCode Create New Project

Select the iOS and App options to create an iOS application. Then click Next.

Xcode Create Template For New Project

Choose options for your new project that match the following image then click Next.

  • Product Name: The name of the application. This can be any valid name. We've chosen Guides.
  • Organization Identifier: A reverse DNS string that uniquely identifies your organization. If you don't have a company identifier, Apple recomends using com.example.your_name where your_name is your organization or personal name.
  • Interface:: Xcode generates an interface file that includes all your source code's internal and public declarations when using the Assistant editor, the Related Items, or the Navigate menu. Select SwiftUI since we're building a SwiftUI application.
  • Language: Determines which language Xcode should use for the project. Select Swift.

Including Tests is optional, but it's enabled by default so we've left the setting as-is.

Xcode Choose Options For Your New Project

Select an appropriate folder location where you would like to store the iOS project, then click Create.

Add the LiveView Client SwiftUI Package

To add the liveview-client-swiftui package to the iOS application, select File -> Add Package Dependencies. Then, search for liveview-client-swiftui. Once you have selected the package, click Add Package.

Choose the Package Products for liveview-client-swiftui. Select the iOS application we've already built for the LiveViewNative target.

If the following prompt appears, select Trust & Enable All to enable the liveview-client-swiftui package we just added.

Setup the LiveSessionCoordinator and SwiftUI LiveView

The ContentView contains the main view of our iOS application. We need to establish a connection between the SwiftUI application and the Phoenix application in this file.

Replace the code in the ContentView file with the following.

import SwiftUI
import LiveViewNative

struct ContentView: View {
    @StateObject private var coordinator = LiveSessionCoordinator(
        {
            let prodURL = Bundle.main.object(forInfoDictionaryKey: "Phoenix Production URL") as? String

            #if DEBUG
            return URL(string: "http://localhost:4000")!
            #else
            return URL(string: URL || "https://example.com")!
            #endif
        }(),
        config: LiveSessionConfiguration(navigationMode: .replaceOnly)
    )
    
    var body: some View {
        LiveView(session: coordinator)
    }
}

The code above sets up a LiveSessionCoordinator which is session coordinator object that handles the initial connection and navigation on the iOS app. We also create a SwiftUI LiveView, which is the SwiftUI root view for a Phoenix LiveView.

The SwiftUI LiveView uses the LiveSessionCoordinator and our SwiftUI application connects to the Phoenix application on a given URL. By default, the iOS application connects to a Phoenix application on http://localhost:4000.

graph LR;
  subgraph I[iOS App]
   direction TB
   ContentView
   SL[SwiftUI LiveView]
   SC[LiveSessionCoordinator]
  end
  subgraph P[Phoenix App]
    LiveView
  end
  I --> P
  ContentView --> SL
     ContentView --> SC

  

To avoid any potential confusion with the step above, here's how our ContentView should look in Xcode.

Start the Active Scheme

Click the start active scheme button <i class="ri-play-fill"></i> to build the project and run it on the iOS simulator.

A build scheme contains a list of targets to build, and any configuration and environment details that affect the selected action. For example, when you build and run an app, the scheme tells Xcode what launch arguments to pass to the app.

You may encounter an issue with LiveViewNativeMacros. If you do, click on the error in the error panel as seen in the image below and you should see the following prompt. Select Trust & Enable to resolve the issue.

The iOS Xcode simulator should start. If at this point you get a No Connection error, make sure you have followed the Prerequisites steps at the beginning of this guide.

After you start the active scheme, the simulator should open the iOS application and display Hello from LiveView Native!.

Live Reloading

LiveView Native implements live reloading whenever changes are made to the Phoenix application.

Run the following smart cell and you should see the Xcode simulator update automatically to display Hello again from LiveView Native!

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule MyApp.HomeLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{platform_id: :swiftui} = assigns) do
    ~SWIFTUI"""
    <Text>
      Hello again from LiveView Native!
    </Text>
    """
  end

  def render(assigns) do
    ~H"""
    <div>Hello again from LiveView!</div>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
:ok

Troubleshooting

If you encountered any issues with the native application, here are some common troubleshooting steps you can use:

  • Reset Package Caches: In the Xcode application go to File -> Packages -> Reset Package Caches.
  • Update Packages: In the Xcode application go to File -> Packages -> Update to Latest Package Versions.
  • Rebuild the Active Scheme: In the Xcode application, press the start active scheme button <i class="ri-play-fill"></i> to rebuild the active scheme and run it on the Xcode simulator.
  • Update your XCode version if it is not already the latest version
  • Ensure that the Livebook smart cells in this Notebook evaluate with :ok.

You can also raise an issue if you would like support from the LiveView Native team.