概要
AndroidアプリのパーミッションにはNormalとDangerousの2種類がありGPS位置情報を取得するにはDangerousに分類されるACCESS_FINE_LOCATIONパーミッションが必要になる。Dangerousに分類されるパーミッションはパーミッションの取得にユーザの承認が必要で、このパーミッションの承認方法がtargetSdkVersionによって違う。
targetSdkVersionが23未満のとき
AndroidManifest.xmlにuses-permissionを追加する。
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application ...>
...
</application>
</manifest>
これでアプリのインストール時にシステムがユーザに承認を求め、アプリの実行時には特別な処理をしなくてもGPS機能にアクセスすることができる。
targetSdkVersionが23以上のとき
現時点ではほぼこちらだろう。AndroidManifest.xmlにuses-permissionとuses-featureを追加する。
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
<application ...>
...
</application>
</manifest>
targetSdkVersionが23以上の時はインストール時にはパーミッションの承認は行われず、アプリ実行時に必要になったときにrequestPermissions()を使ってユーザに承認をリクエストする。minSdkVersionが23以上なことはほぼないので基本的にPermissionCheckerやActivityCompatにはサポートライブラリを使う。
AppcompatActivityを継承したActivityのGPS機能にアクセスするメソッドにて次のような処理を行いパーミッションのリクエストを行う。requestPermissions()を呼ぶとユーザに承認を求めるダイアログが表示され、その結果はコールバックでアプリに通知される。そのためGPSのアクセスする部分はもとからパーミッションが得られていた場合とユーザにリクエストして取得した場合の複数にまたがってしまう。
private static final int REQUEST_CODE_GPS = 1;
public void onClicked(View view) {
if(PermissionChecker.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PermissionChecker.PERMISSION_GRANTED) {
//Access GPS
} else {
if(ActivityCompat.shouldShowRequestPermissionRationable(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
//Show Reason
}
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_GPS);
}
}
@Override
public void onRequestPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grandResults) {
switch(requestCode) {
case REQUEST_CODE_GPS:
if(PermissionChecker.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PermissionChecker.PERMISSION_GRANTED) {
//Access GPS
}
break;
}
}
Show Reasonと書いてあるところでは自前でユーザにGPS機能にアクセスする理由を説明する必要がある。
GPS機能を使って位置情報を取得
これまでの方法でアプリがGPS機能を利用できる状態になった。実際にGPSを使用する部分はtargetSdkVersionによらずに行える。まずはGPS位置情報を受け取るためのLocationListenerを実装する。例えば無名クラスを使って実装すると次のようになる。
LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
textView.setText(String.format(Locale.US, "%f,%f", latitude, longitude));
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
};
この例では適当なTextViewに得られた緯度経度を表示するようにしている。 次に上記したAccess GPSの部分で次のようにしてGPS位置情報のアクセスを開始する。
LocationManager locationManager;
@Oerride
public void onStart() {
super.onStart();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
@Override
public void onStop() {
super.onStop();
locationManager.removeUpdates(locationListener);
}
この例では実行時パーミッションは取得済みと仮定している。もし取得できていなければrequestLocationUpdatesはSecurityExceptionを投げる。よってrequestLocationUpdatesの直前にPermissionCheckerを使って再度パーミッションの確認を行うかcatchでSecurityExceptionを処理したほうが良い。
以上でGPS位置情報が取得できるようになった。でも実用するにはもっと工夫が必要。