Web開発しかしてこなかったエンジニアがはじめてネイティブアプリを開発して慄いたこと
この記事はスターフェスティバル Advent Calendar 2021の15日目です。
こんにちは、スターフェスティバル株式会社 ソフトウェアエンジニアのYoshifujiです。今年のアドベントカレンダーとしては3度目の登場となります。2度目の記事でははじめてネイティブアプリを開発してリリースした話を書きましたが、今回はネイティブアプリ開発で慄いたことについてに書きたいと思います。
日常生活で慄く場面はそう滅多にないと思いますが、これまでWeb開発しかしてこなかった私にとって、初めてのネイティブアプリ開発は慄きの連続でした。今回はその慄きの一部と、私がどのようにして落ち着きを取り戻したのかをご紹介します。
Push通知が怖い
Push通知はご存知の通り、ユーザーの端末に対し直接送信できるメッセージです。ユーザーがアプリを開いていなくてもリアルタイムで届けたい情報を送ることができるため、ネイティブアプリを開発するなら是非とも備えたい機能のひとつです。
弊社で開発しているネイティブアプリでは、FCM(Firebase Cloud Messaging)を使ってPush通知を配信しています。
FCMはGoogleが無料で提供しているクロスプラットフォームに対応した通知サービスです。アプリをインストールした端末からSDKを使ってデバイストークンを取得し、それを指定することでFCMでデバイストークンに対応づけられている端末宛にPush通知を配信できる、という仕組みです。
仕組みは理解できたし、DBにデバイストークンを保存していく設計も実装もできたところで、いざ送信!とやってみても、すぐには思うように送信できませんでした。
些事ではありますが、この辺りでつまづきました。
- iOSだと、諸々の設定が必要。
- XCodeのSigning & Capability設定
- APNs用の証明書の作成・設定
- Android8+だと、サイレント通知になってしまう。
- 通知チャンネルを設定する必要がある。
そして一番悩んだのが、FCMが発行するデバイストークンの有効期限についてでした。
SDKを使って取得するデバイストークンですが、ドキュメントによると定期的にリフレッシュされるとのことでした。
予定していた通知が送れないとなると、ビジネスに大きな影響が出てしまいます。これは把握しておかないと非常にまずい...と思い、Firebaseのドキュメントを探すと、こうした記述がありました。
The registration token may change when:
- The app is restored on a new device
- The user uninstalls/reinstall the app
- The user clears app data.
翻訳すると、
- アプリが新しいデバイスで復元される場合
- ユーザーがアプリをアンインストール / 再インストールする場合
- ユーザーがアプリのデータを消去する場合
とのことでした。iOSとAndroidでドキュメントが分かれていますが、同じことが書いてあります。どうやらアプリをインストールしたままの状態でデバイストークンが更新されることはないということが判断できました。
こうした事情もあり、FCMを使って便利に実装できたとは言え、リリース後最初にPush通知が配信されるまでは、たまらなく不安でした。「Push通知を意図したタイミングで送ることができる」ということに対してはどうしてもナーバスになってしまいますが、今のところリリースしたアプリでは安定してPush通知が配信できているようです。
Apple社の審査が怖い
リリースに向けて意気揚々と開発を進めている毎日ですが、審査提出が近づいてくると、なにやら歯の根が合わないような感覚に襲われ、わなわなと震えが止まりません。特にApple社の審査は厳しいという評判を耳にしていたため、はじめて審査提出をしたときなどはどんなダメ出しを受けるのかと小心翼々としていました。
審査はApp Store Review ガイドラインをもとに行われ、これに反していると判断された場合はリジェクトされ、新しいビルドをアップロードしたり、App Store Connectに情報を追記したりする必要があります。
弊社がはじめてアプリをリリースしたときには、4.8 Appleでサインイン
という項目に反していたためリジェクトされました。はじめての審査提出、覚悟はしていたものの、それまで念頭になかった新規のサインイン手段を新たに設けよとは、なかなか大きな要求をしてくれたもんだ...と全員で嘆き苦しんだのを昨日のことのように思い出します。
当時リリースしようとしていたアプリには、SlackのOAuth認証を使ったサインインの機能が含まれており、それがリジェクトされるに至った原因でした。
4.8 Appleでサインイン
ユーザーのプライマリアカウントをAppで設定、または認証する際に、サードパーティのログインサービスやソーシャルログインサービス(Facebookでサインイン、Googleでサインイン、Twitterでサインイン、LinkedInでサインイン、Amazonでログイン、WeChatでログインなど)を使用するAppでは、同等のオプションとして「Appleでサインイン」を組み込む必要があります。
しっかりとガイドラインに明記されています。申し訳ございません。事前に全部読んでいればわかったことなのかもしれません。
「Appleでサインイン」が不要なパターンはガイドライン内に明示されています。
- Appが、自社独自のアカウント設定やサインインシステムのみを使用している場合。
- Appが教育機関、エンタープライズ、法人用のものであり、ユーザーが既存の教育機関またはエンタープライズアカウントでサインインする必要がある場合。
- Appが、政府または民間が運営する住基システムや電子IDを使ってユーザーを認証する場合。
- Appが特定のサードパーティサービスのクライアントであり、コンテンツにアクセスするため、ユーザーがメール、ソーシャルメディア、その他のサードパーティアカウントに直接サインインする必要がある場合。
今年開発した別のアプリでは、弊社独自のAPIによるマジックリンクを使用したサインインのみを実装し、IDとパスワードを使用した一般的なサインイン機能を備えていませんでしたが、こちらはリジェクトされず無事に公開できました。これはAppが、自社独自のアカウント設定やサインインシステムのみを使用している場合。
に当てはまっているものだと考えられます。
ネイティブアプリのリリース計画は、審査結果に左右されることもありますので、余裕を持って行いたいです。
リリースが怖い
またリリースの話です。
ネイティブアプリは、開発完了からリリースまでの間に審査というステップがあるため、リリースタイミングをコントロールするのが難しいと感じました。
Webだと、例えばバグを発見してFixした場合でもすぐにリリースすることができる場合も多いはずです。しかしネイティブアプリは、1つのバグFixをリリースするのにも審査が発生し、たとえ審査を突破してリリースを果たしたところで、ユーザー側の端末でアップデートをされない限り新しいバージョンのアプリを使ってもらうことはできません。
こうした事情から、アプリの改修を含むエピックの開発時は、後方互換を保ちつつ安全にリリースする方法を検討しなければなりません。
例えばAPIのとあるエンドポイントでの処理を一新する開発を行い、クライアントのアプリ側でもそれに合わせた対応を行なったとします。このとき、インターフェースの後方互換が保たれていない場合、APIをリリースすると古いバージョンのアプリでは動かない、なんてことになりかねません。
弊社でも悩んだ末にいくつかの解決策を試しています。
アプリに強制アップデート機能を備える
これは公開後のアプリを運用していく上で、あると大変ありがたい機能です。RemoteConfigに動作に必須なバージョンを保存しておき、端末にインストールされたアプリが「自身のバージョン」と「動作に必須なバージョン」とを比較し、アップデートが必要ならストアへ誘導する、といったものです。これを導入したことにより、古いバージョンへの互換を気にする必要がなくなりました。
破壊的変更が必要な場合は、古いアプリのためのエンドポイントを残しておく
強制アップデートの機能がない場合に、やむを得ず既存エンドポイントを古いバージョンのアプリのためのものとして残し、新たに新しいバージョンのアプリのためのエンドポイントを追加したこともあります。
これをやると古いアプリに向けたコードが残り続けてしまうため、折を見て削除したり、追って強制アップデートを実装したりと後々の対応が必要になってしまいます。根本的な解決を先延ばししているようで気が引けますが、背に腹は変えられませんでした。
最後に
はじめは怯懦の日々を送っていましたが、今では楽しく開発できています。Push通知は安定して送ることができ、Apple社の審査には慣れ、リリース時の互換性問題もなんとか(現在進行形で)解決の道を探っています。
しかしネイティブアプリ開発を続ける限り、こうした不安はつきものです。こういうとき、アプリエンジニアの方がいてくれたらどれだけ安心するだろう、とそう思わない日はありません。
誰か助けてください。
弊社では仲間を大募集しています!興味を持っていただけた方は、ぜひご応募ください!!!
Discussion