のらぬこの日常を描く

ノージャンルのお役立ち情報やアニメとゲームの話、ソフトウェア開発に関する話などを中心としたブログです。

【android】firebaseをdebug版で有効化すると、アプリ権限周りに不具合が出る可能性アリ?

どうもこんにちは。のらぬこです。

今日はandroid開発のお話です。

今回話すこと

firebase-analytics, firebase-crashを試してみたところ、デバッグビルド版で外部SDカードのアプリパッケージストレージ(/storage/sdcard1/Android/data/{packageName}/file/...)への書き込みができなくなったという、何を言ってるか解らないと思うが俺も何が起きたのかわからない系のお話です。

半日ほどはまりました。

前座其の零 - firebaseって?

さて、タイトルにもある「firebase」ですが、これは、今年の中ごろにgoogleにより提供が開始されたBaaSとかmBaaSとか呼ばれている系のサービス群です。

BaaSとかmBaaSとか言われても、いまいちよくわからないのですが、サーバと通信することで成り立つようなアプリのサーバーサイドの機能を仮想化したもの?みたいな感じのようです。

例えば、ログイン機能、ユーザデータ保存機能、プッシュ通知機能などです。

僕が開発中のアプリでも、現在「firebase-ads(アプリ内広告)」「firebase-analytics(google analyticsのアプリ版)」「firebase-crash(クラッシュレポート収集)」の3つのサービスを利用しています。

前座其の壱 - 導入 ~ 使い始めまで

Firebaseとは何ぞや的な話とか、どんなことができるのかとか、アプリに組み込むにはどうすればいいんじゃとかは、公式日本語ドキュメントにかなり詳しく書かれています。

Firebase

ざっくり言うとこんな感じです。

  • Firebase console にログインして、アプリのapplicationId(package name)を登録する
  • アプリ固有の情報が書かれたgoogle-services.json というファイルのリンクが表示され、これををダウンロードしてプロジェクトの app/ に配置しろと説明があるのでその通りにする。
  • build.gradle に 以下のようなdependency を追加
    compile 'com.google.firebase:firebase-ads:9.6.1'
    compile 'com.google.firebase:firebase-crash:9.6.1'
    compile 'com.google.firebase:firebase-analytics:9.6.1'

analyticsとcrash はこれでおしまいです。
adsは広告表示用のコードを layoutで指定するなり javaでコーディングするなりが必要ですが数行書くだけで完了です。

前座其の弐 - google-services.json って何さ

前項で出てきた、google-services.json ですが、この中には何が書かれているのか、ちょっと覗いてみました。
中には、何かのハッシュコード的なものとかアプリのapplicationIdなどが書かれているようです。

おそらく、アプリとFirebaseのアカウントを紐づけるための情報が書かれているんだと思います。

debugとreleaseでパッケージ名変えてるんだが

build.gradleに下記のようなこと書いている方結構いらっしゃると思います

    buildTypes {
        debug {
            ....
            applicationIdSuffix '.debug'
            ....
        }
    }

こんな風にを書いておけば、debugビルドとreleaseビルドでアプリのapplicationIdを変えることができます。

例えば、アプリの applicationIdが下記のような感じだったとします。

applicatoinId : net.noranuk0.hoge.hoge

build.gradle内に上に書いたような指定を記載すると、debugビルド版のapplicationIdが以下のようになります。

applicatoinId : net.noranuk0.hoge.hoge.debug

なるほど、一台のスマホデバッグ版とリリース版両方のアプリを同居させられるわけね。

でも、少し話を戻します。

google-services.json」には release版のapplicationIdが書かれています。

debug版だけapplicationId変えちゃうとおかしなことにならない?

その辺はちゃんと考えられていて、ビルドタイプごとに「google-services.json」を使い分ける仕組みがちゃんと用意されています。

(プロジェクトルート)/app/src/debug/google-services.json
(プロジェクトルート)/app/src/release/google-services.json

のような感じで、debug版,relese版のgoogle-services.json を配置してあげると、ビルドタイプごとに使い分けてくれるようになっています*1

問題発生

冒頭で書いた事案が発生しました。

File[] dirs = context.getExternalFilesDirs(Environment.DIRECTORY_DOWNLOADS);
for (File dir : dirs) {
    // EXTERNAL_WRITE_STORAGE権限が無いと何故か例外が飛ぶ
    // さらに、外部ストレージ(SDカード)の場合にはStorage Access Framework で頑張らないとダメ。
    try {
        FileWriter filewriter = new FileWriter(new File(dir, "example.txt);
        ...
    } catch (IOException e) {
        ....
    }
}

firebase-analytics, firebase-crashを組み込んだプロジェクトをdebugビルド版で起動したところ、外部SDカードのアプリパッケージストレージ(/storage/sdcard1/Android/data/{packageName}/file/...)への書き込みができなくなってしまいました。

Firebaseを組み込んでからしばらくたって現象に気が付いたので特定にえらい時間食いました。

内部SDカードへのアプリパッケージストレージへの読み書きは問題なくできてお、ますます混乱したし*2

試しにfirebaseの依存関係を外したところ現象が出なくなりました。

まじかorz.. と思いました。

解決方法

これがfirebaseのバグなのかはわかりませんが

    compile 'com.google.firebase:firebase-ads:9.6.1'
    releaseCompile 'com.google.firebase:firebase-crash:9.6.1'
    releaseCompile 'com.google.firebase:firebase-analytics:9.6.1'

とりあえずdebug時は crashとanalytics無効にすることで対応です。

無事、外部SDカードのアプリパッケージストレージへの書き込みできました。

今回のお話は以上となります。

どなたかのご参考になれば幸いです。

*1:これができるようになったの割と最近みたいです

*2:開発中アプリが(READ|WRITE)_EXTERNAL_STORAGEをもともと要求していたせい