雰囲気でLaunchScreenをやっていた
はじめに
「LunchScreen? アプリ起動するときにロゴとか出てるあの画面でしょ?」
そのくらいの認識で、UIKitならLaunchScreen.storyboardでちょっと弄れるくらいは知っていたが、それほどちゃんと向き合ったことはなかった。
LaunchScreenについて
まず、LaunchScreenとMainWidowは別物。(これを混同していて悩んだ)
LaunchScreenは起動画面(オレンジ)であり、MainWindowは起動後に最初に表示される画面(グレー)のことだ。
HIGによると、AppleにおいてはSplashScreenは推奨されず、あくまでLaunchScreenはLaunchScreenで、SplashScreenは存在しない。
詳しくはHIGを読むと良いが、知らなかったポイントとしては以下の2点があった。
- ブランディングやオンボーディングをするところではない
- アプリが一瞬で立ち上がっているように見せるのが大事
起動画面でロゴをアニメーションしてるのカッコいい〜と思っていたが、あれ良くなかったんだ...。
ちなみに、Android(MD2)ではブランディングもしよーぜ!と言っている。
ふぅ〜ん?
とりあえずLaunchScreenがどういうものなのかは分かったので、裏側を見ていく。
Development
アプリの起動時に何が起こっているのか
LaunchScreenが表示されている間、以下のAppDelegateのメソッドが実行されている。
application(_:willFinishLaunchingWithOptions:)
application(_:didFinishLaunchingWithOptions:)
上記のドキュメント About the app launch sequence の図がとてもわかりやすい。↓
この Launch time に LaunchScreen が表示されているようだ。
さらに、iOS13以降ではSceneDelegateが登場し、MainWindowが表示されるまでの間にもう少しステップが追加されている。
登場以前はAppDelegateの application(_:willFinishLaunchingWithOptions:)
のタイミングでMainWindowに使うViewControllerの生成と指定を行っていたようだが、登場以降はSceneDelegateの scene(_:willConnectTo:options:)
で行うようになった。
SceneDelegate登場後の起動シーケンスについては以下の神記事がわかりやすかった。
なぜMainWindowに言及しているのかというと、擬似SplashScreenを作って起動時にあれこれ処理を行う場合があるからだ。
(ネットでSplashScreenの設定方法を調べていると、MainWindowに擬似SplashScreenを設定することとLaunchScreenを設定することが同列に書かれていることがままあり、混乱した)
コードだけで画面を作りたかったり、まぁ何か様々な事情でただのLaunchScreenだけでは足りないことがある時(HIG違反だがオンボしたかったりとか)に擬似SplashScreenを作る。
擬似SplashScreenは通常のViewControllerと同じように画面を作り、行いたい処理が終わったら次の画面に遷移するViewControllerをMainWindowに設定すれば良い。ここの詳細については割愛する。
AppDelegateとSceneDelegate合わせたらだいたいこんな感じだと思う。
LauchScreenの設定方法
LaunchScreenの設定方法は以下の2種類ある
- 画像や背景色をInfo.plistで指定する
- storyboardで画面を作る
画像や背景色をInfo.plistで指定する
UILaunchScreen
キーを使うと、storyboardを使わずにLaunchScreenを構成できる。
-
Launch Screen
-
Background color
: 背景色 -
Image Name
: 画像 -
Image respects safe area insets
: SafeAreaに収めるか -
Show Navigation bar
: ナビゲーションバーを表示するか -
Show Tab bar
: タブバーを表示するか -
Show Toolbar
: ツールバーを表示するか
-
HIGで言及されていたように、起動時に表示する画面のハリボテになるように作るのが望ましいので、バーの表示の設定などがある。
このキーを作るだけ作って何も設定しないこともできる。その場合は、OSのAppearance依存の背景色が適用された真っ白/真っ黒な画面がLaunchScreenとなる。
storyboardでLaunchScreenを構成する
新規プロジェクトをstoryboardで作った時は初期ファイルにあるLaunchScreen.storyboardを編集する。
自分で作る場合は、任意のstoryboardを作ったあと、Info.plistの Launch screen interface file base name
キーにstoryboardの名前を指定する。
このキーに存在しないstoryboardを指定しても動くが、その場合は真っ黒な画面がLaunchScreenとなる。(OSのAppearanceに依存しているわけでもなさそうなので、謎だ)
Info.plistにLaunchScreen系の設定は必ず追加する
Info.pilstに Launch Screen
も Launch screen interface file base name
も設定しなかった場合、アプリ全体の画面サイズが壊れる。
以下のオレンジの部分がアプリ全体の背景色だ。崩れている...。
SwiftUIで新規プロジェクトを作成すると、初期値として何も設定されていない Launch Screen
がある。
特に何も設定する必要がないときは↑のようにしておくと良いだろう。
MainWindowの設定方法(=擬似SplashScreenの設定方法)
MainWindowの設定はInfo.plistの SceneConfiguration
の Window Application Session Role
から行える。
MainWindowがstoryboardの場合は Storyboard Name
キーに指定する。
storyboardを使わずにコードでViewControllerを作成する場合は、 SceneConfiguration
から Storyboard Name
を削除し、SceneDelegateの scene(_:willConnectTo:options:)
にて生成・Windowへの設定を行う。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: scene)
let splashVC = SplashViewController()
window.rootViewController = splashVC
self.window = window
window.makeKeyAndVisible()
}
// ...
MainWindowの設定は Targets > Info > Custom iOS Target Properties にも同様のキーで存在しているので、storyboardを消す際はこちらの設定からも削除する。
SwiftUIの場合
SwiftUIの場合、 @main
がついているところのトップにあるViewがMainWindowに相当する。
擬似SplashScreenを作りたい場合、ここにViewを置き、処理が終わったら本来の画面に自動遷移するようにすると良いだろう。
import SwiftUI
@main
struct testApp: App {
var body: some Scene {
WindowGroup {
// ここ
SplashView()
}
}
}
おわりに
自分の中では消化できたと思ったが、文章にまとめてみると概念の違いがちゃんと伝わるのか不安になってきた。
LaunchScreenとSplashScreenとMainWindowと擬似SplashScreenの違いが伝わっていることを祈る。
Discussion