はじめに
Androidアプリ開発グループの深沢です。
今回、ビルド環境によってflac拡張ライブラリがうまく作成できないことがありましたので、環境に依存しないようCIで作成するようにした話を紹介したいと思います。
ExoPlayerとハイレゾ楽曲
私の携わっているアプリではハイレゾ楽曲再生に対応しています。ハイレゾ楽曲にはWAVやFLACなどいくつかの形式があるのですが、このアプリではFLACをサポートしています。ExoPlayerでFLAC楽曲を再生できるようにするには、FLACをデコードするための拡張ライブラリが必要で、これはExoPlayerのバージョン毎に更新する必要があります。作成手順など詳しくはこちらをご確認ください。
起きたこと
先日targetSDKを34に上げる対応をしたところ、楽曲が再生されなくなってしまいました。調べてみると、現行アプリのExoPlayerバージョンでは PlayerNotificationManager#registerReceiver()が使用されており、これがAPI34では対応されていなかったためということがわかりました。ExoPlayerのバージョンを最新のものに変更すると PlayerNotificationManager#registerReceiver()が使用されていないことがわかったので、ExoPlayerのバージョンアップを行いました。このことに伴って、拡張ライブラリの作り直しが必要になり、私は拡張ライブラリをローカルで作成しました。aarファイルは出力され、アプリに組み込むことはできたのですが、FLAC音源がXperia/Android9などの特定端末では再生できないという事象が起きました。
原因究明
コードを確認すると、Playerをセットするときに
FlacLibrary.isAvailable()というメソッドがfalseで返っていました。これはFlacLibraryが機能していないことを意味しており、FLAC対応のハードウェアデコーダーが入っていない機種では再生ができなくなっていました。
先ほどデコードするための拡張ライブラリが必要と書きましたが、一部端末ではライブラリを使用しなくても端末内のハードウェアデコーダーがFLAC楽曲を再生できるようにデコードしてくれるので、ハイレゾ楽曲が問題なく再生できました。そのため、不具合の発見が遅れてしまったので、ExoPlayerを使用するときは
FlacLibrary.isAvailable()を用いて確認するようにしましょう…
ちなみに、デバイスに搭載されているハードウェアデコーダーを調べる方法もあるようです。参考
原因特定のため色々試して拡張ライブラリを作成してみたところ、javaバージョンなどの環境が違う状態で拡張ライブラリを作成すると、 FlacLibrary.isAvailable()がtrueで返ってきていることがわかりました。このライブラリを使用すると、Xperiaでもハイレゾ楽曲が再生できたため、今回の事象の要因はビルド環境であることがわかりました。
そこで、今回はGitHubActionsを用いてビルド環境を統一し、誰でも機能するflac拡張ライブラリが作成できるようにしました。
拡張ライブラリ自動作成方法
- .github/workflows内にymlファイルを作成します。
- ワークフロー名などを設定します。
name: Make Flac Library run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 # トリガーは自由に設定してください。 on: workflow_dispatch: jobs: Make-flac-library: runs-on: ubuntu-latest |
- Android NDKをダウンロードして、 android-ndk-r21eのパスを変数化します。ubuntuを使用しているので、linux版でダウンロードしてください。
- name: Download and set up Android NDK run: | echo "Downloading Android NDK" wget https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64zip unzip android-ndk-r21e-linux-x86_64.zip -d $HOME echo "NDK_PATH=$HOME/android-ndk-r21e" >> $GITHUB_ENV echo "NDK set up at $NDK_PATH" |
- ExoPlayerの特定のバージョンをクローンし、チェックアウトします。
まず、GitHubリポジトリのSettings>Secrets and variables>Actions>Variablesタブに移動します。そこでNew Repository variablesボタンを押下してください。そうしたら、変数が設定できますので、Name:EXOPLAYER_VERSION, Value:任意のExoPlayerバージョン(今回はr2.19.1)を入力して、Add variableボタンを押下してください。これにより、ExoPlayerのバージョンを設定することができました。バージョンを変更したいときは、同じ場所から編集ができます。
次に、ymlファイルに以下のようにクローン&チェックアウトするようステップを追加します。
ExoPlayer/と
ExoPlayer/extension/flac/src/main/をそれぞれ変数化します。
- name: Set Flac Module Path run: | echo "Cloning ExoPlayer repository" git clone https://github.com/google/ExoPlayer.git cd ExoPlayer git checkout tags/${{ vars.EXOPLAYER_VERSION }} echo FLAC_MODULE_PATH=$(pwd)/extensions/flac/src/main >> $GITHUB_ENV echo EXOPLAYER=$(pwd) >> $GITHUB_ENV echo "FLAC_MODULE_PATH set to $FLAC_MODULE_PATH" |
- 続いて、 ExoPlayer/local.propertiesを作成し、sdkのパスを記載します。
- name: Create local.properties run: | echo "sdk.dir=/usr/lib/android-sdk" > $EXOPLAYER/local.properties echo "local.properties file created at $EXOPLAYER/local.properties" cat $EXOPLAYER/local.properties |
- flacライブラリのダウンロードを行い、 flac/に移動させます。
- name: Download and extract Flac Library run: | cd "${FLAC_MODULE_PATH}/jni" curl https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.2.tar.xz | tar xJ mv flac-1.3.2 flac echo "Flac Library download and extracted" |
- Android.mkにコンパイルフラグを追加します。
- name: Update Android.mk run: | cd "${FLAC_MODULE_PATH}/jni" echo "LOCAL_CPPFLAGS := -std=c++11" >> Android.mk echo "Added LOCAL_CPPFLAGS to Android.mk" cat $FLAC_MODULE_PATH/jni/Android.mk |
- ndk-buildスクリプトを作成します。
- name: Create ndk-build run: | echo '#!/bin/sh' > ${NDK_PATH}/ndk-build.sh echo 'DIR="$(cd "$(dirname "$0")" && pwd)"' >> ${NDK_PATH}/ndk-build.sh echo 'arch -x86_64 /bin/bash $DIR/build/ndk-build "$@"' >> ${NDK_PATHndk-build.sh echo "ndk-build script created" |
- ndk-buildを実行して、JNIライブラリを作成します。
- name: Build JNI Library run: | cd "${FLAC_MODULE_PATH}/jni" $NDK_PATH/ndk-build APP_ABI=all -j4 echo "JNI Library build" |
- gradlewを実行します。これで ${{ env.EXOPLAYER }}/extensions/flac/buildout/outputs/aar/にaarファイルが作成されます。
- name: Build extension-flac run: | cd "${EXOPLAYER}" ./gradlew :extension-flac:assembleRelease echo "extension-flac assembled" |
- 作成されたaarファイルをGitHubからダウンロードできるようにします。
- name: Upload AAR file uses: actions/upload-artifact@v2 with: name: extension-flac-aar path: ${{ env.EXOPLAYER }}/extensions/flac/buildout/outputs/aar/extension-flac-release.aar |
いざ実行
これで、ワークフローは完成です。実際に実行してみます。
実行が成功すると、ログの下でaarファイルがダウンロードできるようになります。
このファイルをアプリに組み込んで、実際にFLAC楽曲を再生してみます。
以前作成した拡張ライブラリ使用時
今回作成した拡張ライブラリ使用時
以前作成した拡張ライブラリを使用すると、再生しようとしてもできなかったのですが、今回作成したものを使用したところ、無事Xperia/Android9でも再生することができました。
コードを確認すると、 FlacLibrary.isAvailable()がtrueになっており、無事flac拡張ライブラリが機能していることがわかりました。
以下、ymlファイルの全体です。説明としては省きましたが、変数確認ステップなど確認のため記載していたものも載せています。
name: Make Flac Library run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 # トリガー on: workflow_dispatch: jobs: Make-flac-library: runs-on: ubuntu-latest steps: # Android NDKをダウンロード - name: Download and set up Android NDK # Ubuntuを使用しているのでlinuxを使用 run: | echo "Downloading Android NDK" wget https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip unzip android-ndk-r21e-linux-x86_64.zip -d $HOME echo "NDK_PATH=$HOME/android-ndk-r21e" >> $GITHUB_ENV echo "NDK set up at $NDK_PATH" # ExoPlayerの特定バージョンをクローン&チェックアウト - name: Set Flac Module Path run: | echo "Cloning ExoPlayer repository" git clone https://github.com/google/ExoPlayer.git cd ExoPlayer git checkout tags/${{ vars.EXOPLAYER_VERSION }} echo FLAC_MODULE_PATH=$(pwd)/extensions/flac/src/main >> $GITHUB_ENV echo EXOPLAYER=$(pwd) >> $GITHUB_ENV echo "FLAC_MODULE_PATH set to $FLAC_MODULE_PATH" # 環境変数の確認 - name: Verify Environment Variables run: | echo "Verifying Environment Variables" echo "FLAC_MODULE_PATH is: $FLAC_MODULE_PATH" echo "EXOPLAYER is: $EXOPLAYER" echo "NDK_PATH is: $NDK_PATH" # local.propertiesにsdkのパスを記載 - name: Create local.properties run: | echo "sdk.dir=/usr/lib/android-sdk" > $EXOPLAYER/local.properties echo "local.properties file created at $EXOPLAYER/local.properties" cat $EXOPLAYER/local.properties # Flacライブラリのダウンロードと解凍 - name: Download and extract Flac Library run: | cd "${FLAC_MODULE_PATH}/jni" curl https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.2.tar.xz | tar xJ mv flac-1.3.2 flac echo "Flac Library download and extracted" # Android.mkにフラグを追加 - name: Update Android.mk run: | cd "${FLAC_MODULE_PATH}/jni" echo "LOCAL_CPPFLAGS := -std=c++11" >> Android.mk echo "Added LOCAL_CPPFLAGS to Android.mk" cat $FLAC_MODULE_PATH/jni/Android.mk # ndk-buildを作成 - name: Create ndk-build run: | echo '#!/bin/sh' > ${NDK_PATH}/ndk-build.sh echo 'DIR="$(cd "$(dirname "$0")" && pwd)"' >> ${NDK_PATH}/ndk-build.sh echo 'arch -x86_64 /bin/bash $DIR/build/ndk-build "$@"' >> ${NDK_PATH}/ndk-build.sh echo "ndk-build script created" # JNIライブラリを構築 - name: Build JNI Library run: | cd "${FLAC_MODULE_PATH}/jni" $NDK_PATH/ndk-build APP_ABI=all -j4 echo "JNI Library build" # gradlew実行 - name: Build extension-flac run: | cd "${EXOPLAYER}" ./gradlew :extension-flac:assembleRelease -Pandroid.useAndroidX=true -Pandroid.enableJetifier=true echo "extension-flac assembled" # ファイルを表示 - name: List build outputs run: | echo "Listing build outputs" ls -a $EXOPLAYER/extensions/flac/buildout/outputs/aar # aarファイルをダウンロード - name: Upload AAR file uses: actions/upload-artifact@v2 with: name: extension-flac-aar path: ${{ env.EXOPLAYER }}/extensions/flac/buildout/outputs/aar/extension-flac-release.aar |
flac拡張ライブラリを作成するときは是非参考にしてみてください。