设备重新启动后,地理围栏是不是在 android 中保持活动状态

Posted

技术标签:

【中文标题】设备重新启动后,地理围栏是不是在 android 中保持活动状态【英文标题】:Do Geofences remain active in android after a device reboot设备重新启动后,地理围栏是否在 android 中保持活动状态 【发布时间】:2013-12-03 11:58:48 【问题描述】:

我正在编写一个应用程序,当有人在安装应用程序的整个生命周期内进入/退出多个站点时,它需要使用地理围栏。

我的地理围栏实现(与下面的第二个链接非常相​​似)在我第一次安装应用程序时一切正常,无论是在移入/移出地理围栏时还是在使用模拟位置来模拟它时,直到设备重新启动.

在重新启动时,无论是模拟位置还是实际进出地理围栏似乎都不会触发事件并将未决意图触发到我的广播接收器。

我查看了以下三个链接,并且还阅读了相当多的文档,但我无法在任何地方找到明确的答案,直接说已注册的地理围栏在重新启动后仍然存在或不存在。

这些是我在堆栈溢出时查看的链接: Are android geofences surviving a reboot?

Android Geofence eventually stop getting transition intents

Do Android Geofences remain active until removed/expired or only until my PendingIntent is launched

如果有人碰巧知道他们是否在重新启动后仍然坚持,或者如果他们没有解决,那么将不胜感激!我目前的最后一个希望是为 BOOT_COMPLETED 创建一个侦听器并在启动时重新注册它们,但我更愿意只在绝对必要时这样做。

提前非常感谢!

编辑:虽然我还没有找到明确的(书面)答案,但我很确定 TonyC 先生发布的内容是正确的,并选择了该解决方案。非常感谢 TonyC!

如果有人想查看我的解决方案,我会在设备启动时监听启动完成操作,然后重新注册我需要的所有地理围栏。

这是在清单中:

<!-- Listen for the device starting up -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<receiver android:name="com.YOUR.PACKAGE.geofence.BootCompleteReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

然后为其创建一个广播接收器,它将在启动时重新注册地理围栏:

package com.YOUR.PACKAGE.geofence;

import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.Geofence;

public class BootCompleteReceiver extends WakefulBroadcastReceiver

    private static final String TAG = "BootCompleteReceiver";

    @Override
    public void onReceive(Context context, Intent intent)
    
        //Do what you want/Register Geofences
    

还值得注意的是,如果您在启动时处于地理围栏内,这通常会在地理围栏注册后触发地理围栏的挂起意图。

因此,例如,如果地理围栏启动了一个应用程序,那么当您启动恰好位于地理围栏中的设备时,一旦启动完成广播接收器注册了地理围栏,并且位置服务已经工作,它也会打开该应用程序你在哪里。

希望这对某人有所帮助。

【问题讨论】:

您真的需要在启动时使用 WakefulBroadcastReceiver 吗?简单的 lBroadcastReceiver 还不够吗?设备在启动后就进入睡眠状态是非常罕见的...... @Phenom 有没有关于如何注册地理围栏的示例,我遇到了问题,因为 Google Play 服务尚未初始化 【参考方案1】:

根据我的经验,地理围栏无法在重启后继续存在。正如您所建议的那样,我使用 BOOT_COMPLETED 接收器。它工作正常。

【讨论】:

“仅在需要时重新注册地理围栏”部分中的docs 确认了这一点。【参考方案2】:

地理围栏无法在重新启动后继续存在。在其他情况下,您也必须重新注册地理围栏。

Re-register geofences only when required 文档指出了除了 BOOT_COMPLETED 之外需要重新注册地理围栏的几种情况。不幸的是,它模糊且不完整。

考虑到从 Android O 开始强制实施的新 background execution limits,让我们逐点进行:

设备已重启

可以通过将以下内容添加到您的意图过滤器来处理此问题,因为它们是exempted from the implicit broadcast ban:

<action android:name="android.intent.action.BOOT_COMPLETED" />

然后,确保将以下权限添加到您的清单中:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

您可能想了解 Android N 中引入的较新的 LOCKED_BOOT_COMPLETED Intent:

<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />

但是,如果您这样做,您还需要用android:directBootAware=”true” 标记您的接收器。这个introduces ramifications for your app。也就是说,您访问的任何基于文件的数据都必须使用受设备保护的存储来完成。总而言之,如果您不需要在设备启动到锁定屏幕时收到通知,请不要使用 LOCKED_BOOT_COMPLETED。

应用程序已卸载并重新安装

再一次,我们很幸运,因为您可以使用这个明确的意图:

<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
应用数据被清除

这是我不知道的地方。有一个ACTION_PACKAGE_DATA_CLEARED 不受隐式广播禁令的约束,但只有在清除另一个包的数据时才会触发它。我已经尝试过了,可以确认当您自己的应用数据被清除时,您不会被调用。

Google Play 服务数据已清除

这可以通过将以下内容添加到您的接收器来处理:

<intent-filter>
    <!-- Used to watch for Google Play Services data cleared -->
    <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
    <data android:scheme="package" android:sspPrefix="com.google.android.gms"/>
</intent-filter>

然后将以下代码添加到您的 BroadcastReceiver 的 onReceive 方法中:

String action = intent.getAction();
if (TextUtils.equals(Intent.ACTION_PACKAGE_DATA_CLEARED, action)) 
    Uri uri = intent.getData();
    if (uri.toString().equals("package:com.google.android.gms")) 
        // Code here to handle Google Play services data cleared
    

该应用已收到GEOFENCE_NOT_AVAILABLE 警报

这是 Android 通过地理围栏 API 通知您位置服务不再可用的方式,通过发送带有错误和状态代码 GEOFENCE_NOT_AVAILABLE 的 GeofencingEvent 来表示。

但是,只要遵循地理围栏文档中的模糊建议,您就会相信此时您可以重新注册地理围栏。这会很糟糕,因为位置服务可能仍然被禁用,这样做会导致更多GEOFENCE_NOT_AVAILABLEs。需要一个钩子来判断位置服务何时被切换。

在 Android O 之前,为 android.location.MODE_CHANGED_ACTION 注册一个 BroadcastReceiver 会给你这个钩子。在 Android O 及更高版本上,此隐式 Intent 被禁止,您的 BroadcastReceiver 将不再被调用,因此需要另一个挂钩。

对于 Android O 及更高版本,我发现使用 JobScheduler 和 JobInfo.Builder.addTriggerContentUri 来监控 Settings.Secure.LOCATION_PROVIDERS_ALLOWED URI 用于此目的,如果当前未运行以调用 JobService,它甚至会启动您的应用程序。这种方法需要 API >= 24。我已经验证这可以工作,包括 Android P (API 28)。

JobScheduler 方法的一些注意事项:

    您的应用程序可能不会立即收到更改通知,但在我的测试中,它确实会在几分钟内收到通知。 LOCATION_PROVIDERS_ALLOWED 已弃用,可能会在未来的 Android 版本中移除。

因此,如果您对 24 的 minApi 版本没问题,您可以使用 JobScheduler/JobService 来获取 Settings.Secure.LOCATION_PROVIDERS_ALLOWED 挂钩。

但是,如果您不喜欢放弃 10% 的用户群 (as of this writing, KitKat (API 19) garners 9.1% of Android's active user base) 并且需要更低的 minApi,那么您需要同时拥有 BroadcastReceiver 和 JobService。

【讨论】:

Michael,请问您是如何注册地理围栏的?我们使用一个明确的 Broadcastreceiver 来完成它,该广播接收器将一个 jobintent 服务排入队列。我们这样做是因为我们不能直接在广播接收器中进行网络调用。但是,我们遇到了地理围栏延迟最多 20 分钟触发的问题... 嗨@Mathias。正如您所提到的,BroadcastReceiver#onReceive 是从主线程调用的。在这种情况下,我使用 BroadcastReceiver#goAsync 方法将工作卸载到后台线程而不是 JobIntentService。 嘿,迈克尔,我最终做了 goAsync(),谢谢!我之前尝试过,本可以发誓我得到了“不允许后台线程”的异常,但它似乎有效。感觉有点吓人,不过如果需要太长时间,Android 可能会杀死 BroadcastReceiver... Michael,你确定你让网络操作在 goasync() 中工作吗?它对我来说非常间歇性地工作,我知道为什么但我怀疑奥利奥及以上的打盹模式。 单独发帖讨论这个问题***.com/questions/52257295/…

以上是关于设备重新启动后,地理围栏是不是在 android 中保持活动状态的主要内容,如果未能解决你的问题,请参考以下文章

仅在需要时重新注册地理围栏

Android 地理围栏是不是保持活动状态直到删除/过期或仅在我的 PendingIntent 启动之前

iOS 7.1 地理围栏和 iBeacons 停止工作

Android 地理围栏 - 没有未来的意图?

对于在 O 设备上运行的应用程序,地理围栏的工作方式是不是有任何变化?

地理围栏不再从 ios7 中的终止状态重新启动应用程序?