おもむろにAndroidSDKのバージョン上げたらBLE通信できなくなったんだが

高校生の時に働いていたバイト先では昼だろうが夕方だろうがクリスマスだろうが関係なしに挨拶は「おはようございます」でした。

おはようございます！株式会社GxP 新卒から入社して7年目の向山です。
こちらは[グロースエクスパートナーズ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/gxp)の24日目の記事になります。

例年であればクリスマスや忘年会など大人数でワイワイガヤガヤと飲み食いしたり遊んだりしていたかと思いますが、このご時世流石にそれは厳しいので家でのんびり静かなクリスマスイブをお過ごしでしょう。

多分、例年とギャップがありすぎてやることもなく時間が空いている結果こちらの記事に辿りついたかと思いますので、つい先日あった案件の苦労話でも聞いてください。

## さっくりと背景

私の普段の業務は開発をベースにチームのスケジュール管理であったり、仕様の検討であったりと色んなことをやっています。
案件では「Javaを使ったWebアプリ」と「Xamarinを使ったAndroid/iOSのスマホアプリ」の開発を行っており、月に1回（主に月末）リリース作業を行っています。
スマホアプリではBluetooth Low Energy（以下「BLE」）を用いて機器との通信を行い、受信した値の履歴や変動を一覧やグラフで確認することが可能となっています。

そして今回の記事で主役となるのがこちらのAndroid版アプリとなります。

## 事件当日
11月を少し過ぎてしまい12月上旬、いつもより少し大きめの対応を済ませ、Android7～11とiOS12～14の実機によるリグレッションテストも完了。ここまで来てしまえばあとは各OSのストアへ公開するためにいつも通りアプリをアップロードしてリリースノート書いて申請が通るのを待つだけでした。

**たまーに申請却下されるけど大した内容じゃないしへーきへーき**

そう思っていた時期が私にもありました。

## ストアにアプリを上げようとしただけなのに

先にiOS版アプリのアップロードを済ませ、リリースノートを書いて申請を出しました。問題ありません。
そのままAndroid版アプリもアップロードした時、画面には赤字で見慣れないメッセージが表示されました。

> **現在、お客様のアプリは API レベル 28 を対象にしています。セキュリティとパフォーマンスが最適化された最新の API を利用するには、API レベル 29 以上を対象にする必要があります。アプリの対象 API レベルを 29 以上に変更してください。**

「はぇーマジか」これが私の第一声

どうやら2020/11/02以降、GooglePlayStoreへアプリをアップロードする際はtargetSdkVersionを29以上にしないとアップロードすらできないことになってしまったようです。なるほどなぁ。
ちなみに前回のリリースを行ったのが2020/10/29。ギリギリ影響を受けずにリリースできたようです。

赤字で表示されたTHE・エラーメッセージに私は一瞬戸惑っていましたが「単純にビルドで使ってるsdkのバージョン上げればええんやろ？リグレッションもっかいやんないといけんけどまぁしゃーない」と楽観的に考えながらポチポチとAndroidSDKのバージョンをAndroid9相当だった28からAndroid10相当の29へ変更して再ビルド。
特にエラーも発生しなかったのでリグレッションテストを始めるのでした。

が、しかし…

## 問題発生

AndroidSDKのバージョンを上げただけなのでiOS側には影響なしとして先述の通りAndroid7～11までの実機でリグレッションテストを進めていました。
Android7～9までのリグレッションテストが無事に完了し、Android10のリグレッションを開始。

するとなんということでしょう。
**BLEを使った機器との通信が全くできません。**ぴえん🥺

正確には機器と接続するために待受状態のBluetooth機器を画面の一覧を表示させているのですが、全くヒットしません。

一度ペアリングが完了した機器は端末のBluetooth設定にある接続済み機器の一覧から削除を行うことで再度接続が可能となるのですが、**削除して接続を試みようとしても全くできません**。ぴえんこえてぱおん🐘🐘

私は何かを察したのかおもむろにAndroid11でも接続できるか試して見ました。
**想定通りです。全く通信できません。本当にありがとうございました。**

2020年9月時点でAndroid10のシェア率はおよそ3割のようです。[^1]
Android9以前のバージョンでは問題なく動作するとは言ったものの、この状態でリリースするのは流石にクレームがくる…。

ここで私は素直に上長へ連絡してごめんなさいをしました。

ちなみにくっそどうでもいい話ですが、実はこの日の夜に同僚とご飯を食べに行く約束をしていたにも関わらず、今回の件と飲食店の時短営業も相まった結果行けなくなってしまったのでWパンチを食らい満身創痍でした。
問題が発生した翌日に有給取っていたのがせめてもの救い（リリースは救われてない）

## 原因の究明に向けて

弊アプリではBLE通信を行うために[Plugin.BLE](https://github.com/xabre/xamarin-bluetooth-le)を利用しています。
「動かなくなってしまったのであればライブラリを更新してしまえば良いのではないか」と思いアップデートを確認しました。
しかし、そこには昨年から更新が止まっているPlugin.BLE君の姿が…。
ライブラリを更新することによる問題の解消には繋がりませんでした。

次に確認したことは「Plugin.BLE以外のライブラリではどうなっているのか」でした。
BLE通信を行うためのライブラリは上記に挙げているPlugin.BLE以外にも[Sweetblue](https://sweetblue.io/)や[Nordic](https://github.com/NordicSemiconductor/Android-BLE-Library)などが存在しています。
「Plugin.BLEには更新が無かったけど、他のライブラリでは今回発生しているAndroid10以降の端末でのBLE通信をどのように行っているのか」
「リリースノートや記事などに対応方針やヒントが書かれているのではないか」ということで調査することにしてみました。

すると、Sweetblueのドキュメント[^2]にて以下の記載を見つけました。
> **In order to continue background scanning on Android 10, you need to add the new permission `android.permission.ACCESS_BACKGROUND_LOCATION` to your `AndroidManifest.xml` file.**

**`AndroidManifest.xml`に位置情報の権限を追加すればよい**、と。これで動くかもしれない！
私はウキウキで`AndroidManifest.xml`を見に行き、権限を追加しようとしました。
しかし、そこには既に同じ権限が鎮座していたためそっと振り出しに戻ることにしました。

## 問題の解決

しばらく調査を続けているとStack Overflow[^3]に以下の記載を見つけました。
> **if you target Android 10 then you need `ACCESS_FINE_LOCATION` to scan BLE. `ACCESS_COARSE_LOCATION` doesn't work anymore in Android 10.**

BLEと通信するためには位置情報が必要な情報となっていますが、Android10では `ACCESS_COARSE_LOCATION` でなく `ACCESS_FINE_LOCATION` が必要との記載が。
まさか？お？これは、もしかして…**いったーーーーーーーー！！！！**

ということで、無事にAndroid10以降でも**位置情報の権限を正しく設定することでBLE通信を行うことができるようになりました**🎉🎉🎉

今まで弊アプリでAndroid10以降でもBLE通信ができていたのはAndroidSDKのバージョンが28だったためであり、Android9相当のアプリをAndroid10以降でも頑張って動かしていたということが分かりました。
そしてAndroidSDKのバージョンを29へ上げたことによってAndroid10以降の端末では権限周りが今までよりすこーし厳格化され、BLE通信を行うためには適切な権限を設定する必要があった、というお話でした。

一応技術っぽいことも書いておくと、以下のように`ActivityCompat`から権限情報を取得し、足りていなかったら利用者に許可していただくようにリクエストダイアログの表示を行っています。

```cs
// 位置情報に関する権限情報を取得
var isCoarseLocationGranted = ActivityCompat.CheckSelfPermission(Android.App.Application.Context, Manifest.Permission.AccessCoarseLocation) == (int)Permission.Granted;
var isFineLocationGranted = ActivityCompat.CheckSelfPermission(Android.App.Application.Context, Manifest.Permission.AccessFineLocation) == (int)Permission.Granted;

if (!isCoarseLocationGranted || !isFineLocationGranted)
{
    // 権限が不足している場合は画面に許可のリクエストダイアログを表示
    ...
}
```

## ふりかえり

今回発生したAndroid版アプリをアップロードしてからエラーメッセージが表示され、AndroidSDKのバージョンを上げたらBLE通信ができなってしまった一連の流れですが、根本的な原因としては「**GooglePlayで最低保証されているAndroidSDKバージョンの確認が遅れた**」ということですね。
後から気付いた事ですが、[AndroidDeveloperのガイド](https://developer.android.com/distribute/best-practices/develop/target-sdk)や[Plugin.BLE](https://github.com/xabre/xamarin-bluetooth-le)にもしっかりと `ACCESS_FINE_LOCATION` が必要となる記載がありました。
リリース当日までそのことを知らずに作業を進め、当日にあたふたしながら問題の解消となってしまったのは完全に日頃の情報収集不足が招いた事故なので、今後はSlackのチャンネルに**GoogleやAppleなどの開発者向け情報を流すbot**を設定してなるべく見逃しが無いようにしていきたいと思います。

さて、明日で25日間あったAdventCalendarも最終日ですね！
[グロースエクスパートナーズ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/gxp)の最後は今月25日と26日に新宿中央公園で行われる「キャンドルナイト」についての記事を予定しておりますのでお楽しみに！

[^1]: [9月モバイルOSシェア、Android 10の増加が続く](https://news.mynavi.jp/article/20201003-1362641/) - マイナビニュース
[^2]: [Android-BLE-Issues](https://sweetblue.io/docs/Android-BLE-Issues) - Sweetblue
[^3]: [Android 10 not working with BLE Bluetooth scanning](https://stackoverflow.com/questions/58428763/android-10-not-working-with-ble-bluetooth-scanning) - Stack Overflow