🚀

FlutterでAndroidのDeeplinkを実装するときはLaunchModeを頭の片隅に

2024/06/26に公開

はじめに

こんにちは。お世話になっております。スペースマーケットでAndroid/Flutterエンジニアをしておりますseoと申します。

今日は、Flutter開発しているときに、ちょっぴり必要になってくるAndroidネイティブの知識をシェアできればと思います。

「アプリ開発はFlutterから始めました」という駆け出しエンジニアの方々も多いと思いますので、そういう方向けの記事です。

ハマったこと

FlutterでDeeplinkの実装をしていたときに、ハマってしまいました。

状況としては、開発中のアプリから認証や決済系などの外部アプリへ遷移させて、操作が完了したら再びこちらのアプリへDeeplink経由で戻ってきてもらうような、ユーザーがアプリ間をまたぐ操作を実装するときです。

一連の動作
MyApp --(外部アプリ遷移)--> 外部アプリで操作 --(Deeplink経由)--> MyApp

想定されるユースケースとしては、
MyAppでユーザーが情報を入力し、外部アプリで本人認証や決済を行い、
deeplinkで再びMyAppに戻ると、ユーザーがせっかく入力した情報などが
リセットされてしまっていて、期待した動作にならない。といったことがあります。

解決法

FlutterプロジェクトのAndroid配下に下記のようなManifestファイルがあるかと思います。

AndroidManifest.xml
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTop" <<<<<<<<<<<こちらに注目
    android:theme="@style/LaunchTheme"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="schemeName"
            android:host="hostName" />
    </intent-filter>
</activity>

着目してほしいのはandroid:launchMode="singleTop"です。
Flutterプロジェクトを新規に作成したとき、こちらがデフォルトでsingleTopに設定されているかと思います。

この状態だと外部アプリで操作後、deeplinkで元のアプリへ戻ってきた時に、初期画面に戻っていることがあります。

そんなときはこちらを試してみてください。

AndroidManifest.xml
 <activity
    android:name=".MainActivity"
    android:exported="true"
+   android:launchMode="singleTop"
-   android:launchMode="singleInstance"
    android:theme="@style/LaunchTheme"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="schemeName"
            android:host="hostName" />
    </intent-filter>
 </activity>

AndroidのLaunchModeについて

今回なぜsingleTopのままだと、なぜ入力していた情報などがリセットされるのか?
LaunchModeに関してはGoogle Developerのドキュメントを読んでみると、

An activity with the "standard" or "singleTop" launch mode can be instantiated multiple times.

と記載がある通り、singleTopだと新たなインスタンスが作成される、つまり新たなActivityが起動していることになります。

A "singleInstance" activity, on the other hand, permits no other activities to be part of its task. It must be the only activity in the task.

それに対して、singleInstanceはその名から推測できる通り、単一のインスタンスのため、すでに存在しているactivityが使い回されることになります。

注意点としては、singleInstancenot recommended for general useと記載がある通り、推奨される使い方ではないため、外部から呼び出される操作のときに、副作用がないかを検討する必要があります。

解決方法から得た学び

Flutter実装中に、iOSは問題なく期待通りの動作なので、Androidではうまく動かない(逆も然り)といった状況に遭遇したときは、Flutterのドキュメントだけでなく、iOS/Androidそれぞれの公式ドキュメントを見るようにすることが必要だと気づきになりました。

FlutterならiOS/Androidを一気に作れるので、学習することが少ないと一般的に言われますが、
こういったときにネイティブ実装の知識や経験が活きたりするので、普段から情報感度を高くしておくことも重要ですね!

最後に

スペースマーケットでは一緒に働く仲間を募集しています!
カジュアルに話を聞きたいだけという方でも大歓迎ですので、ちょっとでも興味があれば以下からご応募お待ちしております!

▼インフラエンジニア
https://herp.careers/v1/spmhr/qZ-3RxrPtDgM

▼Webエンジニア
https://herp.careers/v1/spmhr/9zYSnsOQ0UMA

▼アプリシニアエンジニア(EM候補)
https://herp.careers/v1/spmhr/3R1WuEBp6TlT

▼バックエンドエンジニア(EM候補)
https://herp.careers/v1/spmhr/f8x6AkIueBSb

▼エンジニア採用ページ(迷ったらこちらからどうぞ!)

スペースマーケット Engineer Blog

Discussion