位置感知资源使您的应用程序可以与现实世界进行交互,它们是增加用户参与度的理想选择。 尽管许多移动应用程序都使用它们,但本教程的主题是地理围栏 ,它经常被忽略。
地理围栏是在真实地理区域上设置的虚拟边界。 将用户位置与地理围栏范围相结合,可以知道用户是在地理围栏之内还是之外,或者即使他正在离开或进入该区域。
想象一下一个大学应用程序,它可以告诉您当前校园里有哪些同事和教授。 或用于奖励老顾客的购物中心应用。 您还可以探索许多其他有趣的可能性。
在本教程中,您将通过创建一个在用户进入或退出地理围栏时向用户显示通知的应用程序,学习如何在Android上使用地理围栏。 如果您以前对Google Play服务 , Google Maps Android API或IntentService
有所了解,那么它会有所帮助。 如果没有,那么您仍然可以继续学习,但是在阅读了本教程之后,您可能需要对这些主题进行一些研究。
1. Android上的地理围栏
在Android上,有几种使用地理围栏的方法。 您甚至可以创建自己的实现来与地理栅栏配合使用,但是使用Google的GeofencingApi
更容易。
该API是Google 位置 API的一部分。 它包括Geofence
, GeofencingRequest
, GeofenceApi
, GeofencingEvent
和GeofenceStatusCodes
。 在本教程中,我们使用这些类来创建和使用地理栅栏。
地理围栏界面
Geofence
是代表应该监视的地理区域的接口。 它是通过使用Geofence.Builder
创建的。 在创建期间,您可以设置监视区域,地理围栏的到期日期,响应性,标识符以及它应寻找的过渡类型。
为了将功耗降至最低,建议在大多数情况下使用半径至少为100米的地理围栏。 如果地理围栏位于乡村,则应将半径增加到500米或更高,以确保地理围栏有效。
Geofence geofence = new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID) // Geofence ID
.setCircularRegion( LATITUDE, LONGITUDE, RADIUS) // defining fence region
.setExpirationDuration( DURANTION ) // expiring date
// Transition types that it should look for
.setTransitionTypes( Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT )
.build();
地理围栏过渡
-
GEOFENCE_TRANSITION_DWELL
指示用户进入该区域并花了一些时间。 当用户进入和离开该区域的速度过快时,避免出现多个警报很有用。 您可以使用setLoiteringDelay
参数配置setLoiteringDelay
时间。 -
GEOFENCE_TRANSITION_ENTER
指示用户何时进入监视区域。 -
GEOFENCE_TRANSITION_EXIT
指示用户何时退出区域。
GeofenceRequest
GeofencingRequest
类接收应监视的地理围栏。 您可以通过使用Builder
,传递Geofence
或List<Geofence>
以及创建地理围栏时触发的通知类型来创建实例。
GeofencingRequest request = new GeofencingRequest.Builder()
// Notification to trigger when the Geofence is created
.setInitialTrigger( GeofencingRequest.INITIAL_TRIGGER_ENTER )
.addGeofence( geofence ) // add a Geofence
.build();
GeofencingApi
GeofencingApi
类是与Google的geofencing API进行所有交互的入口点。 它是Location API的一部分,并且依赖于GoogleApiClient
来工作。 您将使用GeofencingApi
添加和删除地理围栏。
要添加地理围栏,请调用addGeofence()
方法。 它使用传递给GeofencingRequest
的设置监视给定区域,并在进行地理围栏转换(进入或退出该区域)时拍摄PendingIntent
。
PendingResult<Status> addGeofences (GoogleApiClient client,
GeofencingRequest geofencingRequest,
PendingIntent pendingIntent)
要删除地理围栏,请调用removeGeofences()
。 您可以使用其请求标识符或未决意图删除地理围栏。
PendingResult<Status> removeGeofences(GoogleApiClient client,
List<String> geofenceRequestIds)
PendingResult<Status> removeGeofences (GoogleApiClient client,
PendingIntent pendingIntent)
2.创建地理围栏应用
在本教程中,我们创建一个简单的应用程序,该应用程序监视用户位置并在用户进入或退出地理围栏区域时发布通知。 该应用程序仅包含一个Activity
和一个IntentService
。 我们还快速浏览了GoogleMap
, GoogleApiClient
和FusedLocationProviderApi
,并探讨了地理围栏API的一些注意事项。
步骤1:专案设定
GeofencingApi
是Google Play服务的一部分。 要访问它,您需要正确设置您的开发环境并创建一个GoogleApiClient
实例。 使用空白的Activity
创建一个新项目,如下所示编辑项目的build.gradle文件,并同步您的项目。
步骤2:权限
我们需要设置正确的权限才能创建和使用地理围栏。 将以下权限添加到项目清单中:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
从Android 6.0开始,该应用会在运行时而非安装过程中请求权限 。 我们将在本教程的后面部分解决这个问题。
步骤3:建立版面
该项目包含一个布局,即MainActity
布局。 它包含设备的当前纬度和经度,以及显示地理围栏和用户位置的GoogleMap
片段。
由于activity_main.xml非常简单,我只想专注于MapFragment
元素。 您可以在本教程的源文件中查看完整的布局。
<!--GoogleMap fragment-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.google.android.gms.maps.MapFragment"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
第4步:Google Maps API密钥
由于我们使用的是MapFragment
,因此我们需要设置和初始化GoogleMap
实例。 首先,您需要获取一个API密钥 。 获得API密钥后,将其添加到项目清单中。
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY"/>
让我们从GoogleMap
实例开始。 在Activity
类中实现GoogleMap.OnMapReadyCallback
, GoogleMap.OnMapClickListener
和GoogleMap.OnMarkerClickListener
并初始化地图。
public class MainActivity extends AppCompatActivity
implements
OnMapReadyCallback,
GoogleMap.OnMapClickListener,
GoogleMap.OnMarkerClickListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private TextView textLat, textLong;
private MapFragment mapFragment;
private GoogleMap map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLat = (TextView) findViewById(R.id.lat);
textLong = (TextView) findViewById(R.id.lon);
// initialize GoogleMaps
initGMaps();
}
// Initialize GoogleMaps
private void initGMaps(){
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
// Callback called when Map is ready
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d(TAG, "onMapReady()");
map = googleMap;
map.setOnMapClickListener(this);
map.setOnMarkerClickListener(this);
}
// Callback called when Map is touched
@Override
public void onMapClick(LatLng latLng) {
Log.d(TAG, "onMapClick("+latLng +")");
}
// Callback called when Marker is touched
@Override
public boolean onMarkerClick(Marker marker) {
Log.d(TAG, "onMarkerClickListener: " + marker.getPosition() );
return false;
}
}
步骤5: GoogleApiClient
要使用GeofencingApi
界面,我们需要一个GoogleApiClient
入口点。 让我们在Activity
实现一个GoogleApiClient.ConnectionCallbacks
和一个GoogleApiClient.OnConnectionFailedListener
,如下所示。
public class MainActivity extends AppCompatActivity
implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
OnMapReadyCallback,
GoogleMap.OnMapClickListener,
GoogleMap.OnMarkerClickListener {
// ...
private GoogleApiClient googleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// create GoogleApiClient
createGoogleApi();
}
// Create GoogleApiClient instance
private void createGoogleApi() {
Log.d(TAG, "createGoogleApi()");
if ( googleApiClient == null ) {
googleApiClient = new GoogleApiClient.Builder( this )
.addConnectionCallbacks( this )
.addOnConnectionFailedListener( this )
.addApi( LocationServices.API )
.build();
}
}
@Override
protected void onStart() {
super.onStart();
// Call GoogleApiClient connection when starting the Activity
googleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
// Disconnect GoogleApiClient when stopping Activity
googleApiClient.disconnect();
}
// GoogleApiClient.ConnectionCallbacks connected
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "onConnected()");
}
// GoogleApiClient.ConnectionCallbacks suspended
@Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended()");
}
// GoogleApiClient.OnConnectionFailedListener fail
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.w(TAG, "onConnectionFailed()");
}
}
步骤6: FusedLocationProviderApi
我们还需要访问用户的当前位置。 FusedLocationProviderApi
接口为我们提供了此信息,并允许对位置请求进行高度控制。 考虑到位置请求对设备的电池消耗有直接影响,这非常重要。
现在,让我们实现一个LocationListener
。 通过创建Location
请求,检查用户是否为应用程序授予了适当的权限,并在屏幕上显示其当前位置。
public class MainActivity extends AppCompatActivity
implements
// ....
LocationListener
{
private Location lastLocation;
//...
// GoogleApiClient.ConnectionCallbacks connected
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "onConnected()");
getLastKnownLocation();
}
// Get last known location
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if ( checkPermission() ) {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if ( lastLocation != null ) {
Log.i(TAG, "LasKnown location. " +
"Long: " + lastLocation.getLongitude() +
" | Lat: " + lastLocation.getLatitude());
writeLastLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
}
else askPermission();
}
private LocationRequest locationRequest;
// Defined in mili seconds.
// This number in extremely low, and should be used only for debug
private final int UPDATE_INTERVAL = 1000;
private final int FASTEST_INTERVAL = 900;
// Start location Updates
private void startLocationUpdates(){
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if ( checkPermission() )
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
@Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged ["+location+"]");
lastLocation = location;
writeActualLocation(location);
}
// Write location coordinates on UI
private void writeActualLocation(Location location) {
textLat.setText( "Lat: " + location.getLatitude() );
textLong.setText( "Long: " + location.getLongitude() );
}
private void writeLastLocation() {
writeActualLocation(lastLocation);
}
// Check for permission to access Location
private boolean checkPermission() {
Log.d(TAG, "checkPermission()");
// Ask for permission if it wasn't granted yet
return (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED );
}
// Asks for permission
private void askPermission() {
Log.d(TAG, "askPermission()");
ActivityCompat.requestPermissions(
this,
new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
REQ_PERMISSION
);
}
// Verify user's response of the permission requested
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult()");
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch ( requestCode ) {
case REQ_PERMISSION: {
if ( grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED ){
// Permission granted
getLastKnownLocation();
} else {
// Permission denied
permissionsDenied();
}
break;
}
}
}
// App cannot work without the permissions
private void permissionsDenied() {
Log.w(TAG, "permissionsDenied()");
}
}
必须解决的是,上面创建的LocationRequest
没有针对生产环境进行优化。 UPDATE_INTERVAL
太短,会消耗过多的电池电量。 更实际的生产配置可能是:
private final int UPDATE_INTERVAL = 3 * 60 * 1000; // 3 minutes
private final int FASTEST_INTERVAL = 30 * 1000; // 30 secs
private void startLocationUpdates(){
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if ( checkPermission() )
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
步骤7:GoogleMap标记
我们的Activity
需要两个不同的标记 。 locationMarker
使用FusedLocationProviderApi
给出的纬度和经度来通知设备的当前位置。 geoFenceMarker
是地理围栏创建的目标,因为它使用在地图上给出的最后触摸来检索其位置。
@Override
public void onMapClick(LatLng latLng) {
Log.d(TAG, "onMapClick("+latLng +")");
markerForGeofence(latLng);
}
private void writeActualLocation(Location location) {
// ...
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private Marker locationMarker;
// Create a Location Marker
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation("+latLng+")");
String title = latLng.latitude + ", " + latLng.longitude;
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if ( map!=null ) {
// Remove the anterior marker
if ( locationMarker != null )
locationMarker.remove();
locationMarker = map.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
map.animateCamera(cameraUpdate);
}
}
private Marker geoFenceMarker;
// Create a marker for the geofence creation
private void markerForGeofence(LatLng latLng) {
Log.i(TAG, "markerForGeofence("+latLng+")");
String title = latLng.latitude + ", " + latLng.longitude;
// Define marker options
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title(title);
if ( map!=null ) {
// Remove last geoFenceMarker
if (geoFenceMarker != null)
geoFenceMarker.remove();
geoFenceMarker = map.addMarker(markerOptions);
}
}
第8步:创建地理围栏
最后,是时候创建地理围栏了。 我们使用geoFenceMarker
作为地理围栏的中心。
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 500.0f; // in meters
// Create a Geofence
private Geofence createGeofence( LatLng latLng, float radius ) {
Log.d(TAG, "createGeofence");
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion( latLng.latitude, latLng.longitude, radius)
.setExpirationDuration( GEO_DURATION )
.setTransitionTypes( Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT )
.build();
}
接下来,我们创建GeofencingRequest
对象。
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest( Geofence geofence ) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger( GeofencingRequest.INITIAL_TRIGGER_ENTER )
.addGeofence( geofence )
.build();
}
我们使用PendingIntent
对象调用将处理GeofenceEvent
的IntentService
。 我们稍后会创建GeofenceTrasitionService.class
。
private PendingIntent geoFencePendingIntent;
private final int GEOFENCE_REQ_CODE = 0;
private PendingIntent createGeofencePendingIntent() {
Log.d(TAG, "createGeofencePendingIntent");
if ( geoFencePendingIntent != null )
return geoFencePendingIntent;
Intent intent = new Intent( this, GeofenceTrasitionService.class);
return PendingIntent.getService(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT );
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.d(TAG, "addGeofence");
if (checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
我们还将在地图上绘制地理围栏作为可视参考。
@Override
public void onResult(@NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if ( status.isSuccess() ) {
drawGeofence();
} else {
// inform about fail
}
}
// Draw Geofence circle on GoogleMap
private Circle geoFenceLimits;
private void drawGeofence() {
Log.d(TAG, "drawGeofence()");
if ( geoFenceLimits != null )
geoFenceLimits.remove();
CircleOptions circleOptions = new CircleOptions()
.center( geoFenceMarker.getPosition())
.strokeColor(Color.argb(50, 70,70,70))
.fillColor( Color.argb(100, 150,150,150) )
.radius( GEOFENCE_RADIUS );
geoFenceLimits = map.addCircle( circleOptions );
}
startGeofence()
方法负责启动MainActivity
类中的地理围栏过程。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.geofence: {
startGeofence();
return true;
}
}
return super.onOptionsItemSelected(item);
}
// Start Geofence creation process
private void startGeofence() {
Log.i(TAG, "startGeofence()");
if( geoFenceMarker != null ) {
Geofence geofence = createGeofence( geoFenceMarker.getPosition(), GEOFENCE_RADIUS );
GeofencingRequest geofenceRequest = createGeofenceRequest( geofence );
addGeofence( geofenceRequest );
} else {
Log.e(TAG, "Geofence marker is null");
}
}
步骤9:地理围栏转换服务
现在,我们终于可以创建前面提到的GeofenceTrasitionService.class
。 此类扩展了IntentService
,并负责处理GeofencingEvent
。 首先,我们从收到的意图中获取此事件。
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
然后,我们检查发生的地理围栏过渡是否对我们感兴趣。 如果是这样,我们将检索已触发地理围栏的列表,并创建具有适当操作的通知。
// Retrieve GeofenceTrasition
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) {
// Get the geofence that were triggered
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Create a detail message with Geofences received
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences );
// Send notification details as a String
sendNotification( geofenceTransitionDetails );
}
我还实现了一些辅助方法,以使类的实现更容易理解。
public class GeofenceTrasitionService extends IntentService {
private static final String TAG = GeofenceTrasitionService.class.getSimpleName();
public static final int GEOFENCE_NOTIFICATION_ID = 0;
public GeofenceTrasitionService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
// Retrieve the Geofencing intent
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if ( geofencingEvent.hasError() ) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode() );
Log.e( TAG, errorMsg );
return;
}
// Retrieve GeofenceTrasition
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) {
// Get the geofence that were triggered
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Create a detail message with Geofences received
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences );
// Send notification details as a String
sendNotification( geofenceTransitionDetails );
}
}
// Create a detail message with Geofences received
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for ( Geofence geofence : triggeringGeofences ) {
triggeringGeofencesList.add( geofence.getRequestId() );
}
String status = null;
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER )
status = "Entering ";
else if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT )
status = "Exiting ";
return status + TextUtils.join( ", ", triggeringGeofencesList);
}
// Send a notification
private void sendNotification( String msg ) {
Log.i(TAG, "sendNotification: " + msg );
// Intent to start the main Activity
Intent notificationIntent = MainActivity.makeNotificationIntent(
getApplicationContext(), msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create a notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder
.setSmallIcon(R.drawable.ic_action_location)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Geofence Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
// Handle errors
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
3.测试
在虚拟设备上测试
在虚拟设备上测试地理围栏要简单得多。 有几种方法可以做到这一点。 在Android Studio中,打开一个虚拟设备,然后单击右下角的更多选项按钮。
在左侧的“ 位置”标签中,输入位置的坐标。
我更喜欢使用telnet命令来控制虚拟设备。 要使用此功能,您需要使用以下命令从命令行连接到设备:
telnet localhost [DEVICE_PORT]
设备端口显示在虚拟设备窗口中。 设备端口通常等于5554 。
您可能需要使用auth_token
授权此连接,但命令行会向您显示该连接的位置。 导航到该位置并复制令牌并输入auth [YOUR_AUTH_TOKEN]
。
现在,您可以通过运行以下命令来设置设备的位置:
geo fix [LATITUDE] [LONGITUDE]
结论
地理围栏可能是您应用程序的重要补充,因为它可以大大提高用户参与度。 有许多探索的可能性,您甚至可以使用室内信标(例如Estimote)来创建精致的体验。 使用室内信标,您可以确切地知道用户经过的地点,例如,购物中心。
将地理围栏添加到项目很简单,但是我们始终需要牢记功耗。 这意味着我们需要仔细选择地理围栏的大小和更新速率,因为两者都会直接影响您应用程序的功耗。
因此,进行测试对于了解应用程序的功耗非常重要。 如果用户不需要或不需要此功能,也可以考虑为其提供完全禁用地理围栏的选项。
翻译自: https://code.tutsplus.com/tutorials/how-to-work-with-geofences-on-android--cms-26639