はじめに
この記事はElixirアドベントカレンダー2025シリーズ2の8日目の記事です。
本記事はElixirDesktopのジェネレータDesktopSetupをアップデート内容とどうやったかについて解説します
ElixirDestopとは?
ElixirDesktopとはデスクトップ、iOS、Android上でPhoeni/Elixirを動かすライブラリ群です詳しくは1日目の記事を読んでください
DesktopSetupとは?
通常のPhoenixアプリをElixirDesktopを利用したコマンド一発でDesktopアプリ化、iOS、Androidアプリ化するジェネレータライブラリです
これを作った背景としてはElixirDesktopはWxWidgetでPhoenixを動かすライブラリで、そのままでは動かないので色々と手を加える必要があり、それも特にドキュメント化とかはされておらず以下のサンプルから読み取って自分で全部やる必要がありました
これが面倒かつ、古いErlangしか動かないなど色々問題があったので、ビルドスクリプトとかはあったので頑張って作りました
これで3つほどアプリをリリースする上で、色々知見が溜まってきたりとか不具合とかがちょくちょく出てきたのでそれを反映させた形になります
Elixr と Erlangのバージョンが上がりました!
最初にですが、ElixirとErlangのバージョンを上げました!
ElixirはErlangのバージョンがあってれば何でもいいのでお好きなものをどうぞという感じではありますが
コンパイルエラーと起動即クラッシュと戦いながらiOS,Androidで動くErlangを頑張ってビルドしました
- Erlang 26.2.5 -> 27.3.4
- Elixir 1.17.2-otp-26 -> 1.19.3-otp-27
モバイル用のSQLiteマイグレーション生成コマンドの実装
もともとSQLiteをDBに選択した場合、アプリ起動中に mix ecto.migrationなんて実行できないので、PhoenixのSupervisorが起動する前にマイグレーションを行う関数を入れるようにしていますが、 mix phx.gen.live等 で作成されたマイグレーションファイルを以下のように変更する必要がありました
- lib/migrations フォルダを作成
- マイグレーションファイルをコピーして拡張子を exsからexに変更する
- repoに以下のようなコードを追加する
def migration() do
Ecto.Migrator.up([your app module name].Repo, [timestamp from filename],[your app module name].Migrations.Create[table name])
end
そこまで面倒というわけではないですが、せっかくなので自動でやってくれるようにしようということで
上記の処理を自動化してくれるmixタスクを作成しました!
mix desktop.migrations.convert
mix phx.gen.live xx した後に実行すればアプリ起動時にマイグレーションしてくれます
Androidの不具合修正
Androidに関するいくつかの対応をしました
16kbページサイズ対応
16KBページサイズ対応の概要
- 義務化の背景:Android 15以降で、大容量RAMを搭載したデバイスのパフォーマンスを最適化するため、OSが管理するメモリのページサイズが従来の4KBから16KBに拡張されるためです。
- 対応が必須のアプリ:Android 15以降を対象とする、Google Playに提出されるすべての新規アプリと既存アプリのアップデートです。
- 影響:16KBページサイズに対応していないアプリは、今後のバージョンでクラッシュするリスクがあります
アプリ申請時になんかメモリのページサイズというものが16KBにしろということで、NDKを上げても解消しなかったのでErlangのビルドオプションを変更して16KBに対応したら問題なくなりました!
ファイルアップロード対応
iOSの方では問題なくファイルアップロードができていたのですが、Androidの方がうまく作動しなかったので対応しました!
これで両方のOSでinput type="file"が問題なく動くようになりました
アクションバーの削除
OS固有のアクションバーが表示されてPhoenixのヘッダー部分と競合していたので削除しました
Phoenix.LiveView.ColocatedJS対応
LiveView 1.1から入ったassetsにhooksファイルを作成せずに、同じLiveViewファイルにhooksを書いて参照できる機能ですが、こちらリリース時のmixタスクの順番を気をつけないとそんなファイル無いぞと怒られるので注意が必要です
Error
mix assets.deploy
mix release --overwrite
Success
mix release --overwrite
mix assets.deploy
mix releaseでColocatedJSのJS周りを先に処理する必要があるみたいですね
どうやってアップデートしたのか
そもそもElixirDesktopってのがiOSとAndroidで動くErlangをビルドして、アプリ起動時に起動させるというすっごいトリッキーなことやってるんですよね
それ用のビルドで使うdockerファイルがだいたいこんな感じです
FROM dockcross/android-<%= @arch.id %>
# ENV
ENV NDK_ROOT $CROSS_ROOT
ENV ANDROID_NDK_HOME $CROSS_ROOT
ENV NDK_ABI_PLAT <%= @arch.android_name %><%= @arch.abi %>
ENV PATH $NDK_ROOT/bin:$PATH
ENV FC= CPP= LD= CXX=clang++ CC=clang AR=ar
ENV MAKEFLAGS "-j10 -O"
# ---- 16KB page-size: global flags ------------------------------------------
ENV PAGE_LDFLAGS="-Wl,-z,max-page-size=16384"
ENV PAGE_CFLAGS="-D__BIONIC_NO_PAGE_SIZE_MACRO"
# Setting up openssl
COPY scripts/install_openssl.sh /work/
COPY patch /work/patch
# OpenSSL fails to detect this:
RUN cp ${NDK_ROOT}/bin/llvm-ar ${NDK_ROOT}/bin/<%= @arch.cpu %>-linux-<%= @arch.android_name %>-ar
RUN cp ${NDK_ROOT}/bin/llvm-ranlib ${NDK_ROOT}/bin/<%= @arch.cpu %>-linux-<%= @arch.android_name %>-ranlib
RUN ARCH="android-<%= @arch.id %>" \
CFLAGS="-D__ANDROID_API__=<%= @arch.abi %> -fPIC -Os ${PAGE_CFLAGS}" \
LDFLAGS="${PAGE_LDFLAGS}" \
./install_openssl.sh
# Fetching OTP
COPY _build/otp otp
ENV LIBS /usr/local/openssl/lib/libcrypto.a
# We need -z global for liberlang.so because:
# https://android-ndk.narkive.com/iNWj05IV/weak-symbol-linking-when-loading-dynamic-libraries
# https://android.googlesource.com/platform/bionic/+/30b17e32f0b403a97cef7c4d1fcab471fa316340/linker/linker_namespaces.cpp#100
ENV CFLAGS="-Os -fPIC ${PAGE_CFLAGS}" \
CXXFLAGS="-Os -fPIC ${PAGE_CFLAGS}" \
LDFLAGS="-z global ${PAGE_LDFLAGS}" \
CXX= \
CC=
# RUN env
WORKDIR /work/otp
# Build with debugger produces
# dbg_wx_filedialog_win.erl:22: behaviour wx_object undefined
# Build run #1, building the x86 based cross compiler which will generate the .beam files
<%
config = "--with-ssl=/usr/local/openssl/ --disable-dynamic-ssl-lib --without-javac --without-odbc --without-wx --without-debugger --without-observer --without-cdv --without-et --xcomp-conf=xcomp/erl-xcomp-#{@arch.id}-android.conf --disable-year2038"
%>
RUN ./otp_build setup <%= config %> || bash -c 'cat erts/config.log && exit 1'
RUN ./otp_build boot -a
# Build run #2, now creating the arm binaries, appliying the install flags only here...
ENV INSTALL_PROGRAM "/usr/bin/install -c -s --strip-program=llvm-strip"
RUN ./otp_build configure <%= config %> LDFLAGS="-z global"
RUN ./otp_build release -a
自分は一介のWeb系プログラマーでして、こういったディープなことはからきしです
なので全部ChatGPTに丸投げ!
iOSもAndroidの詳しくないことは丸投げ!
とりあえずビルドを実行して失敗すればエラー文丸ごとぶん投げて、リトライして、また失敗したらエラー文貼り付けてを延々と繰り返すことで無事アップデートできました
ほとんど誰もやってなさそうなことなのによく分かるなーと関心した限りです
最後に
自分ぐらいしか使ってなさそうなライブラリですが、ChatGPTとドメインを狭めてピンポイントできいていけば先駆者がいなさそうな領域でもしっかりと効果をだすのでLLMはすごいなーと思いました。
なので自分の知らない領域にどしどし挑戦して、溺れたらChatGPTにたくさん浮き輪を投げてしっかりと泳いでいきましょう!
本記事は以上になりますありがとうございました