はじめに
本記事は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を指定します
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
を使うようにします
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を作成します
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で管理するようにします
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で切り替えるようにします
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で読み込むファイルを切り替えるようにします
# 以下追加
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の設定を読み込む
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で使用する設定ファイルを作成
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にする必要があります
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をプロジェクトに合わせます
#!/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 に変更します
Android設定
AndroidStudioでandroidフォルダを開いたら
ビルドするJavaのバージョンが1.8とかになっていないかを確認します
run_mixを書き換えます
階層がiOSより深いので注意が必要です
#!/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
Desktop
MIX_TARGET=desktop iex -S mix
すべての環境で無事動きました!
最後に
まだハマリポイントが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
リポジトリ