前人未踏の領域へ アプリ開発編

Android, iOSアプリ開発に関する調査メモ置き場。ほとんどAndroid。はてなダイアリーから移行したため古い記事にはアプリ以外も含まれます。

Firebase Invitesを使う [Android]

絶賛はまり中。やりたいことによってはドはまりすると思うので覚悟すること。

お題

Firebase Invitesを使ってユーザーがアプリから友達を招待できるようにしたい。

環境

  • Android Studio 3.3 Beta4
  • com.android.tools.build.gradle:3.2.1
  • kotlin-gradle-plugin:1.3.10
  • firebase-plugins:1.1.5
  • google-services:4.2.0
  • firebase-core:16.0.4
  • firebase-invites:16.0.4

実装

onClickListenerなどに書く

val intent =
    AppInviteInvitation.IntentBuilder("ご案内")
        .setMessage("このアプリやろうぜ")
        .setEmailSubject("アプリに招待します")
        .setEmailHtmlContent(
            "<html><body>%%APPINVITE_LINK_PLACEHOLDER%%</body></html>"
        )
        .setGoogleAnalyticsTrackingId(getString(R.string.ga_trackingId))      //GoogleAnalytics
        .setDeepLink(Uri.parse("https://hogehoge.com/items/12345"))         //DeepLinkは現在未使用だが無いとSMSのURLが500エラーになるので仮当て
        .build()

startActivityForResult(
    intent,
    REQUEST_INVITE
)

動作

  • startActivityするとcom.google.android.gms.appinvite.ACTION_APP_INVITEアクションに対応するcom.google.android.gms..appinvite.AppInviteActivityが起動する

トラブルシューティング

SMSが送信されない
  • SHA1, SHA256登録後にgoogle-services.jsonを取り直していない(KeyStoreごとにclient_idが異なるようなので注意)
SMSを選択すると招待画面が落ちる(未解決)
  • Android 8.0以降か
  • Permissionの問題
  • android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@3b3fae7 -- permission denied for window type 2003 とか発生して落ちる
SMSのリンク先が500エラーになる

setDeepLinkを記述しないと発生する。nullをセットすると落ちる。使わなくても何かしらそれっぽいURLを書いておく。

メールが送信されない
  • ドキュメントに記載がないが、setEmailSubject setEmailHtmlContent を使わないと送信されない。
onActivityResultが2回呼ばれる
  • FragmentからStartActivityForResultしていて、MainActivity内でFragmentのonActivityResultを呼んでいたために発生
    厳密にはrequestCodeが異なるので合致するRequestCodeのみ扱うことで対応。
onActivityResultが resultCode=3になある
  • 送信に失敗している
  • Firebase ConsoleにSHA1を登録していない(releaseとstagingでKeyStoreが異なる場合などで設定忘れに注意)
  • Firebase ConsoleにSHA256を登録していない(Dynamic Linkの生成に必要)
onActivityResultが常に resultCode=0(RESULT_CANCELED) になる
  • 「SMSを選択すると招待画面が落ちる」と関連
  • 自分のアプリに戻る前にAppInviteActivityが落ちている
  • 送信完了メッセージをSnackBarで表示しようとして落ちる
  • 完了通知時に落ちるので送信はされる(正しく書けていれば)
firebase-core:16.0.5にするとビルドエラーになる

依存関係の問題。 修正版がリリースされているが、よく分からない。dex絡み。

Release Notes  |  Google APIs for Android  |  Google Developers

プロジェクトのbuild.gradleにVersion Matcher Pluginを入れたら動くにようになった気がする

apply plugin: 'com.google.android.gms.strict-version-matcher-plugin'
classpath 'com.google.android.gms:strict-version-matcher-plugin:1.0.2'
  • Clean Projectしてから再ビルドが必要。

まとめ

  • ドキュメント通りには動かない
  • メソッドの使用有無で送信されたりされなかったりがある
  • SMS送信の際にDynamic Linkが自動生成されるので
    AppsFlyerなどの他のDynamic Linkツールと組み合わせて使うには妥協が必要
  • 送信されない理由の説明がないので原因が特定しにくい
  • 結構バグっぽい挙動も多くて手強い

参考

Android アプリから Firebase Invites を送受信する  |  Firebase

Target API levelを28にした際に遭遇したエラー

Target API level 28にしたところ、Essential Phoneで2つのエラーに遭遇した。

Google Mapが落ちる

NoClassDefFoundError: Failed resolution of: Lorg/apache/http/ProtocolVersion; inside of com.google.android.gms

対応

AndroidManifest.xmlに以下の記述を追加する。

<uses-library
            android:name="org.apache.http.legacy"
            android:required="false" />
参考

Project Configuration  |  Maps SDK for Android  |  Google Developers

HTTP通信がエラーになる

Httpはデフォルトで無効化されたため、HTTP通信が必要な場合は回避コードを記述する必要がある。

対応

res/xml/network_security_config.xml を新たに作成し、HTTPを有効化したいドメインを記述し、 cleartextTrafficPermitted="true" とする

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">example.com</domain>
    </domain-config>
</network-security-config>

AndroidManifest.xmlに追記する

<application
        android:networkSecurityConfig="@xml/network_security_config">
参考

Android 8: Cleartext HTTP traffic not permitted - Stack Overflow

FLAG_ACTIVITY_REORDER_TO_FRONTのバグについて

BackStack上にあるActivityを再作成することなく再利用したい場合に、FLAG_ACTIVITY_REORDER_TO_FRONT を使うことで可能となるが、2つのバグがあって採用できずにいる。1つは解決済みだがもう一方は現在も発生する。

RootViewではないのにバックボタン押下時にHomeに戻ってしまう

対象

4系を含めたいくつかのAndroid Versionで発生

対応

参考URLに回避コードあり

再現手順

注:カッコ内はバックスタックの状態

  1. アプリ起動。Activity Aを表示(A)
  2. 画面をタップしてBに遷移(A : B)
  3. 画面をタップしてAに遷移(B : A)
  4. 戻るボタンをタップするとHomeに戻ってしまう

参考

Android 6.0系でOnNewIntent後に画面をタップするとHomeに戻ってしまう

対象

Android6.0系。Nexus5 で確認。ただしエミュレータ及び6系の他端末では再現せず

対応

調査中

再現手順
  1. アプリ起動。Activity Aを表示(A)
  2. 画面をタップしてBに遷移(A : B)
  3. 画面をタップしてAに遷移(B : A)
  4. 画面をタップするとHomeに戻ってしまう。

参考

幸い前者は回避コードがあるが、後者にはなく、かつ致命的なので6系サポート中は FLAG_ACTIVITY_REORDER_TO_FRONT が採用できない気が。現在イベント周りを調査中。