【问题标题】:How to block a notification that comes through based on a SharedPreferences value?如何阻止基于 SharedPreferences 值的通知?
【发布时间】:2020-03-15 22:00:32
【问题描述】:

我有一个 SharedPreference:sharedPref.getBoolean("online", false)

如果我在online 为假时收到通知,我想阻止它。如果用户离线,通常不会有通知,但我偶尔会收到通知,我希望将此作为备份以防止通知。

通知是通过Firebase Cloud Messaging (FCM) 发送的,这是我的应用程序中的处理方式:

class CustomApplication : Application() {

    val MATCH_CHANNEL_ID = "MATCH_CHANNEL"

    companion object {
        var database: AppDatabase? = null
    }

    override fun onCreate() {
        super.onCreate()
        val settings: FirebaseFirestoreSettings = FirebaseFirestoreSettings.Builder().setPersistenceEnabled(false).build()
        FirebaseFirestore.getInstance().firestoreSettings = settings
        CustomApplication.database = Room.databaseBuilder(this, AppDatabase::class.java, "AppDatabase").build()
        createNotificationChannel()
    }

    private fun createNotificationChannel(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            val matchChannel = NotificationChannel(MATCH_CHANNEL_ID, "Nearby matches", NotificationManager.IMPORTANCE_HIGH)
            matchChannel.description = "Nearby matches"
            val manager: NotificationManager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(matchChannel)
        }
    }
}

如果 online 在 SharedPreferences 中为 false,我有什么办法可以阻止通知进入?

编辑:

当我在后台收到通知 FCM 时,它会调用 . FirebaseMessagingService.onCreate():

class CustomFirebaseMessagingService : FirebaseMessagingService() {

    val db = FirebaseFirestore.getInstance()

    override fun onCreate() {
        Log.d(TAG, "CustomFirebaseMessagingService onCreate()")
        return
        super.onCreate()
    } 

我已经覆盖 onCreate() 以在 super.onCreate() 之前返回 - 希望取消通知。但是,通知仍然会触发。

CustomFirebaseMessagingService() 中是否有另一个函数可以覆盖来拦截通知并取消它?

【问题讨论】:

  • 你可以将通知管理器放在 if 语句中
  • 怎么样? manager.createNotificationChannel(matchChannel) 不只是创建通知通道而不处理未来的通知吗?
  • 您是否使用了扩展 FirebaseMessagingService 的服务?
  • @Zorgan createNotificationChannel 仅在应用程序的通知设置中创建用户可以自定义的Channel(系统也是),但是创建通知是一个不同的过程,您可以按照建议找到它FirebaseMessagingService 中的其他
  • 设置标志并检查它是否来自firebase或共享首选项..

标签: android firebase kotlin firebase-cloud-messaging


【解决方案1】:

查看你的清单文件会有这样的服务

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

然后转到MyFirebaseMessagingService.java 文件并检查您的共享偏好值并设置通知条件。试试这个..

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

    boolean flag = sharedPref.getBoolean("online", false);

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {

          if(flag){
             //TODO write your code here to set notification and notify
          }

    }

} 

【讨论】:

  • onMessageReceived() 仅在应用程序内部被调用 - 我需要在后台阻止通知。
【解决方案2】:
    <service
        android:name=".fcm.FCMService"
        android:enabled="true"
        android:exported="false"
        android:stopWithTask="false"> 
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

没有很好的文档记录,但将其设置为 false 将保持服务处于活动状态,即使应用程序处于后台或停止状态 https://developer.android.com/reference/android/R.attr.html#stopWithTask

通过这种方式,您可以按照上一张海报的建议处理 on msg received 方法中的阻塞

 NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_QA_ID)
            .setSmallIcon(R.drawable.icon_notif)
            .setColor(getResources().getColor(R.color.primary))
            .setContentTitle(title)
            .setContentText(text)
            .setAutoCancel(true)
            .setStyle(new NotificationCompat.BigTextStyle()
               .bigText(text)
            );

    Intent intent = new Intent(getApplicationContext(), LauncherActivty.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

    //use the bundled url if it is there and we have more then 1 notification for this type
    if(amount > 1 && !bundledURL.equals("")){
        intent.putExtra("url", bundledURL);
    }else{
        intent.putExtra("url", url);
    }

    intent.putExtra("notification_group", notificationGroup);
    intent.putExtra("notification_group_id", notificationGroupID);
    intent.putExtra("notification_id", notificationID);
    intent.putExtra("is_group", isGroup);

    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    notificationBuilder.setContentIntent(pendingIntent);
    NotificationManager notificationManager =  (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(notificationGroup, Constants.NOTIFICATION_ID, notificationBuilder.build());

【讨论】:

  • 我刚刚添加了android:stopWithTask="false",它仍然没有在后台调用onMessagedReceived()
  • hm 好吧,这很奇怪,因为对于我的项目,它可以工作,我在 FCMService 中手动创建所有通知,并且它在应用程序处于后台并完全关闭时都可以工作。你在测试之前删除了创建中的return语句吗?
  • 是的,我删除了 return 声明。你是什​​么意思你手动创建了通知?我通过 Cloud Functions 创建了我的
  • 我创建的所有通知都是在收到的 msg 中完成的,基本上我只从 fcm 获取数据“推送”通知,然后使用构建器创建通知:将通知的实际创建放入 main可读性的答案;)
【解决方案3】:

如果我正确理解了您的问题,那么您所说的是在您的应用未运行时收到推送消息的情况。您提到 onMessageReceived() 仅在您的应用程序处于运行状态时被调用,但即使系统未调用此方法,您的通知也会显示。因此,我们可以得出结论,这些通知是系统自动绘制的。此行为由 FCM 消息正文中的“通知”和“数据”部分控制。

FCM 消息有一个复杂的规范,可以在 here 找到。但由于我们只对“通知”和“数据”部分感兴趣,我们可以依赖它们的行为:

第一种情况 - “通知”和“数据”部分都存在

例子:

{
  "message":{
    "notification": { /*...*/ },
    "data": {/*...*/}
  }
}

在这种情况下,如果您的应用处于后台状态,

  • 系统会自动显示通知;
  • 如果点击此通知,将启动一个活动;
  • 活动的意图将包含“数据”正文和有关 FCM 消息的一些技术信息。

第二种情况 - 仅存在“通知”部分

例子:

{
  "message":{
    "notification": { /*...*/ },
  }
}

在这种情况下,如果您的应用处于后台状态,

  • 系统会自动显示通知;
  • 如果点击此通知,将启动一个活动;
  • 活动的意图将包含有关 FCM 消息的技术信息。

第三种情况 - 仅存在“数据”部分

例子:

{
  "message":{
    "data": {/*...*/}
  }
}

在这种情况下,如果您的应用处于后台状态,

  • 系统不会自动显示通知;
  • onMessageReceived() 将被调用。

因此,在查看了这些信息之后,您可以尝试更改 FCM 消息的正文(即丢弃“通知”部分)以禁止系统自行处理绘图通知。

onMessageReceived()每次处理您的消息,您可以将带有该标志的逻辑放在那里。

【讨论】:

  • 谢谢,这解释得很好。但是,我希望禁用基于本地数据(SharedPreferences 数据)而不是 FCM 正文的通知。
  • 这样做您将在Service 中收到所有推送消息,并且您将能够应用您的逻辑。问题是修改消息的结构将使您能够自行控制所有内容,而不是让系统自动执行某些操作。现在您的问题存在,因为当应用程序离线时系统会自行显示这些通知。通过抛出消息的“通知”部分,您将告诉系统您要自己处理推送消息(即显示通知)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
相关资源
最近更新 更多