Androidでの位置情報の取得の今と昔
- はじめに
- 最新の Android Studio 2.3 Canary 2 に関する言及
- 古い取得方法 と OS 2.3で動いていたバージョン(v1)と現在のAPI(v2)が何が違うか?
- 最近の v9.8/v10.0 ベース
- 最近の compileSdkVersion 25
- support-v4 が低いosを殺しに来てる
- Geofencingの低電力という話に関して
- 過渡期的な位置情報系APIのdeprecated対応
はじめに
のお話を読んでて
位置情報的な話のコラム的な話を書きたくなったので書いてみた
最新の Android Studio 2.3 Canary 2 に関する言及
- InstantRun + DataBinding の併用が動くようになった
- Built-in shrinker と InstantRun の併用可と書いてあるけど
- 確かにビルドは通る
- ビルドはまともに長時間かかる*1
- アプリは必ず再起動
MultiDex + InstantRun
ユーザー定義style系が読み込まれなくなったので、レイアウトpreviewが死にました。なんか一個バグ潰したら新しいバクが発生するの止めてほしい
rm -rf ~/Library/Caches/AndroidStudioPreview あたりを消して、立ち上げ直したら治りました
- Invalidate Cachesが効かなかったorz
- AS2.2.2 => AS 2.3 Canary 2 のルートでOK*4
古い取得方法 と OS 2.3で動いていたバージョン(v1)と現在のAPI(v2)が何が違うか?
古い取得方法
- LOCATION_SERVICE から位置情報を取得
- LocationListener 経由で位置情報を取得
現在でも、compileSdkVersionを “Google APIs:24” 等に指定すれば利用可能- api 26でも問題なく動きます!。LocationManagerはちゃんとLimit Location対象になってる!!
android {
//compileSdkVersion "Google APIs:24" //<= ココ関係ないです><
}
LocationManager mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); //〜中略〜 LocationProvider provider = locationManager.getProvider(LocationManager.GPS_PROVIDER); // LocationListenerを登録 mLocationManager.requestLocationUpdates(provider, 0, 0, this); @Override public void onLocationChanged(Location location) { }
v1.5 ベース
- LocationClient で取得
- google_play_services_froyo 相当(5.xベース)
- OS2.3でもちゃんと動く
- NW接続が必須
- 正確にはGooglePlay開発者サービスが、GooglePlayService 8.4 ぐらいからOS4.1以下では現状更新されていないため最新のものを使っても情報が取得できない
- 2系、3系端末が殆ど使われていないみたいな話のレトリックはココらへんから
- Google Analiticsも古いから勿論端末利用情報が最新サーバに送られていない
LocationClient mClient = new LocationClient(this, this, this); //〜中略〜 Location loc = mClient.getLastLocation();
現在のAPI(v2)
- GoogleApiClient で取得
- 新し目のGooglePlay開発者サービスが入っていないと勿論正常に動かない
NW接続が必須
LocationServices.FusedLocationApi.requestLocationUpdates の利用
- この関数なんですが、位置情報モード[高精度] でないとまともに動きません。
- そのため、 status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS); 辺りのコードは必須
GooglePlayServicesを使うとした場合のオフライン対策的な話
最後の位置情報をPreference等で保持しておくしか無い
あと
LocationServices.FusedLocationApi.getLastLocation
もかなり怪しいのであてにならない*7
G様Mapアプリ では最後にMapを開いた位置動いているようなので、別途権限が必要なのかも
電池消耗の話に関して
設定>位置情報 で表示される
- 最近の位置情報リクエスト
- 低い電池使用量
と表示させるには
LocationRequestの設定は、あんま意味なくて
一定時間における位置情報リクエスト数*8で判定しているだけのようなので
- 高精度、PRIORITY_HIGH_ACCURACY で取得
- Interval は最低が1000ms(1秒) らしい
- 取得したらすく切断する*9
がベストプラクティスになるのかなと。
あと PRIORITY_HIGH_ACCURACY は、
- 現在GPS多用というよりアンテナ局の位置等(3G/LTE)で位置情報を取得している*10
- WiFi Onlyだと精度が落ちる
- 一番確実に取れる形が 3G/LTE + Wifi +GPS というお話も*12
最近の v9.8/v10.0 ベース
- 位置情報をOFFにした状態でも、LocationServices.SettingsApi.checkLocationSettings の関数が
- v10.0ベース
すべてのGooglePlayServicesのライブラリがv10.0 に上がっているわけではないので上げられない場合があり*15
android update sdkのタイミングで、短時間ですが minsdk-14でリリースされていて、すぐminsdk-9に戻された経緯があり、
G様内部では minsdk-14 前提で開発されている可能性が高*16
- x86用GooglePlayServices
zenfone2とかこちら側のはずなんですが、自分も使っていて
- GooglePlayStoreアプリでアプリのアップデートでクラッシュOS再起動*17
- G様エミュレータですら最新のGooglePlay開発者サービスが載っていないので動かせない
- まあversionさげてもエラーが出ないぐらいの確認しかできないのですが。。(汗
辺の動きもあるようですけど、実際どうなるんだろう。。
x86 Androidのサポートは基本低らしいですからね。。
最近の compileSdkVersion 25
- IntentServices::onHandleIntent で下記の関数が「UIスレッドで使え」とExceptionを吐くようになった
- getSystemService(LOCATION_SERVICE);
この手の変更点は、android.jarに変更が入っているんでしょうけど
どこにも記載されていないので正直すごく困りますね。。
むだに new Handlerで囲まないと駄目な感じになっています*18
これ compileSdkVersion 24 からかもしれないんですが
NotificationCompat経由からのActivity起動とかで困ってる。
- ActivityLifecycleCallbacks辺りを実装、ActivityStackを監視
- ActivityGroupが非推奨なので。。。
- 既存のActivityStackを終了させてから
- activity起動
とかしかないのかな〜(汗
support-v4 が低いosを殺しに来てる
target-25にすると、support-libraryも25使えといわれるのですが、
バラバラにされたaar単位で、下記を定義しましょうと言われます
<uses-sdk tools:overrideLibrary="XXX">
- ただこの手のタグのvalue値が255文字まで
- 重複タグ定義不可
- support-v4 だけで溢れます
なのでまず死にます。逃れられませんorz
Geofencingの低電力という話に関して
Geofencing自体は、低消費電力という話になっていますが*20
これはロケーション履歴のデータを利用しているからとのことらしいんですけど*21
ロケーション履歴を参照するAPIが公開されていないのでどうにもならないかなーと。
G様戦略だと
- 位置情報ON時
- GooglePlay開発者サービス=>位置情報を取得しつつ、ロケーション履歴 をG様鯖に送信、作成
- GooglePlay開発者サービス は高い電池使用量になる*22
- ただ他のG様アプリは、ロケーション履歴を利用するので 低い電池使用量
なんだろうな。。というのが所感。
まあ GoogleNow API も未だメーカー契約でしか公開されていないからなー
そこら辺の契約すれば、使えているメーカーさんもあるかもしれないですけど。。。
Google Nowといえば
というソフトがありましたね・・
GoogleNowランチャー使うときは便利なんですが
大概はメーカー製のLancherアプリが入っているので、
Google純正端末/genymotion等のエミュぐらいにしか導入しないという奴だったりも。。
過渡期的な位置情報系APIのdeprecated対応
Settings.Secure.LOCATION_PROVIDERS_ALLOWED
端末のGPSが使えるかどうかの判定
private boolean canGpsProvider() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ //Equal or higher than API 19/KitKat try { int locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE); if (locationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY){ return true; } } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } else{ // 位置測位プロバイダー一覧を取得 String providers = Secure.getString( context.getContentResolver(), Secure.LOCATION_PROVIDERS_ALLOWED); // "gps"が含まれているか boolean isGps = !(providers.indexOf("gps", 0) < 0); return isGps; } return false; }
*1:ビルド60〜180秒
*2:ビルド30〜90秒
*3:必ずアプリが再起動かかる
*4:Canary1にした段階で変なデータ作成されたのかもorz
*5:オフラインでは動かない
*6:オフラインでは動かない
*7:普通に使うと必ず北米を指す。
*8:GoogleAPIコール数
*9:継続して位置情報を取得する必要が無い場合
*10:補正が正しい?
*12:これがズバリ 高精度モード
*13:OSのversion依存? Firebase互換辺りにした関係のデグレ?
*14:これ北米でしかテストしてないから??
*15:Appindexingとかつかっていると駄目。。。9.8.0までしかリリースされていない
*16:というかそういうバージョンがリリースされてしまうのはリリース優先のスケジュールなんでしょうか。。
*17:PokemonGoとかndkでチェック厳しくしたのにx86サポートしていないやつとか
*18:OkHttp/Retrofit化しても new Handler()で囲むことにより階層が深くなる的な
*19:Service等を挟んで、FLAG_ACTIVITY_NEW_TASK 指定で上に重ねることは出来るけど。。
*20:G社様製アプリ と同様に
*22:たまに低い電池使用率 とか騙りますけど<苦笑