はじめに
本記事はPhoenix LiveViewからHTMLではなく、
SwiftUIのレンダリングするLiveViewNativeSwiftUIの解説と
実際にPhoenixプロジェクトを作成してiOSアプリでHello Worldを表示するところまでを解説します
LiveViewNativeとは?
PhoenixではWebsocketを介してフロントエンドとバックエンド間の通信を行い、APIを作成せずにサーバーサイドの知識だけでSPAなページを作成できるLiveViewがありますが
それをiOS,Android,Unity,WinUi3等に対してもコネクションを貼ってLiveViewのプロトコルとDSLでかけるようにして覇権とろうぜ!というプロジェクトがLiveViewNativeになります
現在のバージョンは0.4.0-rcで
iOS SwiftUI,Android JetPack,Flutterなどのクライアントライブラリが作成されています
LiveViewNative.SwiftUIとは?
LiveViewNativeのプロジェクトのなかで一番活発に開発されているライブラリです
XCodeプロジェクトの雛形をxcogegenで生成するジェネレーターやチュートリアル、ドキュメントなど、開発を始めるにあたって必要なものが揃っています
- 基本コンポーネントは網羅
- 独自コンポーネントも実装可能
- コンポーネントの差分更新のパフォーマンスが0.2で大幅に改善
- avkit,photokit,mapkitなども順次ライブラリ化
作ってみる
基本こちらに沿って進めていきます
実行環境
以下の環境で実行しています
macOS Sonoma 14.6.1
CPU Apple M1
elixir 1.17.2-otp-26
erlang 26.2.5
phoenix 1.7.18
プロジェクトの生成
Phoenixが最新版でない方は以下のコマンドで更新しておきましょう
mix archive.install hex phx_new
最新版が入ったら以下のコマンドで通常のPhoenixプロジェクトを作成します
今回はデータベースを使わないので--no-ecto
オプションをつけて実行します
mix phx.new --no-ecto my_app
ライブラリの追加
ライブラリを追加していきます
2025/02/04現在phoenix_live_view 1.0.3
だとコンパイル時にエラーになるため1.0.1
で固定します
defp deps do
[
{:phoenix, "~> 1.7.18"},
{:phoenix_html, "~> 4.1"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
- {:phoenix_live_view, "~> 1.0.0"},
+ {:phoenix_live_view, "1.0.1"},
{:floki, ">= 0.30.0", only: :test},
...
{:bandit, "~> 1.5"},
+ {:live_view_native, "~> 0.4.0-rc.0"},
+ {:live_view_native_stylesheet, "~> 0.3.2"},
+ {:live_view_native_swiftui, "~> 0.4.0-rc.0"},
+ {:live_view_native_live_form, "~> 0.4.0-rc.0"}
]
end
セットアップ
コマンドが用意されているので以下を実行します
mix lvn.setup.config
書き換えの許可を求められるので全部yで書き換えていきます
Write to config/config.exs
(Y)es (n)o (d)iff
> y
Write to config/dev.exs
(Y)es (n)o (d)iff
> y
Write to lib/my_app_web/endpoint.ex
(Y)es (n)o (d)iff
> y
Write to lib/my_app_web/router.ex
(Y)es (n)o (d)iff
> y
終わったら次のコマンドを実行します
mix lvn.setup.gen
SwiftUI用のコアコンポーネントとXCodeプロジェクトを作ってくれます
Proceed with interactive overwrite? [Yn] y
* creating lib/my_app_native.ex
* creating lib/my_app_web/components/layouts.swiftui.ex
* creating lib/my_app_web/components/layouts_swiftui/app.swiftui.neex
* creating lib/my_app_web/components/layouts_swiftui/root.swiftui.neex
* creating lib/my_app_web/styles/app.swiftui.ex
* creating lib/my_app_web/components/core_components.swiftui.ex
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/1024-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/128-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/16-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/256-mac 1.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/256-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/32-mac 1.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/32-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/512-mac 1.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/512-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/64-mac.png
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/AppIcon 1.jpg
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/AppIcon.jpg
* creating native/swiftui/MyApp/Assets.xcassets/AppIcon.appiconset/Contents.json
* creating native/swiftui/MyApp/Assets.xcassets/Contents.json
* creating native/swiftui/MyApp/ConnectingView.swift
* creating native/swiftui/MyApp/ContentView.swift
* creating native/swiftui/MyApp/DisconnectedView.swift
* creating native/swiftui/MyApp/ErrorView.swift
* creating native/swiftui/MyApp/Preview Content/Preview Assets.xcassets/Contents.json
* creating native/swiftui/MyApp/ReconnectingView.swift
* creating native/swiftui/MyApp/MyApp.swift
* creating native/swiftui/base_spec.yml
* creating native/swiftui/project.yml
* creating native/swiftui/project_watchos.yml
⚙️ Generating plists...
⚙️ Generating project...
⚙️ Writing project...
Created project at /Users/shou/phoenix/elixir_mobile/my_app/native/swiftui/MyApp.xcodeproj
Now that your app is configured please follow these instructions for enabling a LiveView for LiveView Native
https://hexdocs.pm/live_view_native/0.4.0-rc.0/LiveViewNative.html#module-enabling-liveview-for-native
テンプレートファイルがheex
じゃなくてneex
という拡張子のようです
LiveViewページの作成
実際に表示するliveviewのページを作っていきます
通常のLiveViewとLiveViewNativeを切り替える起点のhome_live.exを作成します
ついでに render関数を追加して通常のブラウザでも表示できるようにします
defmodule MyAppWeb.HomeLive do
use MyAppWeb, :live_view
use MyAppNative, :live_view
def render(assigns) do
~H"""
<h1>Hellow Browser</h1>
"""
end
end
LiveViewNativeページの作成
swiftuiでのアクセスの場合はこちらが表示されます
render関数の第2引数はwatchOS,tvOSなど機種によって表示を変えることが可能です
defmodule MyAppWeb.HomeLive.SwiftUI do
use MyAppNative, [:render_component, format: :swiftui]
def render(assigns, _interface) do
~LVN"""
<VStack>
<Text>
Hello SwiftUI!
</Text>
</VStack>
"""
end
end
routerへの追加
routerへは、home_liveだけを表示するだけでアーキテクチャごとに表示するliveviewを切り替えてくれます
scope "/", MyAppWeb do
pipe_through :browser
- get "/", PageController, :home
+ live "/", HomeLive
end
準備ができたので以下のコマンドでphoenixサーバーを起動します
iex -S mix phx.server
XCodeの起動
my_app/native/swiftui
配下にファイルが作成されいるので以下のコマンドで開きます
open native/swiftui/MyApp.xcodeproj/
indexingにめっちゃ時間かかりますが気長に待ちましょう
ビルドしようとしてもエラーが残っていてできませんが、ライブラリを信用しますか?とでてるのでtrustを押しましょう
ビルドが完了したらiOSシミュレーターとブラウザも無事表示されました
最後に
フロント側はアーキテクチャ事に分ける必要はありますが
バックエンドとの通信をAPIを介することなく、表示のレイアウト以外を同じElixir/Phoenixでかける
ElixirDesktopと違って外部サーバーとの通信なので、AI/ML系のライブラリも制限なく使えるかと思います
気になった方はチュートリアルがこちらにあるのでぜひやってみてください
本記事は以上になりますありがとうございました
参考サイト
https://hexdocs.pm/live_view_native_swiftui/0.4.0-rc.0/readme.html
https://github.com/liveview-native/live_view_native
https://github.com/liveview-native/liveview-client-swiftui