ElixirDesktopを動かすiOS Projectを０から作成する

# はじめに
この記事は Elixirアドベントカレンダーのシリーズ４の5日目の記事です

ElixirDekstopのiOSアプリを以下を参考にXCodeでプロジェクトを作るところから初めて
実際に起動するまで行います

https://github.com/elixir-desktop/ios-example-app


# フォルダ構成

別のネイティブアプリを作るライブラリにLiveViewNativeというものがあり、そのサンプルアプリのフォルダ構成が、 `app_name/native/[ios or android pj]`となっていたのでそちらを踏襲します

https://github.com/liveview-native/elixirconf_chat

```
mkdir native
```

# XcodeからiOSプロジェクトを作る
Xcodeを開き、新規プロジェクトを作成していきます

iOS Appを選択してNextをクリックします
![スクリーンショット 2023-11-30 16.35.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/fbac8d2e-eea5-5e98-a5c2-adeaf81ff2eb.png)

アプリ名を入力して nextをクリック

![スクリーンショット 2023-11-30 16.36.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/9bf7baf2-0aa1-507f-9eef-51212fc91a59.png)

作成先を先ほど作成した `native`の下に指定して Createをクリック

![スクリーンショット 2023-11-30 16.36.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/49430b82-e783-85b1-b4df-c341108bd8ef.png)

作成したら
`native/bookshelf/bookshelf`となっているので
`native/ios/bookshelf`とリネームしましょう

このときXcodeからRe Saveしますか？ときかれるのでキャンセルしてください


# iOSサンプルアプリからファイルをコピー
サンプルアプリをXcodeで開き、以下のファイルをコピーしていきます

サンプルアプリ側の
- ZIPFoundation -> zipファイルを操作するライブラリ
- liberlang -> クロスコンパイルしたErlang実行バイナリ
- native-lib.cpp -> liberlangを起動するスクリプト
- native-lib.hpp -> 上記のヘッダーファイル
を選択してドラッグアンドドロップでコピーします

![スクリーンショット 2023-11-30 16.53.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/320df6dd-72cf-81d4-d69c-6669e42f0779.png)

グループかリファレンスかとターゲットをきかれるので変更はせずにFinishをクリック

![スクリーンショット 2023-11-30 16.53.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/21a87bc1-e2e6-b928-5169-12a1832be25d.png)

次にBridge-Headerを作るかを訊かれるので Createをクリック

完了すると以下のようになります

![スクリーンショット 2023-11-30 16.53.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/6228e040-0ab3-b85a-2461-8080e605ec72.png)



# ヘッダーファイルの修正
Header.hファイルにnative-libのヘッダーファイルを読み込む設定を追加します

```bash:native/ios/bookshelf-Bridging-Header.h
#import "native-lib.hpp"
```

# ライブラリ設定

VSCodeからCartfileのファイルを作成し、以下を追加します

```bash:native/ios/Cartfile
github "weichsel/ZIPFoundation" ~> 0.9
```

iosのフォルダに移動し以下を実行します

```
cd native/ios
carthage update --use-xcframeworks
```

インストールが完了したらXcodeでアプリの設定画面の`General`タブを表示し、`Frameworks`の項目の`liberlang`と`ZIPFoundation`の`Embed`の項目を`Embed & Sign`にします

![スクリーンショット 2023-09-27 13.49.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/878613a4-2857-fec7-7ab5-43e747e9796e.png)

# WebViewアプリケーションと、ブリッジの作成

`TodoApp.swift`のstructの内容をコピーします

```native/ios/bookshelf/bookshelfApp.swift
import SwiftUI

@main
struct bookshelfApp: App {
    @Environment(\.scenePhase) var scenePhase
    
    var content = ContentView()
    var body: some Scene {
        WindowGroup {
            self.content
        }
        .onChange(of: scenePhase) { phase in
            switch phase {
            case .background:
                print(".background")
            case .active:
                print(".active")
                if let bridge = Bridge.instance {
                    bridge.reinit()
                }
            default: break
            }
        }
    }
}
```

アプリ起動時に`conent`を表示し、アプリがバックグラウンドになったらログを出力し、バックグラウンドからアクティブになったらPhoenixアプリケーションとのブリッジを再度作成します

もとからある ContentView.swiftを削除し、サンプルアプリから以下のファイルをドラッグアンドドロップでコピーします

- ContentView.swift　-> アプリの画面でセーフエリアとWebviewを表示
- WebViewController.swift -> WebViewの初期化処理と画面更新時の処理
- WebView.swift -> 表示するWebviewの設定
- Bridge.swift -> Erlangの起動と接続処理

# ビルドスクリプト作成

run_mixをVSCode経由でコピーしビルドスクリプトをPhoenix Projectに合わせて編集します


```diff_shell:native/ios/run_mix
#!/bin/bash
set -e

# Setting up the PATH environment
[ -s /opt/homebrew/bin/brew ] && eval $(/opt/homebrew/bin/brew shellenv)
[ -s /usr/local/bin/brew ] && eval $(/usr/local/bin/brew shellenv)

# This loads nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  

# This loads asdf
if [ -s "$HOMEBREW_PREFIX/opt/asdf/libexec/asdf.sh" ]; then 
  \. "$HOMEBREW_PREFIX/opt/asdf/libexec/asdf.sh" 
elif [ -s "$HOME/.asdf/asdf.sh" ]; then
  \. "$HOME/.asdf/asdf.sh"
fi

BASE=`pwd`
export MIX_ENV=prod
export MIX_TARGET=ios

mix local.hex --force --if-missing
mix local.rebar --force --if-missing

- if [ ! -d "elixir-app" ]; then
- git clone https://github.com/elixir-desktop/desktop-example-app.git elixir-app
- fi

- # using the right runtime versions
- if [ ! -f "elixir/.tool-versions" ]; then
-  cp .tool-versions elixir-app/
- fi

- cd elixir-app
+ # Phoenix PJまでのパスに変更 
+ cd ../../

if [ ! -d "deps/desktop" ]; then
  mix deps.get
fi

# tailwindのみの場合コメントアウト
# if [ ! -d "assets/node_modules" ]; then
#  cd assets && npm i && cd ..
# fi

- if [ -f "$BASE/todoapp/app.zip" ]; then
-  rm "$BASE/todoapp/app.zip"
- fi
+ # xcodeで作成したプロジェクト名に変更
+ if [ -f "$BASE/bookshelf/app.zip" ]; then
+  rm "$BASE/bookshelf/app.zip"
+ fi

mix assets.deploy && \
  mix release --overwrite && \
-  cd _build/ios_prod/rel/todo_app && \
-  zip -9r "$BASE/todoapp/app.zip" lib/ releases/ --exclude "*.so"
+  cd _build/ios_prod/rel/bookshelf && \
+  zip -9r "$BASE/bookshelf/app.zip" lib/ releases/ --exclude "*.so"  

```


# ビルド実行
ErlangとElixirのバージョンを以下のコマンドで切り替えます

```
asdf global erlang 25.0.4
asdf global elixir 1.15.7-otp-25
```

iosのフォルダに移動して`run_mix`を実行します

```
cd native/ios/
./run_mix
```

ビルドが正常に完了したら、`bookshelf`フォルダに`app.zip`を追加します

![スクリーンショット 2023-12-01 1.38.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/5e2f58b0-8882-8526-20bd-1baa9c4a874f.png)

![スクリーンショット 2023-12-01 1.38.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/7c9efb56-75be-1c18-3b68-d5c6aa66ad79.png)

ファイルを追加したらXcodeの実行ボタンをクリックすると以下のように表示されます

![スクリーンショット 2023-12-01 1.41.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/13ec2023-9a62-8309-0062-24bc2ff6b076.png)

# 最後に
Xcodeでプロジェクトを作るところから実際にElixirDesktopが動くところまでを実装しました
ファイルをXcode経由でコピーしたりといろいろ面倒なので、LiveViewNativeみたいに自動化されないかなーとは思っています

次はAndroidプロジェクトを作成していきます

本記事は以上になります、ありがとうございました