Android 地理围栏不';不行?
因此,我一直在尝试从互联网上使用简单的地理围栏应用程序,但它们似乎都不起作用。在下面的示例中,当手机的经度和纬度满足constants类中定义的经度和纬度时,应触发通知。我用模拟器对其进行了测试,但当我相应地更改模拟器gps坐标时,什么也没发生。 根据文档,警报无法按预期工作可能有一些原因:Android 地理围栏不';不行?,android,geolocation,gps,geofencing,android-geofence,Android,Geolocation,Gps,Geofencing,Android Geofence,因此,我一直在尝试从互联网上使用简单的地理围栏应用程序,但它们似乎都不起作用。在下面的示例中,当手机的经度和纬度满足constants类中定义的经度和纬度时,应触发通知。我用模拟器对其进行了测试,但当我相应地更改模拟器gps坐标时,什么也没发生。 根据文档,警报无法按预期工作可能有一些原因: 在您的地理围栏或您的 土工栅栏太小了 设备上的Wi-Fi已关闭 地理围栏内没有可靠的网络连接 警报可能会延迟 我在android studio上收到以下消息: 这是我的日志: 02-01 13:42:
- 在您的地理围栏或您的 土工栅栏太小了
- 设备上的Wi-Fi已关闭
- 地理围栏内没有可靠的网络连接
- 警报可能会延迟
02-01 13:42:09.932 14925-14925/? I/zygote: Not late-enabling -Xcheck:jni (already on)
02-01 13:42:09.955 14925-14925/? W/zygote: Unexpected CPU variant for X86 using defaults: x86
02-01 13:42:09.993 14925-14932/? E/zygote: Failed writing handshake bytes (-1 of 14): Broken pipe
02-01 13:42:09.993 14925-14932/? I/zygote: Debugger is no longer active
02-01 13:42:10.315 14925-14925/? I/InstantRun: starting instant run server: is main process
02-01 13:42:10.725 14925-14942/? D/OpenGLRenderer: HWUI GL Pipeline
02-01 13:42:10.784 14925-14942/? I/zygote: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
02-01 13:42:10.784 14925-14942/? I/OpenGLRenderer: Initialized EGL, version 1.4
02-01 13:42:10.784 14925-14942/? D/OpenGLRenderer: Swap behavior 1
02-01 13:42:10.785 14925-14942/? W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
02-01 13:42:10.785 14925-14942/? D/OpenGLRenderer: Swap behavior 0
02-01 13:42:10.810 14925-14942/? D/EGL_emulation: eglCreateContext: 0x9cb60b60: maj 2 min 0 rcv 2
02-01 13:42:10.872 14925-14942/? D/EGL_emulation: eglMakeCurrent: 0x9cb60b60: ver 2 0 (tinfo 0xa60b35d0)
02-01 13:42:10.963 14925-14942/? D/EGL_emulation: eglMakeCurrent: 0x9cb60b60: ver 2 0 (tinfo 0xa60b35d0)
02-01 13:42:11.480 14925-14925/com.shah.kaushal28.fence I/Choreographer: Skipped 31 frames! The application may be doing too much work on its main thread.
MainActivity.java类
package com.shah.kaushal28.fence;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.model.LatLng;
import java.util.ArrayList;
import java.util.Map;
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ResultCallback<Status>{
private static final String TAG = "";
protected ArrayList<Geofence> mGeofenceList;
protected GoogleApiClient mGoogleApiClient;
private Button mAddGeofencesButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
// Empty list for storing geofences.
mGeofenceList = new ArrayList<Geofence>();
// Get the geofences used. Geofence data is hard coded in this sample.
populateGeofenceList();
// Kick off the request to build GoogleApiClient.
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
Log.e(TAG, "building client successful");
}
public void populateGeofenceList() {
for (Map.Entry<String, LatLng> entry : Constants.LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
}
Log.e(TAG, "geofence populated");
}
@Override
protected void onStart() {
super.onStart();
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
Log.e(TAG, "mGoogleApiClient connected");
}
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
Log.e(TAG, "mGoogleApiClient disconnected");
}
}
@Override
public void onConnected(Bundle connectionHint) {
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// Do something with result.getErrorCode());
}
@Override
public void onConnectionSuspended(int cause) {
mGoogleApiClient.connect();
}
public void addGeofencesButtonHandler(View view) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
}
Log.e(TAG, "geofence added");
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(
this,
"Geofences Added",
Toast.LENGTH_SHORT
).show();
} else {
// Get the status code for the error and log it using a user-friendly message.
System.out.println("Error");
Toast.makeText(
this,
"Error",
Toast.LENGTH_SHORT
).show();
}
}
}
package com.shah.kaushal28.fence;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Kaushal28 on 4/26/2017.
*/
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
public GeofenceTransitionsIntentService() {
super(TAG); // use TAG to name the IntentService worker thread
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if (event.hasError()) {
Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
return;
}
String description = getGeofenceTransitionDetails(event);
sendNotification(description);
}
private static String getGeofenceTransitionDetails(GeofencingEvent event) {
String transitionString =
GeofenceStatusCodes.getStatusCodeString(event.getGeofenceTransition());
List triggeringIDs = new ArrayList();
for (Geofence geofence : event.getTriggeringGeofences()) {
triggeringIDs.add(geofence.getRequestId());
}
return String.format("%s: %s", transitionString, TextUtils.join(", ", triggeringIDs));
}
private void sendNotification(String notificationDetails) {
Log.e(TAG, "Notification Triggered");
// Create an explicit content Intent that starts MainActivity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Get a PendingIntent containing the entire back stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class).addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText("Click notification to return to App")
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true);
// Fire and notify the built Notification.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}
}
package com.shah.kaushal28.fence;
/**
* Created by Kaushal28 on 4/26/2017.
*/
import com.google.android.gms.maps.model.LatLng;
import java.util.HashMap;
public class Constants {
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = 12 * 60 * 60 * 1000;
public static final float GEOFENCE_RADIUS_IN_METERS = 20;
public static final HashMap<String, LatLng> LANDMARKS = new HashMap<String, LatLng>();
static {
// San Francisco International Airport.
LANDMARKS.put("Moscone South", new LatLng(37.783888,-122.4009012));
// Googleplex.
LANDMARKS.put("Japantown", new LatLng(37.785281,-122.4296384));
// Test
LANDMARKS.put("SFO", new LatLng(37.621313,-122.378955));
}
}
Constants.java类
package com.shah.kaushal28.fence;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.model.LatLng;
import java.util.ArrayList;
import java.util.Map;
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ResultCallback<Status>{
private static final String TAG = "";
protected ArrayList<Geofence> mGeofenceList;
protected GoogleApiClient mGoogleApiClient;
private Button mAddGeofencesButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
// Empty list for storing geofences.
mGeofenceList = new ArrayList<Geofence>();
// Get the geofences used. Geofence data is hard coded in this sample.
populateGeofenceList();
// Kick off the request to build GoogleApiClient.
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
Log.e(TAG, "building client successful");
}
public void populateGeofenceList() {
for (Map.Entry<String, LatLng> entry : Constants.LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
}
Log.e(TAG, "geofence populated");
}
@Override
protected void onStart() {
super.onStart();
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
Log.e(TAG, "mGoogleApiClient connected");
}
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
Log.e(TAG, "mGoogleApiClient disconnected");
}
}
@Override
public void onConnected(Bundle connectionHint) {
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// Do something with result.getErrorCode());
}
@Override
public void onConnectionSuspended(int cause) {
mGoogleApiClient.connect();
}
public void addGeofencesButtonHandler(View view) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
}
Log.e(TAG, "geofence added");
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(
this,
"Geofences Added",
Toast.LENGTH_SHORT
).show();
} else {
// Get the status code for the error and log it using a user-friendly message.
System.out.println("Error");
Toast.makeText(
this,
"Error",
Toast.LENGTH_SHORT
).show();
}
}
}
package com.shah.kaushal28.fence;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Kaushal28 on 4/26/2017.
*/
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
public GeofenceTransitionsIntentService() {
super(TAG); // use TAG to name the IntentService worker thread
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if (event.hasError()) {
Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
return;
}
String description = getGeofenceTransitionDetails(event);
sendNotification(description);
}
private static String getGeofenceTransitionDetails(GeofencingEvent event) {
String transitionString =
GeofenceStatusCodes.getStatusCodeString(event.getGeofenceTransition());
List triggeringIDs = new ArrayList();
for (Geofence geofence : event.getTriggeringGeofences()) {
triggeringIDs.add(geofence.getRequestId());
}
return String.format("%s: %s", transitionString, TextUtils.join(", ", triggeringIDs));
}
private void sendNotification(String notificationDetails) {
Log.e(TAG, "Notification Triggered");
// Create an explicit content Intent that starts MainActivity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Get a PendingIntent containing the entire back stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class).addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText("Click notification to return to App")
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true);
// Fire and notify the built Notification.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}
}
package com.shah.kaushal28.fence;
/**
* Created by Kaushal28 on 4/26/2017.
*/
import com.google.android.gms.maps.model.LatLng;
import java.util.HashMap;
public class Constants {
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = 12 * 60 * 60 * 1000;
public static final float GEOFENCE_RADIUS_IN_METERS = 20;
public static final HashMap<String, LatLng> LANDMARKS = new HashMap<String, LatLng>();
static {
// San Francisco International Airport.
LANDMARKS.put("Moscone South", new LatLng(37.783888,-122.4009012));
// Googleplex.
LANDMARKS.put("Japantown", new LatLng(37.785281,-122.4296384));
// Test
LANDMARKS.put("SFO", new LatLng(37.621313,-122.378955));
}
}
包com.shah.kaushal28.fence;
/**
*由Kaushal28于2017年4月26日创建。
*/
导入com.google.android.gms.maps.model.LatLng;
导入java.util.HashMap;
公共类常量{
公共静态最终长地理围栏\u到期时间\u毫秒=12*60*60*1000;
公共静态最终浮动土工围栏半径(单位:米)=20;
public static final HashMap LANDMARKS=new HashMap();
静止的{
/旧金山国际机场。
LANDMARKS.put(“莫斯科内南部”,新拉特林(37.783888,-122.4009012));
//谷歌广场。
LANDMARKS.put(“Japantown”,新LatLng(37.785281,-122.4296384));
//试验
LANDMARKS.put(“SFO”,新LatLng(37.621313,-122.378955));
}
}
尝试使用更大的半径,然后将其减小到要求的范围-
查看谷歌文档-
为地理围栏选择最佳半径
为获得最佳效果,土工栅栏的最小半径应设置在100-150米之间。当Wi-Fi可用时,定位精度通常在20-50米之间。当室内位置可用时,精度范围可小至5米。除非您知道地理围栏内的室内位置可用,否则假设Wi-Fi定位精度约为50米
当Wi-Fi位置不可用时(例如,当您在农村地区驾驶时),定位精度会降低。精度范围可达几百米到几公里。在这种情况下,您应该使用更大的半径创建地理围栏。GPS在很大程度上依赖于硬件和位置。许多人坐在电脑前,想知道为什么他们的GPS代码不能像他们期望的那样工作。当我学习这些东西的时候,我曾经制作GPS跟踪应用程序,让它们通知我上班路上的地点,你可以很快看到它的变化。不要依赖地理围栏之类的东西,只需使用它们来增强您的体验我正在android emulator上测试应用程序,这可能是因为它。使用您看到的一些日志更新您的问题,这样我们就有了一个想法当在真实设备上测试时,这里是我日志的屏幕截图抱歉,我应该说-为geofence添加更多日志,并在没有日志时显示日志工作-例如,打印出你的latlong并显示它确实改变了等等,我把它的半径改为100,但仍然没有得到任何东西。我正在android模拟器上测试应用程序,这可能是因为它。是的,这可能是您直接指定位置的原因,可能是您可以检查驻留模拟器,但我不确定。用真正的设备试试。我用真正的设备试过,但也没发生什么。我断断续续地做了几天。多么糟糕的表演。该示例已被弃用,文档让它看起来超级简单,可怕,因为该公司认为他们发明了位置管理。可怕的。