16

我有一个 Android 应用程序,它使用 Awareness API 在插入耳机时设置围栏。

我已经使用与以下示例中的代码非常相似的代码实现了 AwarenessFence:https ://developers.google.com/awareness/android-api/fence-register 。

我有一个 PendingIntent 定义为:

PendingIntent.getBroadcast(context, 0, new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)

然后在我的 AndroidManifest.xml 文件中

<receiver android:name=".fence.FenceDetector$MyFenceReceiver">
<intent-filter>
    <action android:name="my.application.packageFENCE_RECEIVER_ACTION" />
</intent-filter>

这是在 Manifest 中声明的,因为即使我的应用程序在后台,我也想接收广播。

这一切在 Android 7.0 及更低版本上运行良好,但是当我在 Android 8.0 上运行时,我收到错误:

BroadcastQueue: Background execution not allowed: receiving Intent { act=my.application.packageFENCE_RECEIVER_ACTION

我认为这是由于 Android O 上对后台执行的新限制。

谁能告诉我如何注册一个广播接收器,它可以在运行 API 26 的 Android 设备上在后台监听感知围栏触发器。

让我知道是否有不清楚的地方或者我需要详细说明。

提前致谢

4

3 回答 3

13

我现在无法在设备上对其进行测试,但从我所阅读的所有内容来看,限制仅在于隐式广播。这意味着,如果您改为创建显式广播,那么您只需要使其工作即可。

这意味着而不是这个:

// implicit intent matching action
PendingIntent.getBroadcast(context, 0,
    new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)

你做吧:

// explicit intent directly targeting your class
PendingIntent.getBroadcast(context, 0,
    new Intent(context, FenceDetector.MyFenceReceiver.class), 0)
于 2017-09-24T12:38:41.443 回答
6

我做了一点挖掘,偶然发现了CommonsWare的这篇博客文章。它说明了您所面临的问题。

从上面的帖子: -

对于具有足够高 targetSdkVersion 的应用程序,Android O 中最具争议的变化之一是有效禁止隐式广播。

因此,据此,我认为您的问题与 Awareness API 无关。相反,这是因为 Android 8 中引入的新行为。

不幸的是,到目前为止,似乎还没有可行的解决方案。同样,从同一篇文章中措辞:-

如果您正在接收系统发送的隐式广播(例如 ACTION_PACKAGE_ADDED),请将您的 targetSdkVersion 保持在 25 或更低,直到我们找到更好的解决方法(希望)不涉及轮询。

所以,希望在不久的将来会有更好的 8 解决方案。同时,您可以考虑其他选项或可以考虑降低您的 targetSDK。

于 2017-09-23T08:28:55.047 回答
1

你的理解非常正确。

面向 Android 8.0 或更高版本的应用无法再在其清单中为隐式广播注册广播接收器。隐式广播是不专门针对该应用程序的广播。

应用程序可以继续在其清单中注册显式广播。

来源

如果您只对插入耳机时设置围栏感兴趣。您可以使用

注意:许多隐式广播目前不受此限制。应用程序可以继续在其清单中为这些广播注册接收器,无论应用程序的目标是什么 API 级别。有关豁免广播的列表,请参阅隐式广播例外

您可以ACTION_HEADSET_PLUGAndroid Manifest. 在onReceive您可以:

  • 启动一个NotificationManager.startServiceInForeground(),以便您可以继续在后台工作。
  • 找到一种方法来使用计划的作业复制服务的功能。如果服务没有做用户立即注意到的事情,您通常应该能够使用计划的作业来代替。参考作业调度程序
  • 推迟后台工作,直到应用程序自然处于前台。

如果需要完成长时间运行的工作,我建议使用Job Scheduler的组合。ACTION_HEADSET_PLUG

否则,如果需要完成短期工作onReceive ,你们可以从以下方面获得帮助:

使用 goAsync() 来标记在 onReceive() 完成后需要更多时间才能完成的 BroadcastReceiver。如果您要在 onReceive() 中完成的工作足够长以导致 UI 线程错过一帧(>16 毫秒),这将特别有用,使其更适合后台线程。

您不应该从广播接收器启动长时间运行的后台线程。在 onReceive() 之后,系统可以随时终止进程以回收内存,并在此过程中终止进程中运行的衍生线程。为避免这种情况,您应该调用 goAsync()(如果您想要更多时间在后台线程中处理广播)或使用 JobScheduler 从接收器调度 JobService,以便系统知道该进程继续执行活动工作。

来源

于 2017-09-20T07:04:04.800 回答