🤖

【Flutter】Android12~とそれ以前でスプラッシュを出し分ける

2021/12/20に公開

Androidの実装経験のない自分が、Flutter製の個人アプリで掲題の対応をしたときに結構詰まったので、記事にまとめました。

前提

Flutter Engineの初期化前にネイティブのスプラッシュが表示されます。そこはネイティブの領域なので、ネイティブ側で編集する必要があります。
公式ドキュメント

Android版のスプラッシュ実装

AndroidはAndroid11以前と12以降で挙動が全く違います。

  • ~Android11は、コードなりxmlをいじって自前でスプラッシュ画面を実装する必要あり
  • Android12~は、android側で自動でスプラッシュ画面が表示されます

そのため自前でスプラッシュ実装をしている場合、Android12でスプラッシュが2重に出てしまいます。

スプラッシュの実装を消して、~Android11はスプラッシュを表示しない実装でも良いですが、Flutter Engineの初期化までをシームレスに繋げたいためスプラッシュは実装したい。
そうなるとスプラッシュの出し分けが必要になってきます。

Android12~とそれ以前でスプラッシュを出し分ける方法

Androidはバージョン指定のテーマを作成でき、下記のようにテーマを出し分けることができます。
公式ドキュメント

res/values/styles.xml        # themes for all versions
res/values-v31/styles.xml    # themes for API level 31+ only

この場合、全てのバージョンでstyles.xmlのテーマが反映され、API level 31~ (Android12~)はvalues-v31/styles.xmlのテーマが反映されます。
これを使ってスプラッシュの出しわけをします。(スタイルを継承することも可能。詳しくはドキュメント参照)

Flutterのプロジェクトを作ると自動で最低限必要なスタイルの指定がres/values/styles.xmlに指定されており、AndroidManifest.xmlで参照するところまで準備できているので、これを出し分けます。

<!-- AndroidManifest.xml -->
<activity
    android:name=".MainActivity"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme"

~Android11の場合

自前のスプラッシュを表示

res/values/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- アプリ起動時のテーマ -->
    <!-- @drawable/splashに作った自前のスプラッシュを指定 -->
    <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar.Fullscreen">
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
    <!-- Flutter UI初期化まで表示されるテーマ -->
    <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>

Android12~の場合

スプラッシュの背景色などの指定をする

Themeの指定で、背景色, 真ん中に表示されるアイコン, スプラッシュが表示されるduration程度なら指定できます。スプラッシュ表示自体をOFFにすることはできないようです。
公式ドキュメント

res/values-v31/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- アプリ起動時のテーマ -->
    <!-- スプラッシュの背景色などを指定 -->
    <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowFullscreen">false</item>
        <item name="android:windowSplashScreenBackground">@color/launch_background</item>
    </style>
    <!-- Flutter UI初期化まで表示されるテーマ -->
    <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>

完成

~Android11

Android12~

【Flutter2.5~】io.flutter.embedding.android.SplashScreenDrawableはDeprecatedになった

スプラッシュが表示されて、FlutterのFrameが初期化されるまでの間を描画するためにio.flutter.embedding.android.SplashScreenDrawable の指定がAndroidManifest.xmlにプリセットされていますが、Flutter2.5からは自動でAndroidの起動画面をキープしてくれるようになったので、削除して問題ないです。
Migrating from Manifest / Activity defined custom splash screens

余談

flutter_native_splashというスプラッシュのネイティブ実装をジェネレートしてくれる便利パッケージも存在しますが、あまり依存するパッケージを増やしたくなく、弊アプリでは自前で実装しました。
(実装は大いに参考にしました。:pray:)

Discussion