【问题标题】:Awareness API & Android O using BroadcastReceiver使用 BroadcastReceiver 的 Awareness API 和 Android O
【发布时间】:2017-09-14 13:55:20
【问题描述】:

我有一个 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 设备的后台监听感知围栏触发器。

如果有不清楚的地方或者我需要详细说明的地方,请告诉我。

提前致谢

【问题讨论】:

    标签: android broadcastreceiver android-broadcastreceiver android-8.0-oreo google-awareness


    【解决方案1】:

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

    这意味着不是这个:

    // 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)
    

    【讨论】:

    • 经过测试和工作。这应该是公认的答案,
    • 你说得对,西蒙。我刚刚对此进行了测试,并且可以确认它正在工作。它现在是公认的答案。
    • 注意,还是需要在manifest中注册receiver,比如:
    • Android @MichaelFranz 中的每个PendingIntent 都是如此。系统只初始化 Manifest 上注册的组件。在Android中,只能使用未注册的BroadcastReceiver使用Context.registerReceiver(receiver)
    【解决方案2】:

    我做了一点挖掘,偶然发现了this blog postCommonsWare。它说明了您所面临的问题。

    从上面的帖子:-

    Android O 中更具争议性的变化之一 — 对于具有 足够高的 targetSdkVersion — 是对隐式的有效禁止 广播。

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

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

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

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

    【讨论】:

    • 这在我开发应用程序时起到了作用,但是接受的答案是更好的解决方案,所以请检查一下。
    【解决方案3】:

    你的理解很正确。

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

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

    Source

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

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

    您可以在Android Manifest 中为ACTION_HEADSET_PLUG 进行抗辩。在onReceive 中,您可以:

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

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

    如果需要在onReceive 中完成短期工作,则另当别论 你们中的一些人可以从以下方面获得帮助:

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

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

    Source

    【讨论】:

    • 感谢您的回答阿努拉格。但是我需要使用 Awareness API,因为我的围栏不仅包括 HeadsetFence,而且还使用 DetectedActivityFence,因此我使用 AwarenessFence.and(DetectedActivityFence.during(DetectedActivityFence.IN_VEHICLE), HeadphoneFence.during(HeadphoneState.PLUGGED_IN)) 组合两个围栏,否则 ACTION_HEADSET_PLUG本来是完美的。
    • 行不通ACTION_HEADSET_PLUG 不会使用 Manifest 触发。它需要在代码中注册。请参阅:stackoverflow.com/a/6366238/2277631。所以这是一种完全没用的方法,因为您不想打开应用程序来检测耳机连接。
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多