在Android O(奥利奥)中,使用AlarmManager和BroadcastReceiver的本地通知未能触发。

24

我已经在Android SDK 26之前的安卓设备上成功运行本地通知。

但是在Android O中,我收到了以下警告,并且广播接收器没有被触发。

W/BroadcastQueue: Background execution not allowed: receiving Intent { act=package.name.action.LOCAL_NOTIFICATION cat=[com.category.LocalNotification] flg=0x14 (has extras) } to package.name/com.category.localnotifications.LocalNotificationReceiver

从我所了解的,Android O中广播接收器的限制更多了,但是如果是这样,如果我想要在主活动未运行时启动广播,该如何安排广播呢?

我应该使用服务而不是接收器吗?

以下是AlarmManager的启动代码:

public void Schedule(String aID, String aTitle, String aBody, int aNotificationCode, long aEpochTime)
{
    Bundle lExtras = new Bundle();
    lExtras.putInt("icon", f.getDefaultIcon());
    lExtras.putString("title", aTitle);
    lExtras.putString("message", aBody);
    lExtras.putString("id", aID);
    lExtras.putInt("requestcode", aNotificationCode);

    Intent lIntent = 
      new Intent(LocalNotificationScheduler.ACTION_NAME)
      .addCategory(NotificationsUtils.LocalNotifCategory)
      .putExtras(lExtras);

    PendingIntent lPendIntent = PendingIntent.getBroadcast(f.getApplicationContext(), aNotificationCode,
                                                           lIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    AlarmManager lAlarmMgr = (AlarmManager) f.getSystemService(Context.ALARM_SERVICE);
    lAlarmMgr.set(AlarmManager.RTC, 1000, lPendIntent);
}

这是接收方的代码:

public class LocalNotificationReceiver extends BroadcastReceiver {

public static native void   nativeReceiveLocalNotification (String aID, String aTitle, String aMessage, boolean aOnForeground );

/** This method receives the alarms set by LocalNotificationScheduler,
*   notifies the CAndroidNotifications c++ class, and (if needed) ships a notification banner 
*/
@Override
public void onReceive(Context aContext, Intent aIntent)
{
    Toast.makeText(context, text, duration).show();
}

}

Android清单文件:

<receiver android:name="com.category.localnotifications.LocalNotificationReceiver">
        <intent-filter>
            <action android:name="${applicationId}.action.LOCAL_NOTIFICATION" />
            <category android:name="com.category.LocalNotification" />
        </intent-filter>
    </receiver>

请查看 Oreo 指南,后台服务已被移除。请使用作业调度程序或在应用程序在前台时执行任务。 - Mayank Bhatnagar
1
是的,但我希望在一段时间后即使主要活动未运行,也能像之前一样接收通知。这可能吗? - Hug
2
你能否尝试显式地启动intent,就像https://gist.github.com/yccheok/d39b434470a4135104efae76ec75afc2中所示的那样? - Cheok Yan Cheng
4个回答

23

Android O至今仍相对较新,因此我会尽力消化并提供尽可能准确的信息。

来源:https://developer.android.com/about/versions/oreo/background.html#broadcasts

  • 针对Android 8.0或更高版本的应用程序不能再在其清单文件中注册隐式广播接收器。
    • 应用程序可以在运行时使用Context.registerReceiver()来注册接收器以接收任何广播,无论是隐式还是显式。
  • 应用程序仍然可以在其清单文件中注册显式广播。

此外,在https://developer.android.com/training/scheduling/alarms.html中,示例使用显式广播,并未提及任何有关Android O的特别内容。


我建议您尝试使用以下显式广播:

public static void startAlarmBroadcastReceiver(Context context, long delay) {
    Intent _intent = new Intent(context, AlarmBroadcastReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, _intent, 0);
    AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    // Remove any previous pending intent.
    alarmManager.cancel(pendingIntent);
    alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, pendingIntent);        
}

AlarmBroadcastReceiver

public class AlarmBroadcastReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
    }

}

AndroidManifest中,只需将类定义为:

<receiver android:name="org.yccheok.AlarmBroadcastReceiver" >
</receiver>

6
请将这句话“Apps that target Android 8.0 or higher can no longer register broadcast receivers for implicit broadcasts”改为“针对Android 8.0或更高版本的应用程序不再能够在应用程序清单中静态注册隐式广播接收器来接收广播”,因为根据Android文档,即使是隐式或显式广播,仍允许使用Context.registerReceiver()在运行时注册广播接收器。请参考https://developer.android.com/about/versions/oreo/background.html#broadcasts。 - Sudhanshu Gaur

6

今天我遇到了相同的问题,我的通知无法正常工作。我以为是在Oreo闹钟管理器不起作用,但问题其实出在了通知上。在Oreo中,我们需要添加Channel id。请看我的新代码:

int notifyID = 1; 
String CHANNEL_ID = "your_name";// The id of the channel. 
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
// Create a notification and set the notification channel.
Notification notification = new Notification.Builder(HomeActivity.this)
            .setContentTitle("Your title")
            .setContentText("Your message")
            .setSmallIcon(R.drawable.notification)
            .setChannelId(CHANNEL_ID)
            .build();

请查看这个解决方案,它效果很好。

https://dev59.com/SVgQ5IYBdhLWcg3wORdJ#43093261

我展示了我的方法:

public static void pendingListNotification(Context context, String totalCount) {
        String CHANNEL_ID = "your_name";// The id of the channel.
        CharSequence name = context.getResources().getString(R.string.app_name);// The user-visible name of the channel.
        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationCompat.Builder mBuilder;

        Intent notificationIntent = new Intent(context, HomeActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString(AppConstant.PENDING_NOTIFICATION, AppConstant.TRUE);//PENDING_NOTIFICATION TRUE
        notificationIntent.putExtras(bundle);

        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);

        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (android.os.Build.VERSION.SDK_INT >= 26) {
            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
            mNotificationManager.createNotificationChannel(mChannel);
            mBuilder = new NotificationCompat.Builder(context)
//                .setContentText("4")
                    .setSmallIcon(R.mipmap.logo)
                    .setPriority(Notification.PRIORITY_HIGH)
                    .setLights(Color.RED, 300, 300)
                    .setChannelId(CHANNEL_ID)
                    .setContentTitle(context.getResources().getString(R.string.yankee));
        } else {
            mBuilder = new NotificationCompat.Builder(context)
//                .setContentText("4")
                    .setSmallIcon(R.mipmap.logo)
                    .setPriority(Notification.PRIORITY_HIGH)
                    .setLights(Color.RED, 300, 300)
                    .setContentTitle(context.getResources().getString(R.string.yankee));
        }

        mBuilder.setContentIntent(contentIntent);

        int defaults = 0;
        defaults = defaults | Notification.DEFAULT_LIGHTS;
        defaults = defaults | Notification.DEFAULT_VIBRATE;
        defaults = defaults | Notification.DEFAULT_SOUND;

        mBuilder.setDefaults(defaults);
        mBuilder.setContentText(context.getResources().getString(R.string.you_have) + " " + totalCount + " " + context.getResources().getString(R.string.new_pending_delivery));//You have new pending delivery.
        mBuilder.setAutoCancel(true);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

3

通过定义显式意图(明确定义广播接收器的类名)来创建AlarmManager:

private static PendingIntent getReminderReceiverIntent(Context context) {
    Intent intent = new Intent("your_package_name.ReminderReceiver");
    // create an explicit intent by defining a class
    intent.setClass(context, ReminderReceiver.class);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    return pendingIntent;
}

在创建实际通知时,不要忘记为Android Oreo(API 26)创建通知渠道:

NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
    notificationManager.createNotificationChannel(NotificationFactory.createNotificationChannel(context));
} else {
    notificationManager.notify(NotificationsHelper.NOTIFICATION_ID_REMINDER, notificationBuilder.build());
}

1
尝试使用以下代码适用于Android O 8.1:
Intent nIntent = new Intent("android.media.action.DISPLAY_NOTIFICATION");
        nIntent.addCategory("android.intent.category.DEFAULT");
        nIntent.putExtra("message", "test");
        nIntent.setClass(this, AlarmReceiver.class);

PendingIntent broadcast = PendingIntent.getBroadcast(getAppContext(), 100, nIntent, PendingIntent.FLAG_UPDATE_CURRENT);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接