在更高版本的Android上,通知DeleteIntent已损坏

Sea*_*eau 6 java android android-intent android-notifications android-pendingintent

在我们的应用程序OneBusAway Android(Github上的开源)中,我们需要在用户解除特定提醒通知时收到通知,因此我们不会针对同一事件发布另一个提醒通知(他们的公共汽车到达多长时间).

我们通过侦听一个这样Intent在我们的应用程序,注册为DeleteIntentNotification.当用户解除通知时(通过轻扫通知或点击通知窗口中的清除按钮),我们的应用程序应该收到通知Intent.

从测试来看,似乎使用Google Play上的当前版本(以及Github上当前主分支),我们的应用程序从未在以下Android版本中收到DeleteIntent:

  • Android 4.4.3
  • Android 4.4.4

然而,确切的相同的代码DOES工作(即,登记为DeleteIntent意图是由该应用接收到的)上:

  • Android 2.3.3
  • Android 2.3.6
  • Android 4.1.1
  • Android 4.1.2

我查看了以下涉及DeleteIntent的SO帖子,并且列出的所有解决方案都不适用于Android 4.4.3和4.4.4:

当前工作的主分支使用服务来侦听Intent.但是,基于上面的一些帖子,我确实调整了一些代码,使其更符合使用BroadcastReceiver监听Intent的工作示例.

使用BroadcastReceiver的代码位于以下Github分支中:

https://github.com/CUTR-at-USF/onebusaway-android/tree/issue104-RepeatingReminders

下面是我当前版本的外观(仍适用于Android 4.1.2及更低版本,但不适用于4.4.3或4.4.4)的摘录,以及指向Github源的链接:


创建通知

https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/tripservice/NotifierTask.java#L131

private Notification createNotification(Uri alertUri) {
    //Log.d(TAG, "Creating notification for alert: " + alertUri);
    Intent deleteIntent = new Intent(mContext, AlarmReceiver.class);
    deleteIntent.setAction(TripService.ACTION_CANCEL);
    deleteIntent.setData(alertUri);

    return new NotificationCompat.Builder(mContext)
            .setSmallIcon(R.drawable.ic_stat_notification)
            .setDefaults(Notification.DEFAULT_ALL)
            .setOnlyAlertOnce(true)
            .setDeleteIntent(PendingIntent.getBroadcast(mContext, 0,
                    deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT))
            .setAutoCancel(true)
            .build();
}
Run Code Online (Sandbox Code Playgroud)

标题和其他动态通知信息稍后设置(如果通知仍未确定,则稍后重置):

@SuppressWarnings("deprecation")
private void setLatestInfo(Notification notification,
        String stopId,
        String routeId,
        long timeDiff) {
    final String title = mContext.getString(R.string.app_name);

    final PendingIntent intent = PendingIntent.getActivity(mContext, 0,
            new ArrivalsListActivity.Builder(mContext, stopId).getIntent(),
            PendingIntent.FLAG_UPDATE_CURRENT);

    notification.setLatestEventInfo(mContext,
            title,
            getNotifyText(routeId, timeDiff),
            intent);
}
Run Code Online (Sandbox Code Playgroud)

TripService 包含操作的常量:

public static final String ACTION_CANCEL =
        "com.joulespersecond.seattlebusbot.action.CANCEL";
Run Code Online (Sandbox Code Playgroud)

AlarmReceiver

https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {

    private static final String TAG = "AlarmReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "In onReceive with intent action " + intent.getAction());
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

AndroidManifest

https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/AndroidManifest.xml

<receiver android:name=".AlarmReceiver">
     <!-- These action names must match the constants in TripService -->
      <intent-filter>
         <action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" />
         <action android:name="com.joulespersecond.seattlebusbot.action.POLL" />
         <action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" />
     </intent-filter>
 </receiver>
Run Code Online (Sandbox Code Playgroud)

有了上述内容,在Android 4.4.3/4.4.4上,当用户解除通知时,AlarmReceiver永远不会看到Intent.

我还尝试添加MIME类型,如在自定义操作中使用应用程序之间的隐式意图中指定的那样,但这在Android 4.4.3/4.4.4上也不起作用:

Intent deleteIntent = new Intent(mContext, AlarmReceiver.class);
    deleteIntent.setAction(TripService.ACTION_CANCEL);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        deleteIntent.setDataAndTypeAndNormalize(alertUri, TripService.REMINDER_MIME_TYPE);
    } else {
        deleteIntent.setDataAndType(alertUri, TripService.REMINDER_MIME_TYPE);
    }

    return new NotificationCompat.Builder(mContext)
            .setSmallIcon(R.drawable.ic_stat_notification)
            .setDefaults(Notification.DEFAULT_ALL)
            .setOnlyAlertOnce(true)
            .setDeleteIntent(PendingIntent.getBroadcast(mContext, 0,
                    deleteIntent, 0))
                    //.setLights(0xFF00FF00, 1000, 1000)
                    //.setVibrate(VIBRATE_PATTERN)
            .build();
Run Code Online (Sandbox Code Playgroud)

REMINDER_MIME_TYPEapplication/vnd.com.joulespersecond.seattlebusbot.reminder

使用MIME类型的清单:

<receiver android:name=".AlarmReceiver">
        <!-- These action names must match the constants in TripService -->
        <intent-filter>
            <action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" />
            <action android:name="com.joulespersecond.seattlebusbot.action.POLL" />
            <action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" />

            <data android:mimeType="application/vnd.com.joulespersecond.seattlebusbot.reminder" />
        </intent-filter>
    </receiver>
Run Code Online (Sandbox Code Playgroud)

我也尝试过使用支持库(即Notification.Builder代替使用NotificationCompat.Builder),但这也没有改变任何东西.

任何想法为什么这不适用于Android 4.4.3/4.4.4?

有关此问题的更多信息显示在Github问题中.

编辑

我还在一个小的Github项目"DeleteIntentDemo"中复制了这个问题:

https://github.com/barbeau/DeleteIntentDemo

重现的说明在本项目的自述文件中.

编辑2

这似乎是由于Android中存在错误Notification.setLatestEventInfo()- 我已在此处报告:https: //code.google.com/p/android/issues/detail?id = 73720

有关解决方法,请参阅@ CommonsWare的答案.

编辑3

我的AOSP补丁修复此问题现已合并,因此在未来的Android版本中,旧版应用不会出现此问题:https://code.google.com/p/android/issues/detail? id = 73720#c4

但是,在上面的AOSP主题中强调一个人不应再使用Notification.setLatestEventInfo()- 而是Notification.Builder用来创建一个新的通知.

Com*_*are 4

在示例项目中,如果删除以下行,则可以deleteIntent在运行 4.4.4 的 Nexus 4 上运行:

setLatestInfo(getActivity(), notification, routeId);
Run Code Online (Sandbox Code Playgroud)

我怀疑这个电话正在消灭你的deleteIntent. 作为处理的一部分,deleteIntent重新​​应用您的信息可能会起作用。NotificationsetLatestInfo()