こんにちは!
プログラミング未経験文系出身、Elixirの国に迷い込んだ?!見習いアルケミストのaliceと申します。
今回はElixirDesktop + Phoenix1.7のスマホアプリをWindows11 + WSL2で動かす手順をまとめたいと思います。
なお、本記事は2023/7/13開催ElixirMobile#3:DBも内蔵したElixirDesktopスマホアプリ開発ハンズオンのイベントレポート(前半)を兼ねています。
------ハンズオンの様子(前半)はこちらから------
↓ ~27:03までが本記事のハンズオン動画です。
■「ElixirDesktopでスマホアプリを作る」シリーズの目次
①Windows11+WSL2に環境構築
|> ②Phoenix1.7のアプリを起動
|> ③LiveViewを使用してCRUDの機能を実装する
|> ④Android実機に転送する(Google Drive経由)
目的
こちらの記事をWindows11 + WSL2の環境で動かします。
実行環境
Windows 11 + WSL2 + Ubuntu 22.04
Elixir v1.14.3
Erlang v25.0.4
Phoenix v1.7.3
前提条件
Elixirのインストール
以下のいずれかが未実施の場合は前回の記事を参照して環境構築を行ってください。
- Android Studioのインストール
- NDK(※Native Development Kitの略、Android で C や C++ のコードを使用できるようにするツールセット)のインストール
- git、npm、asdf のインストール
- asdfを使用してのErlangおよびElixirのインストールと設定(※バージョン指定があります)1
Phoenixのインストール
最新のPhoenixをインストールします。
(私は既にインストール済のためスキップしました)
mix archive.install hex phx_new
SQLite3のインストール
apt経由でSQLite3をインストールします。2
sudo apt install sqlite3
プロジェクトの作成
DBはsqlite3を使うので --database sqlite3のオプションをつけます。
また、Phoenixのプロジェクトとandroid-studioのプロジェクトの2つが必要なので、両方のプロジェクトをいれるディレクトリを作成します。
mkdir todo_root
cd todo_root
mix phx.new todo_app --database sqlite3
cd todo_app
mix ecto.create #todo_app_dev.dbが作成される
ライブラリの追加
defp deps do
[
...
+ {:exqlite, github: "elixir-desktop/exqlite", override: true},
+ {:desktop, "~> 1.5"},
+ {:wx, "~> 1.1", hex: :bridge, targets: [:android, :ios]}
]
end
- exqliteとは、ElixirDesktopからSqlite3を操作するライブラリ
- desktopとは、ElixirDesktopフレームワーク本体
- wxとは、ElixirDesktopをスマートフォン上で動かすためのライブラリ
追加後、以下を実行します。
mix deps.get
config修正
config :todo_app, TodoAppWeb.Endpoint,
- url: [host: "localhost"],
+ http: [ip: {127, 0, 0, 1}, port: 10_000 + :rand.uniform(45_000)],
render_errors: [
formats: [html: TodoAppWeb.ErrorHTML, json: TodoAppWeb.ErrorJSON],
layout: false
],
pubsub_server: TodoApp.PubSub,
- live_view: [signing_salt: "J82JhPeQ"]
+ live_view: [signing_salt: "J82JhPeQ"],
+ secret_key_base: :crypto.strong_rand_bytes(32),
+ server: true
※signing_saltの値は人によって異なります。
- secret_key_baseとは、secureな文字列を作る際のベースになるもの。
- server: trueとは、アプリケーションが起動しているサーバーのIPアドレス + ポート番号への外部からのアクセスを受け付けられるようになる設定。3
runtime.exsの無効化
アプリの実行時にtodo_app/config/runtime.exs
があるとエラーになるそうです。
よって、runtime_disable.exs
にリネームしておきます。
Endpoint設定
EndpointのモジュールをPhoenixからDesktopに変更します。
ElixirDesktopではcookieでのセッション管理を使えないのでetsに変更します。
defmodule TodoAppWeb.Endpoint do
- use Phoenix.Endpoint, otp_app: :todo_app
+ use Desktop.Endpoint, otp_app: :todo_app
@session_options [
- store: :cookie,
+ store: :ets,
key: "_todo_app_key",
- signing_salt: "GvxD48aX",
- same_site: "Lax"
+ table: :session
]
アプリケーション起動時の設定
todo_app.ex
にどのような手順でPhoenixアプリケーションを起動していくかの設定をします。
todo_app.ex
にはデフォルトではドキュメントしか書かれていないので、以下を追加します。
defmodule TodoApp do
+ use Application
+ def config_dir() do
+ Path.join([Desktop.OS.home(), ".config", "todo_app"])
+ end
+ @app Mix.Project.config()[:app]
+ def start(:normal, []) do
+ # ~/.config/todo_appフォルダを作成する。その中に設定ファイルを放り込んでいく
+ File.mkdir_p!(config_dir())
+ # DBの場所を指定
+ Application.put_env(:todo_app, TodoApp.Repo,
+ database: Path.join(config_dir(), "/database.sq3")
+ )
+ # session用のETS(インメモリDB)を起動
+ :session = :ets.new(:session, [:named_table, :public, read_concurrency: true])
+ children = [
+ TodoApp.Repo,
+ {Phoenix.PubSub, name: TodoApp.PubSub},
+ TodoAppWeb.Endpoint
+ ]
+ opts = [strategy: :one_for_one, name: TodoApp.Supervisor]
+ # Phoenixのsuperviserをメインとして起動
+ {:ok, sup} = Supervisor.start_link(children, opts)
+ # DBの初期化とマイグレーション実行
+ TodoApp.Repo.initialize()
+ # phoenixサーバーが起動中のポート番号を取得
+ port = :ranch.get_port(TodoAppWeb.Endpoint.HTTP)
+ # ElixirDesktopのsuperviserを子プロセスとして起動
+ {:ok, _} =
+ Supervisor.start_child(sup, {
+ Desktop.Window,
+ [
+ app: @app,
+ id: TodoAppWindow,
+ title: "TodoApp",
+ size: {400, 800},
+ url: "http://localhost:#{port}"
+ ]
+ })
+ end
+ def config_change(changed, _new, removed) do
+ TodoAppWeb.Endpoint.config_change(changed, removed)
+ :ok
+ end
end
-
Desktop.OS.home()
はユーザーのホームディレクトリを返す関数4 - superviserとは、アプリが落ちたときに自動的にプロセスキルして再起動してくれるもの。堅牢なシステムを作る際に有用。
repo.exの変更
todo_app.ex
から呼び出される関数の設定をします。
(ひとまず空の関数を置いておきます)
defmodule TodoApp.Repo do
...
+ def initialize() do
+ end
end
mix.exsの変更
mix.exs
で呼び出される起動時の設定を変更します。
# アプリケーション起動時の設定 で設定したtodo_app.ex
に差し替えます。
def application do
[
- mod: {TodoApp.Application, []},
+ mod: {TodoApp, []},
extra_applications: [:logger, :runtime_tools]
]
end
以上がPhonenixプロジェクトの設定です。
androidでの起動
android-example-appのリポジトリをクローン
cd ..
git clone git@github.com:elixir-desktop/android-example-app.git
run_mixの変更
run_mix5内で今回使用しないスクリプトをコメントアウトします。
使用するプロジェクトを先ほど作成したtodo_appに切り替えます。
#!/bin/bash
set -e
BASE=`pwd`
APP_FILE="$BASE/src/main/assets/app.zip"
export MIX_ENV=prod
export MIX_TARGET=android
- 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-app/.tool-versions" ]; then
- cp .tool-versions elixir-app/
- fi
- cd elixir-app
+ cd ../../todo_app
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/todo_app" && \
zip -9r "$APP_FILE" lib/ releases/ --exclude "*.so"
run_mixの実行
先にrun_mixを単体で走らせて、リリースビルドを作成しておきます。
./run_mix
run_mixをブランクにする
run_mixをそのままにしてAndroid StudioのRunボタン(Android Studioの画面右上にある、緑色の▷ボタン)を押すと、再びビルドが走ってしまいます。
現時点ではrun_mixを実行済みでリリースビルドが出来上がり済のため、run_mixはもう使用しません。
よって、run_mixは別名でバックアップとして取っておき、run_mixそのものはブランクにします。
cp run_mix run_mix_build
Android StudioでRunする
Android Studioを起動します。
~/android-studio/bin/studio.sh
run_mixとrun_mix_buildがあることを確認してファイルを開きます。
Android Studioの画面右上にある、緑色の▷ボタンがRunボタンです。
これを押下すると、先ほど作成したリリースビルドを読み込んで、エミュレータ上でアプリが起動します。
run_mixがブランクになっていることを確認して、Runボタンを押下します。
次の記事へ
~Elixirの国のご案内~
↓Elixirって何ぞや?と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます
↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ!私もエンジニア未経験から学習中です。
↓We Are The Alchemists, my friends!6
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。7
-
2023/7/12時点ではErlang26系では動かなかったとのことです。https://qiita.com/the_haigo/items/17a89b5038a7f337b102#elixir%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB ↩
-
sqlite3の導入。参考にさせていただきました。 https://qiita.com/t-yamanashi/items/ef4c5bcab4a130105760 ↩
-
外部とはローカルホスト(同一マシン)以外を指す。 ↩
-
https://github.com/elixir-desktop/desktop/blob/5927dc42d97305c43cad523b905153b687434219/lib/desktop/os.ex#L21 ↩
-
run_mixとは
ダウンロードしたリポジトリ内のrun_mixはビルドスクリプトといって、
1.GitHubからexampleをcloneしてくる
2.ライブラリのインストール等を行う
3.リリース(prod環境ビルド)に必要な処理を行う
4.Zipで圧縮
5.Android側が読み込むようにしてある場所にコピー
以上の処理をまとめて走らせてくれるシェルスクリプトのこと。
https://qiita.com/Alicesky2127/items/5f9a1c6496b1c083720f#run_mix%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B
※なお、今回は1.についてはコメントアウトして実施しないようにしている。 ↩ -
@torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。 ↩