适用于 Android 的 Azure 通知中心:如何使用后台服务处理数据消息?
Posted
技术标签:
【中文标题】适用于 Android 的 Azure 通知中心:如何使用后台服务处理数据消息?【英文标题】:Azure Notification Hubs for Android: How do I handle Data-Messages with a Background-Service? 【发布时间】:2021-09-29 20:23:06 【问题描述】:我正在尝试制作一个能够处理 Azure 通知中心发送的(数据)消息的应用程序。在当前状态下,它会在 Azure 接收有效负载时发送通知。当应用程序在前台运行(或仍在快速面板中打开)时,它完全没有问题,onPushNotificationReceived()
处理传入的消息很好,但是当从快速面板中删除应用程序时,我尝试调用空对象引用:
Logcat
2021-07-22 15:27:33.675 23017-23053/com.example.fcmtutorial1app E/androidRuntime: FATAL EXCEPTION: Firebase-Messaging-Intent-Handle
Process: com.example.fcmtutorial1app, PID: 23017
java.lang.NullPointerException: Attempt to invoke interface method 'void com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener.onPushNotificationReceived(android.content.Context, com.google.firebase.messaging.RemoteMessage)' on a null object reference
at com.microsoft.windowsazure.messaging.notificationhubs.FirebaseReceiver.onMessageReceived(FirebaseReceiver.java:52)
at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage(com.google.firebase:firebase-messaging@@22.0.0:13)
at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk(com.google.firebase:firebase-messaging@@22.0.0:8)
at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent(com.google.firebase:firebase-messaging@@22.0.0:3)
at com.google.firebase.messaging.FirebaseMessagingService.handleIntent(com.google.firebase:firebase-messaging@@22.0.0:3)
at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService(com.google.firebase:firebase-messaging@@22.0.0:1)
at com.google.firebase.messaging.EnhancedIntentService$$Lambda$0.run(Unknown Source:6)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:6)
at java.lang.Thread.run(Thread.java:923)
这仅在发送数据消息时发生,因为 Firebase 服务处理带有通知负载的消息而不调用 onPushNotificationReceived()
。
我已尝试以下方法来解决此问题:
使用 android.app.Service 扩展 CustomNotificationListener.class 将 onPushNotificationReceived() 替换为 Thunderbirds onMessageReceived()第一个解决方案导致相同的错误,而第二个解决方案根本没有任何消息。
如果有人有办法解决这个问题或知道可能是什么问题,如果你能写一个答案,我会非常高兴:)
这是两个类的代码(android.app.Service 仍然包括在内,尽管它对我不起作用)。提前致谢!
MainActivity.class
package com.example.fcmtutorial1app;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import com.microsoft.windowsazure.messaging.notificationhubs.NotificationHub;
public class MainActivity extends AppCompatActivity
public static final String CHANNEL_1_ID = "Channel1";
public static final String CHANNEL_2_ID = "Channel2";
public static String editTextTitle;
public static String editTextMessage;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createNotificationsChannels();
NotificationHub.setListener(new CustomNotificationListener());
NotificationHub.start(this.getApplication(), "spfcmtutorial1nhub", "Endpoint=sb://azurecloudmessaging.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=abc[...]xyz");
public static void sendCloudMessage(Context context)
editTextTitle = CustomNotificationListener.title;
editTextMessage = CustomNotificationListener.body;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(editTextTitle)
.setContentText(editTextMessage)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notificationBuilder.build());
Log.v("MSG", "SENDCLOUDMESSAGE WAS ACTIVATED");
public void createNotificationsChannels() //Channel 2 is for tests only
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
NotificationChannel channel1 = new NotificationChannel(
CHANNEL_1_ID,
"Channel 1",
NotificationManager.IMPORTANCE_HIGH
);
channel1.setDescription("This is Channel 1");
NotificationChannel channel2 = new NotificationChannel(
CHANNEL_2_ID,
"Channel 2",
NotificationManager.IMPORTANCE_LOW
);
channel2.setDescription("This is Channel 2");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel1);
manager.createNotificationChannel(channel2);
CustomNotificationListener.class
package com.example.fcmtutorial1app;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import com.google.firebase.messaging.RemoteMessage;
import com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener;
import java.util.Map;
public class CustomNotificationListener extends Service implements NotificationListener
private static final String TAG = "Message";
public static String title;
public static String body;
public static String dataTitle;
public static String dataBody;
@Override
public int onStartCommand(Intent intent, int flags, int startId)
Log.d(TAG, "Service started");
return Service.START_NOT_STICKY;
@Override
public void onPushNotificationReceived(Context context, RemoteMessage message) //FATAL EXEPTION: Firebase-Messaging-Intent-Handle HERE
RemoteMessage.Notification notification = message.getNotification();
try title = notification.getTitle(); catch(Exception e)
try body = notification.getBody(); catch (Exception e)
Map<String, String> data = message.getData();
//region LOGGING
if (message != null)
Log.d(TAG, "Message Notification Title: " + title);
Log.d(TAG, "Message Notification Body: " + body);
else Log.e(TAG, "ERROR, no message found");
if (data != null)
for (Map.Entry<String, String> entry : data.entrySet())
Log.d(TAG, "key, " + entry.getKey() + "value " + entry.getValue());
else Log.e(TAG, "ERROR, no data found");
//endregion
Log.v("VERBOSE", data.get("property1"));
MainActivity.sendCloudMessage(context);
@Nullable
@Override
public IBinder onBind(Intent intent)
return null;
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.fcmtutorial1app">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FCMTutorial1App">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".CustomNotificationListener"></service>
</application>
</manifest>
【问题讨论】:
【参考方案1】:要回答这个问题,我们需要讨论https://developer.android.com 中记录的一些 Android 生命周期概念:
Process and Application Lifecycle Activity Lifecycle在上面提供的代码中,您在应用程序的主入口点MainActivity
中调用NotificationHub.setListener
。如您所见,这在您的最终用户手动启动应用程序时有效,因为 MainActivity.onCreate
被调用。
但是,您的场景中有第二个入口点:FirebaseMessagingService
在后台收到纯数据通知时启动应用程序。这是微妙且容易错过的——因为如果有效负载包含notification
组件,当在系统托盘中单击通知时,Android 仍会路由到MainActivity
。
在这种情况下,MainActivity
不涉及,所以 MainActivity.onCreate
和 NotificationHub.setListener
在应用程序初始化时永远不会被调用,following line from the stack trace 遇到空引用:
mHub.getInstanceListener().onPushNotificationReceived(this.getApplicationContext(), remoteMessage);
要解决此问题,无论入口点如何,您都需要在应用程序初始化时调用的某个地方调用 NotificationHub.setListener
。
最自然的选择是通过扩展 android.app.Application
、覆盖 onCreate()
method 和 updating your manifest 在应用程序级别设置 NotificationHub。
【讨论】:
谢谢!创建一个新类并对其进行扩展非常有效^^ 我很高兴!谢谢你告诉我。 @MarStr 我按照您说的进行了配置,现在可以使用。但这会导致另一个问题。+ I use azure notification hub for android sdk v1.1.6 + I use firebase Data message + I set azure listener on Application onCreate()
但是当我关闭手机屏幕大约15-20分钟时,我发送了一条数据消息,并且没有推送到我的手机。我认为在使用数据消息时,Azure 集线器需要保留一个服务来监听 Firebase 推送,但是当手机离屏时间过长时,该服务会被终止。我说得对吗,@MarStr?请帮我检查一下。非常感谢。以上是关于适用于 Android 的 Azure 通知中心:如何使用后台服务处理数据消息?的主要内容,如果未能解决你的问题,请参考以下文章
Azure 通知中心:SendTemplateNotificationAsync 是不是适用于 .net Core
将数据负载添加到 Xamarin 推送通知(GFB 和 Azure 通知中心)
适用于 chrome、firefox 和 safari 浏览器的 Azure 浏览器推送通知