
- はじめに
- ドコモから発売されている折りたたみスマホ
- 最初の課題:【Fold】アプリが起動できない
- 2番目の課題:【Flip】端末を回転・開閉するとアプリが表示できなくなる
- 3番目の課題:【Flip】再起動してほしくない画面でアプリが再起動する
- おわりに
はじめに
はじめまして、こんにちは。
NTTドコモ 第二プロダクトデザイン部の鈴木美帆です。
全くの未経験からコンシューマ向けのアプリ開発担当に配属され、早1年半。
何気なく使っていたアプリケーションの裏側は、こんなにも複雑だったのかと日々驚かされています。
そんな折、Androidの折りたたみスマホにアプリを対応させる担当になりました。
......次から次に出てくる課題。それらを解決した過程をしたためてみようと思います。
ドコモから発売されている折りたたみスマホ
近年種類が増えている折りたたみスマホ。
実は、ドコモからは5種類もの折りたたみスマホが発売されています。(2024年11月25日現在)
- Google Pixel 9 Pro Fold
- Galaxy Z Fold5 (SC-55D)
- Galaxy Z Fold6 (SC-55E)
- Galaxy Z Flip5 (SC-54D)
- Galaxy Z Flip6 (SC-54E)
折りたたみスマホは大きく「Fold」タイプと「Flip」タイプに分けられます。
Foldタイプは横開きにできる端末で、大きなディスプレイやマルチウィンドウを楽しめます。
Flipタイプは縦半分にできる端末で、端末を立てたりコンパクトに持ち運ぶことができます。
Flipタイプには、端末を折りたたんだ状態でも操作が可能なカバーディスプレイがあります。

FoldタイプとFlipタイプ、それぞれで課題が発生していました。具体的に見ていきましょう。
最初の課題:【Fold】アプリが起動できない
Foldタイプの端末を開いた状態でアプリを起動しようとするとクラッシュするという事象が発生しました。
解析した結果、アプリのマニフェストファイル(AndroidManifest.xml)の設定が不十分だと判明。
AndroidManifest.xmlはアプリ作成において必須のファイルで、様々な情報を定義しています。*1 *2
詳細を説明してしまうと記事が書き終わらなくなってしまうので省きますが、
このAndroidManifest.xmlの中に画面の設定を宣言する箇所があるのです。
ちなみに、Androidアプリ開発では画面のことをActivityと呼びます。*3
担当アプリのActivityの設定は以下でした。
これは該当Activityの向きを宣言するもので、"portrait"は縦方向に固定する設定です。
端末を縦向きで使用する前提でアプリが構成されているので、以下設定となっていました。
android:screenOrientation="portrait"
しかし、縦固定の設定を入れているにもかかわらず、起動時に画面が回転する処理が走っていたのです。
アプリを縦固定にしているのにどうして回転してしまうんだ!?という疑問は一旦置いておいて......*4
画面の回転を想定していないため、回転したときの動きをハンドリングしていませんでした。
そのためシステムの挙動に従って、自動的にActivityが破棄されてしまっていました。
Activityが破棄されている間でも、裏の処理は実行されます。
裏で走っている処理がActivityを参照したいのに、Activityが無い!という状態に陥り、
結果としてアプリがクラッシュしていたのです。

Activityの自動再生成を防ぐため、以下を追加しました。
android:configChanges="fontScale|screenSize|locale|orientation"
"orientation"を入れることで、画面が回転したタイミングで以下が呼ばれます。*5
onConfigurationChanged()
これによりActivityを破棄することなく、処理を進めることができるのです。*6 *7 *8
これでクラッシュせずにアプリを立ち上げられるぞ〜!

2番目の課題:【Flip】端末を回転・開閉するとアプリが表示できなくなる
アプリが立ち上げられるようになったと思いきや、早速2つ目の課題に阻まれました。
Flipタイプの端末では、端末設定からカバーディスプレイの画面回転をONにできます。
カバーディスプレイの画面回転をONにして端末を回転させると、アプリが閉じてしまいました。
アプリを縦固定にしているのにどうして回転してしまうんだ!?という疑問はまたまた一旦置いておいて......*9
端末回転だけでなく、端末を開閉した時にも同様の事象が発生すると判明。
折りたためることが特徴のスマホでそれはまずい!ということで解析しました。
結果、最初の課題で追加したonConfigurationChanged()
メソッドが原因と分かりました。
onConfigurationChanged()
が呼び出された際、
android:configChanges
に設定している構成タイプ(fontScale[フォントサイズ]など)の値が
前回と変わっていた場合に、Activityを全て破棄する処理が実装されていたのです。
通常、Android端末では、
android:configChanges
に設定している構成タイプの変更は設定アプリを開いて行います。
たとえばアプリの文字が小さくて見づらいので、設定アプリでフォントサイズを大きくしたとします。
せっかく変更したのですから、アプリに戻った時にも変更後のフォントサイズで画面を表示したいですよね。
そのため設定アプリから戻ってくる時に再起動処理を入れActivityを再生成していました。
画面回転・端末開閉もフォントサイズと同じくandroid:configChanges
に設定されている構成タイプです。
そのためフォントサイズと同じように、
設定アプリから戻ってくる時に再起動処理を入れActivityを再生成したいのですが、
カバーディスプレイで端末回転・端末開閉をする場合は設定アプリを開きません。
そのため再起動処理が入るタイミングがなく、
Activityもないのでアプリで表示できるものがありません!という状態になっていたのでした。

ということで、onConfigurationChanged()
が呼ばれた際は再起動する処理を明示的に追加しました。
これで無事にアプリを使うことができる!はず!!!

3番目の課題:【Flip】再起動してほしくない画面でアプリが再起動する
喜びも束の間、重大な問題を見落としていました。
なんと弊アプリ、端末を傾けて使用する画面があるのです。
2番目の課題で、端末を回転させた時には再起動をする処理を追加しました。
つまり、端末を傾けるとその度にアプリが再起動してしまいます。
さすがに使い勝手が悪すぎるので、解決方法を模索していきました。
端末メーカーさんとも相談し、結果としてActivityに<meta-data>
を追加することになりました。
<meta-data>
とは、独自の情報を設定できる箱のようなものです。*10
名前も、中に入れる値も、自由に決めることができます。
端末メーカーさん側で定義している<meta-data>
をアプリに設定すると、
<meta-data>
で定義された制御を端末がアプリに対して実行してくれます。
上記を使用して、端末設定で回転が許容されていたとしてもアプリが回転しないよう制御を入れました。

おわりに
なんだかんだあり、無事に皆様にもお使いいただける形まで持っていくことができました。
ここには記載していない大小さまざまな問題もありましたが、なんとかものになって良かったです。
今後の展望としては、アプリのつくりを根本から見直すことも視野に入れる必要があります。
そうすることで、これから発売される未来の折りたたみスマホでも弊アプリを簡単に使えるでしょう。
すでに多くのサイトで解説されていることではありますが、
一連の流れがわかりやすくなるよう執筆しました。
この記事が少しでも誰かのお役に立てれば嬉しいです!
最後までお読みいただきありがとうございました!
*1:アプリの基礎 | Android Developers
*2:AndroidManifest.xml の備忘録 #Android - Qiita
*3:【Androidアプリ開発】ActivityとViewの基礎 #初心者 - Qiita
*4:アプリを縦固定にしているにも関わらず、端末を開いたときに画面が回転してしまった理由については、
端末を開いたときの縦横比が同じだったことが関係しているのではと考えられます。
*5:その他の値についてはこちらで補足します。
fontScale:フォントサイズの変更
screenSize:画面サイズの変更
locale:言語の変更
上記が変更されたときも、onConfigurationChanged() メソッドが呼ばれます。
詳細は*7のリンク先をご確認ください。
*6:構成の変更に対処する | App architecture | Android Developers
*7:android:configChanges | Android Developers
*8:【Android】画面回転した時に処理を入れたい【Kotlin】 #Android - Qiita
*9:アプリを縦固定にしているにも関わらず、カバーディスプレイで画面が回転してしまった理由は、
おそらく端末固有の仕様によるものだと思われます。