19
10

More than 1 year has passed since last update.

ElixirDesktopとPhoenixを同一のProjectで開発する際の構成

Last updated at Posted at 2022-08-30

はじめに

本記事はElixirDesktopとPhoenixを1つのPhoenixプロジェクトとして開発する際に
どのような構成にすると良いか模索した備忘録になります

環境構築

asdf でできるようになりましたので、以下の手順で該当のElixirとErlangをインストールしておいてください

構成

色々模索した結果以下の構成にしてMIX_TARGETで読み込む設定ファイルを切り替えるのがお手軽でよさそうでした
top project
└ Phoenix -> スマホ、Web共通のコード
└ Andoroid -> ビルド+WebView設定
└ iOS -> ビルド+WebView設定

UmbrellaでWebはWeb,スマホはスマホでプロジェクトを分けてDB部分を分けてビルド時に必要なものだけを読み込むでも良いですが、Umbrella自体があまり情報が多くないのとソースコード管理や、phx.gen周りが面倒なので、途中で断念しました。

Umbrellaに関してはこちらが参考になるかもしれません

プロジェクトの作成

早速作成していきます、今回は行きたい場所を管理するアプリを作成していてそちらの作り直しの過程をサンプルとして実装していきます

mkdir trarecord_project
cd trarecord_project
git init
mix phx.new trarecord
cd trarecord
mix ecto.create

Desktopを組み込む

基本こちらに沿って作成していきます

ライブラリの追加

mix targetでdesktop,ios,androidを指定したときだけ追加するように targetsを指定します

mix.exs
defmodule Trarecord.MixProject do
  ...
  defp deps do
    [
       ...
      {:desktop, "~> 1.4", targets: [:android, :ios, :desktop]},
      {:wx, "~> 1.0.10", hex: :bridge, targets: [:android, :ios]}
    ]
  end
...
end

Applicationファイルを作成

Application起動時に行うことを記述するdesktop用のファイルを作成します
phoenixはapplication.ex
desktopはtrarecord.ex
を使うようにします

trarecord/lib/trarecord.ex
defmodule Trarecord do
  @app Mix.Project.config()[:app]
  def start(:normal, []) do
    {:ok, sup} = Supervisor.start_link([Trarecord.Repo], name: __MODULE__, strategy: :one_for_one)
    {:ok, _} = Supervisor.start_child(sup, TrarecordWeb.DesktopSup)

    {:ok, _} =
      Supervisor.start_child(sup, {
        Desktop.Window,
        [
          app: @app,
          id: TrerecordWindow,
          title: "TrerecordApp",
          size: {600, 500},
          url: &TrarecordWeb.Endpoint.url/0
        ]
      })
  end
end

session,pubsub周りのsuperviserを記述する desktop_sup.exを作成します

trarecord/lib/trarecord_web/desktop_sup.ex
defmodule TrarecordWeb.DesktopSup do
  use Supervisor

  @moduledoc """
    Supervisor for the WebApp
  """

  def start_link([]) do
    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init([]) do
    children = [
      {Phoenix.PubSub, name: Trarecord.PubSub},
      TrarecordWeb.Endpoint
    ]

    :session = :ets.new(:session, [:named_table, :public, read_concurrency: true])
    Supervisor.init(children, strategy: :one_for_one, max_restarts: 1000)
  end
end

Desktop用のEndpointファイルを作成します、同じファイル名を使用して MIX_TARGETで切り替えたいので、実行するdefmoduleをif文で分けます
Dektopの方は記事にあるようにendpointをPhoenixのからDesktopのものに変えて、sessionをetsで管理するようにします

trarecord/lib/trarecord_web/endpoint.ex
if Mix.target() in [:desktop, :android, :ios] do
  defmodule TrarecordWeb.Endpoint do
    use Desktop.Endpoint, otp_app: :trarecord

    @session_options [
      store: :ets,
      key: "_trarecord_key",
      table: :session
    ]
  # 以下endpoint.exのコピー
  end
else
  # もとのendpoint.exをコピー
end

applicationファイルができたのでmix.exsでtargetで切り替えるようにします

mix.exs
defmodule Trarecord.MixProject do
  use Mix.Project
  ...
  def application do
    application(Mix.target())
  end

  def application(target) when target in [:android, :ios, :desktop] do
    [
      mod: {Trarecord, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  def application(_) do
    [
      mod: {Trarecord.Application, []},
      extra_applications: [:logger, :runtime_tools]
    ]
  end

  ...
end

configの切り替え

こちらもtargetで切り替えるようにしていきます

endpointの設定を削除してtargetで読み込むファイルを切り替えるようにします

trarecord/config/config.exs

# 以下追加
if Mix.target() in [:desktop, :android, :ios] do
  import_config "desktop.exs"
else
  import_config "web.exs"  
end

import_config "#{config_env()}.exs"

desktop用のEndtpointの設定を読み込む

trarecord/config/desktop.exs
import Config

# Configures the endpoint
config :trarecord, TrarecordWeb.Endpoint,
  http: [ip: {127, 0, 0, 1}, port: 0], # desktop全体で設定
  render_errors: [view: TrarecordWeb.ErrorView, accepts: ~w(html json), layout: false],
  pubsub_server: Trarecord.PubSub, # すべての環境で行うなら Redisにしたほうが良い
  live_view: [signing_salt: "nt9pr/6W"],
  secret_key_base: "cVZaz98CBZNGr4dk7XhVqYpW49We6OKdzORLS20peE0ZK8Qv3ex6uOLujx/mXS80",
  server: true # server trueを設定

PhoenixのEdnpointで使用する設定ファイルを作成

trarecord/config/web.exs
import Config

if config_env() == :dev do
  config :trarecord, TrarecordWeb.Endpoint,
    # Binding to loopback ipv4 address prevents access from other machines.
    # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
    http: [ip: {127, 0, 0, 1}, port: 4000]
end

releaseビルドするのでprodにローカル環境のiOS,AndroidからPostgreSQLに接続する情報をいれます

iosはloopbackアドレスで行けましたが、Androidは10.0.2.2にする必要があります

trarecord/config/prod.exs
import Config

if Mix.target() == :ios do
    username: "postgres",
    password: "postgres",
    hostname: "127.0.0.1",
    database: "trarecord_dev",
    stacktrace: true,
    show_sensitive_data_on_connection_error: true,
    pool_size: 10
end

if Mix.target() == :android do
  config :trarecord, Trarecord.Repo,
    username: "postgres",
    password: "postgres",
    hostname: "10.0.2.2",
    database: "trarecord_dev",
    stacktrace: true,
    show_sensitive_data_on_connection_error: true,
    pool_size: 10
end

runtime.exsがあるとエラーになるのは変わっていないようなのでとりあえずファイル名を変えておきます
Phonixをデプロイする時は runtime.exsに戻す運用にしましょう
runtime.exs -> runtime_disable.exs

各OSビルド用のプロジェクトフォルダを作成する

ios-example-appとandroid-example-appをクローンしてきます

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

iOS 設定

最初にreadmeにあるように関連ライブラリをインストールします

cd ios
carthage update --use-xcframeworks

ビルドスクリプトのrun_mixをプロジェクトに合わせます

ios/run_mix
#!/bin/bash
set -e

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

# desktop-example-appは使わないので削除
- 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 ../trarecord # projectパスを変更
fi

cd ../trarecord 

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

# npmをまだ使用していないのでコメントアウト
# 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

mix assets.deploy && \
  mix release --overwrite && \
  cd _build/ios_prod/rel/trarecord && \ # ここのパスの変更を忘れないように
  zip -9r "$BASE/todoapp/app.zip" lib/ releases/ --exclude "*.so"

todoapp.xcodeprojをダブルクリックしてxcodeを開いて
各種ライブラリが埋め込まれていないので Embed & Sign に変更します
スクリーンショット 2022-08-31 0.54.24.png

Android設定

AndroidStudioでandroidフォルダを開いたら
ビルドするJavaのバージョンが1.8とかになっていないかを確認します

run_mixを書き換えます
階層がiOSより深いので注意が必要です

android/app/run_mix
#!/bin/bash
set -e

BASE=`pwd`
APP_FILE="$BASE/src/main/assets/app.zip"
export MIX_ENV=prod
export MIX_TARGET=android

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

cd ../../trarecord

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

#if [ ! -d "assets/node_modules" ]; then
#  cd assets && npm i && cd ..
#fi

if [ -f "$APP_FILE" ]; then
  rm "$APP_FILE"
fi

mix assets.deploy && \
  mix release --overwrite && \
  cd "_build/${MIX_TARGET}_${MIX_ENV}/rel/trarecord" && \ # ここの変更を忘れないこと
  zip -9r "$APP_FILE" lib/ releases/ --exclude "*.so"

動作確認

Web
MIX_TARGET=host iex -S mix phx.server
スクリーンショット 2022-08-31 1.10.02.png

Desktop
MIX_TARGET=desktop iex -S mix
スクリーンショット 2022-08-31 1.12.09.png

iOS
スクリーンショット 2022-08-31 1.40.01.png

Android
スクリーンショット 2022-08-31 1.39.28.png

すべての環境で無事動きました!

最後に

まだハマリポイントが1つずつ残っていますが、バージョンアップでREADMEに従えばスマホのビルドができるようになりました
次は Tailwind,DaisyUI, 実際にDBを使う辺りをやってみたいと思います

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

参考サイト

https://github.com/elixir-desktop/desktop
https://github.com/elixir-desktop/ios-example-app
https://github.com/elixir-desktop/android-example-app
https://qiita.com/the_haigo/items/0fd907d24fdde1905aa2
https://github.com/dashbitco/bytepack_archive
https://dev.to/gumi/mix-otp-07-1p5k
https://elixirschool.com/ja/lessons/advanced/umbrella_projects
https://araramistudio.jimdo.com/2018/01/11/android%E3%81%AE%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%E3%83%BC%E3%81%8B%E3%82%89%E8%87%AA%E8%BA%AB%E3%81%AEpc-localhost-%E3%81%B8%E6%8E%A5%E7%B6%9A/
https://qiita.com/takahirom/items/5e8d7b69e873edb3dcaf

リポジトリ

19
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
10