SplashScreen API (androidx.core.splashscreen) を利用したスプラッシュ画面の実装を前提とします
Android 12 以降において startActivity() + Intent.FLAG_ACTIVITY_NEW_TASK
で Activity を新たに起動する場合、スプラッシュ画面のアイコンが表示されません。
before | after |
---|---|
TL;DR
Activity の起動方法によらず常にスプラッシュ画面でアイコンを表示させるには以下の対応が必要です。
Android 13 以降
themes で静的に指定できます
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- 対象のActivityに適用するテーマ -->
<style name="MySplash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
+ <item name="android:windowSplashScreenBehavior" tools:targetApi="33">icon_preferred</item>
</style>
</resources>
Android 12
Activityを起動するコードからオプション指定が必要です。ただし AndroidStudio から起動する場合にアイコンが表示されない問題は解決できません。
val intent = Intent(context, MyActivity::class.java)
- startActivity(intent)
+ if (Build.VERSION.SDK_INT in listOf(31, 32)) {
+ val options = bundleOf("android.activity.splashScreenStyle" to 1)
+ startActivity(intent, options)
+ } else {
+ startActivity(intent)
+ }
詳説
検証に使用したソースはこちら
AndroidX ライブラリ
Android 12 においてOS側のスプラッシュ画面の挙動が大幅に変更され、同時に従来のスプラッシュ画面をAndroid 12 以降も一貫的に実装できるライブラリが提供されました。 SplashScreen API の詳細はここでは割愛します。
Android 12 以降の問題
SplashScreen API によるスプラッシュ画面が表示されるのは、
- コールドスタート
(例) アプリが完全に終了している状態でランチャーアプリから起動したとき - ウォームスタート
(例) システムによりbackgroundのアプリが破棄された状態からforegroundに復帰したとき
一方で起動済み&表示中のアプリから新たにActivityを起動すると、Android 12 以降に限りスプラッシュ画面自体は表示されますがアイコンが表示されません。具体的には以下のようなコードが該当します。
fun onRestartClicked() {
val intent = Intent(context, MyActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
startActivity(intent)
}
windowSplashScreenBehavior属性
API 33 (Android 13) 以降でのみ使用できます
スプラッシュ画面を設定するthemes.xml
においてwindowSplashScreenBehavior
属性でアイコン表示有無を制御できます。Activityの起動方法によらず常に表示させるにはicon_preferred
を指定します。
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- MyActivityに適用するテーマ -->
<style name="MySplash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="android:windowSplashScreenBehavior">icon_preferred</item>
</style>
</resources>
コードから指定する場合は、
val intent = Intent(context, MyActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
- startActivity(intent)
+ if (Build.VERSION.SDK_INT >= 33) {
+ val options = ActivityOptions.makeBasic().apply {
+ splashScreenStyle = SplashScreen.SPLASH_SCREEN_STYLE_ICON
+ }.toBundle()
+ startActivity(intent, options)
+ } else {
+ startActivity(intent)
+ }
Android 12 対応
windowSplashScreenBehavior
属性はAndroid 13 で導入されたため、Android 12 では使用できません。スマートな方法が見つからず、みんな同じ問題で困っているようでした....
開発側の回答にて以下のようなワークアラウンドが提案されています。Bundle
だったら文字列でkeyを直接指定できるって発想ですね。
val intent = Intent(context, MyActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
+ if (Build.VERSION.SDK_INT in listOf(31, 32)) {
+ val options = bundleOf("android.activity.splashScreenStyle" to 1)
+ context.startActivity(intent, options)
} else if (Build.VERSION.SDK_INT >= 33) {
AndroidStudio から Run ボタンでアプリ起動する場合、Android 12 でアイコンが表示されない問題はこの方法でも回避できません。