LiveViewNative × SwiftUI で 外部API呼び出し実装

# 概要

本記事は、以前公開した以下の記事の続きとなります。

https://qiita.com/B_tanuki/items/7e53cd63bd9ce7cbae55

今回は、LiveViewNativeを使って、**ページ上の要素からElixirの処理を実行する実装例**について紹介します。

LiveViewNativeでは、SwiftUIでViewを作成する代わりに、<font color="red">外部のPhoenix LiveViewサーバーから**neex**を取得し、それをSwiftUIのViewに変換して表示</font>します。

そのため、画面上の処理などは**すべてElixir側で実装する**ことになります。
Elixir側の処理は基本的に通常のLiveViewと同じ要領で記述できるため、比較的簡単に実装できます。

記事中のコードは公開しているリポジトリから抜粋して掲載しています。
記事を読み進める際は、併せてリポジトリを参照いただくことをおすすめします。

公開しているリポジトリでは、以下のAPIを利用しています

https://weather.tsukumijima.net/

# リポジトリ

https://github.com/BlackTanuTanuNinjas/tutorial_lvn_swiftui_interaction

# 環境

開発環境については、前回の記事と同じ構成です。詳細は以下をご参照ください。

https://qiita.com/B_tanuki/items/7e53cd63bd9ce7cbae55#%E7%92%B0%E5%A2%83

# 手順

基本的には、前回の記事で作成した [swiftuiモジュール](https://qiita.com/B_tanuki/items/7e53cd63bd9ce7cbae55#swiftui%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)、[neex](https://qiita.com/B_tanuki/items/7e53cd63bd9ce7cbae55#neex%E3%81%AB%E5%86%85%E5%AE%B9%E3%82%92%E8%A8%98%E8%BF%B0)、[LiveViewモジュール](https://qiita.com/B_tanuki/items/7e53cd63bd9ce7cbae55#swiftui%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)をベースに作業を進めます。

今回は、ボタンを押した時にElixirの処理を実行し、結果を画面に表示する実装を行います

1. [neex内のButton要素に`phx-click`を追加](#neex内のbutton要素にphx-clickを追加)  
2. [LiveViewモジュールに`handle_event/3`を実装](#liveviewモジュールにhandle_event3を実装)  
3. [neex内に状態を表示](#neex内に状態を表示)

## neexファイル内のButton要素に`phx-click`を追加

heexと同様に、`phx-click`を使用します。

次のように`Button`に`phx-click`を記述して、送信するイベントを定義できます

```heex:lib/tutorial_lvn_swiftui_interaction_web/live/swiftui/elixir_actions_live.swiftui.neex
    <Button
    style="buttonStyle(.borderedProminent); controlSize(.large); cornerRadius(12.0)"
    phx-click="get_weather"
    >
        天気を取得
    </Button>
```

上記は、get_weatherというイベントを送信する例です。

## LiveViewモジュールに`handle_event/3`を実装

neex内で送信したイベントの処理は、heexと同様にLiveViewモジュール内で記述します。

以下の`handle_event`は、`get_weather`イベントの処理です。

```elixir:lib/tutorial_lvn_swiftui_interaction_web/live/elixir_actions_live.ex
  use TutorialLvnSwiftuiInteractionNative, :live_view
  
  def handle_event("get_weather", _params, socket) do
    case Tsukumijima.get_weather() do
      {:ok, weather_text} ->
        {:noreply,
         socket
         |> assign(:status, :ok)
         |> assign(:weather_text, weather_text)}

      {:error, message} ->
        {:noreply,
         socket
         |> assign(:status, :error)
         |> assign(:weather_text, message)}
    end
  end
```

## neex内に状態を表示

LiveViewの状態は、neex上でもheexと同様に表示できます。

以下は、`weather_text`の値を画面に表示する記述です。

```heex:lib/tutorial_lvn_swiftui_interaction_web/live/swiftui/elixir_actions_live.swiftui.neex
    <Text style="font(.caption)"><%= @weather_text %></Text>
```

# 動作確認

公開しているリポジトリの内容を実行すると、次のような動作になります。

![Simulator Screen Recording - iPhone 16 - 2025-04-15 at 10.23.59.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455723/63a77750-5395-4eb2-91f8-990ba4b2bd30.gif)

`天気を取得`ボタンを押すことで、天気予報を取得するAPIが呼び出され、画面上にその結果が表示されました

# まとめ

今回はLiveViewNativeで外部APIを実行してみる実装を行いました。

応用するなら、Pigeonを使ってサーバーからAPNs通知を送信し、クライアント側でそれを受信してネイティブ機能を呼び出す、といった実装も考えられます。 
ただ現時点では、そういった機能をどのように活用すれば有用なのか、具体的なアイデアはあまり浮かんでいません。

今後、SwiftUIを学習しながら、色々アイデアを増やしていきたいです。

現時点で不安なのは、LiveViewNativeの仕組み上、**クライアント側の画面操作からOSの機能を直接呼び出せない点**です。
そのため、そういった処理をどう実現するかが課題になりそうです。

先ほど挙げたように、APNs通知をうまく活用すれば、ある程度のことは実現できそうですが、他にも有効な方法がないか、今後も調査していきたいです。