Android 6.0とかパーミッションまわりがめんどくさいんですね…。 ということで自分用メモです。
まず、permissionを設定します。AndoridManifest.xmlに以下の定義を追加。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
追加するのはmanifestタグの直下ですね。
gms使うっぽいので、build.gradle(Module: app)に依存関係を追加します。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.1.1' compile 'com.google.android.gms:play-services:9.4.0' }
一番最後の依存関係ですね。
今回はサービスで色々ごにょごにょやりたかったので、GeofenceTransitionsIntentServiceという名前でサービスを1つ作りました。こんな感じで。
package com.example.kazuki.myapplication; import android.*; import android.app.IntentService; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.os.Bundle; import android.os.IBinder; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.util.Log; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingEvent; import com.google.android.gms.location.GeofencingRequest; import com.google.android.gms.location.LocationServices; import java.util.LinkedList; import java.util.List; public class GeofenceTransitionsIntentService extends Service implements GoogleApiClient.ConnectionCallbacks{ private List<Geofence> geofences = new LinkedList<>(); private GoogleApiClient client; @Override public void onCreate() { super.onCreate(); client = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .build(); client.connect(); Log.d("Sample", "onCreate"); } @Override public void onDestroy() { super.onDestroy(); client.disconnect(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return super.onStartCommand(intent, flags, startId); } Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(this.client); if (lastLocation == null) { Log.d("Sample", "lastLocation is null"); } else { float[] distances = new float[3]; Location.distanceBetween(34.38511, 132.4539817, lastLocation.getLatitude(), lastLocation.getLongitude(), distances); Log.d("Sample", "lastLocation: " + lastLocation.getLatitude() + ", " + lastLocation.getLongitude() + ", " + distances[0] + "m"); } GeofencingEvent e = GeofencingEvent.fromIntent(intent); if (e == null || e.getTriggeringLocation() == null) { Log.d("Sample", "GeofencingEvent#getTriggeringLocation is null"); return super.onStartCommand(intent, flags, startId); } String reason = ""; if (e.getGeofenceTransition() == Geofence.GEOFENCE_TRANSITION_ENTER) { reason = "ENTER"; } else if (e.getGeofenceTransition() == Geofence.GEOFENCE_TRANSITION_EXIT) { reason = "EXIT"; } else if (e.getGeofenceTransition() == Geofence.GEOFENCE_TRANSITION_DWELL) { reason = "DWELL"; } Log.d("Sample", reason + ": " + e.getTriggeringLocation().getLatitude() + ", " + e.getTriggeringLocation().getLongitude()); return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onConnected(@Nullable Bundle bundle) { this.setupGeofence(); } private void setupGeofence() { if (!this.geofences.isEmpty()) { return; } if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } Log.d("Sample", "setupGeofence"); this.geofences.add( new Geofence.Builder() .setRequestId("home") .setCircularRegion( 34.38511, 132.4539817, 1000 ) .setExpirationDuration(Geofence.NEVER_EXPIRE) .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) .build() ); GeofencingRequest req = new GeofencingRequest.Builder() .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_EXIT | GeofencingRequest.INITIAL_TRIGGER_DWELL) .addGeofences(this.geofences) .build(); Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); LocationServices.GeofencingApi.addGeofences( this.client, req, pendingIntent ); } @Override public void onConnectionSuspended(int i) { } }
色々ごにょごにょやってますが、パーミッションのチェックがOKならgeofenceを追加しています。座標は広島市役所に半径1㎞(1000m)のジオフェンスを作ってます。GeofenceingRequestとPendingIntentを作ってaddGeofencesをしています。
最後にMainActivityです。 ここでパーミッションOKしてもらったら、先ほど作ったサービスを起動しています。
package com.example.kazuki.myapplication; import android.Manifest; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.PackageManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingRequest; import com.google.android.gms.location.LocationServices; import java.util.LinkedList; import java.util.List; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onStart() { super.onStart(); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, 0); return; } this.startService(new Intent(this, GeofenceTransitionsIntentService.class)); } public void onClick(View v) { this.startService(new Intent(this, GeofenceTransitionsIntentService.class)); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { this.startService(new Intent(this, GeofenceTransitionsIntentService.class)); } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
あとは、Fake GPSアプリとか入れて開発者オプションから疑似ロケーションの設定をして広島市役所付近でいじってやればLogにENTERとかEXITとか出るはずです。
ソースコードはGitHubに上げておきました。