You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Smack 4.2中注册设备令牌?实现离线/后台推送通知

嘿,我来帮你搞定Smack 4.2里的设备令牌注册,同时实现你要的两种通知场景——离线/应用终止时的推送,以及后台在线时通过IQ获取通知。

在Smack 4.2中注册设备令牌并实现双场景通知

一、注册设备令牌到Ejabberd服务器

首先得把设备的推送令牌(比如FCM/APNs令牌)通过Smack传给Ejabberd,让服务器知道该设备的推送通道。这里我们用自定义IQ请求来实现,适配Ejabberd的处理逻辑。

步骤1:定义自定义IQ类封装令牌数据

public class PushTokenIQ extends IQ {
    public static final String ELEMENT = "push-token";
    public static final String NAMESPACE = "urn:xmpp:push:token";

    private String token;
    private String platform; // 标记是"fcm"还是"apns"

    public PushTokenIQ() {
        super(ELEMENT, NAMESPACE);
    }

    @Override
    protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
        xml.rightAngleBracket();
        xml.element("token", token);
        xml.element("platform", platform);
        return xml;
    }

    // Getter & Setter
    public String getToken() { return token; }
    public void setToken(String token) { this.token = token; }
    public String getPlatform() { return platform; }
    public void setPlatform(String platform) { this.platform = platform; }
}

步骤2:连接成功后发送令牌到服务器

// 假设你已经通过FCM获取到了设备令牌
String fcmDeviceToken = "你的FCM令牌字符串";

PushTokenIQ pushTokenIQ = new PushTokenIQ();
pushTokenIQ.setType(IQ.Type.set);
pushTokenIQ.setTo("你的ejabberd服务器域名"); // 比如"your-server.com"
pushTokenIQ.setToken(fcmDeviceToken);
pushTokenIQ.setPlatform("fcm");

// 获取已建立的Smack连接
AbstractXMPPConnection xmppConnection = getYourActiveSmackConnection();
// 发送IQ并监听结果
xmppConnection.sendIqWithResponseCallback(pushTokenIQ, 
    stanza -> {
        IQ response = (IQ) stanza;
        if (response.getType() == IQ.Type.result) {
            Log.d("SmackPush", "设备令牌注册成功!");
        } else {
            Log.e("SmackPush", "令牌注册失败: " + response.getError().getMessage());
        }
    },
    exception -> Log.e("SmackPush", "发送令牌出错: " + exception.getMessage())
);

二、实现离线/应用终止时的推送通知

当设备离线或应用被杀死时,Ejabberd需要把离线消息转发到你的推送服务(比如FCM)。这一步需要在Ejabberd服务器上配置推送模块,同时客户端处理推送回调。

服务器端配置(Ejabberd.yml)

确保启用推送相关模块,并配置FCM/APNs的服务信息:

modules:
  mod_push: {}
  mod_push_keepalive: {}
  mod_offline:
    store_messages: true
    push_notifications: true # 开启离线消息转推送

mod_push:
  backend: ejabberd_push
  push_service:
    fcm:
      api_key: "你的FCM服务器密钥"
      endpoint: "https://fcm.googleapis.com/fcm/send"

客户端处理FCM推送

在Android的FirebaseMessagingService中接收并展示通知:

public class MyFirebaseMsgService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Map<String, String> pushData = remoteMessage.getData();
        String sender = pushData.get("from");
        String msgContent = pushData.get("body");

        // 构建并显示本地通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "XMPP_PUSH_CHANNEL")
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle("来自" + sender)
                .setContentText(msgContent)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        NotificationManagerCompat.from(this).notify((int) System.currentTimeMillis(), builder.build());
    }
}

三、应用后台时通过IQ获取实时通知

当应用在后台但Smack连接仍活跃时,我们可以监听服务器发送的自定义IQ来获取通知,避免依赖推送延迟。

步骤1:定义IQ监听器处理通知

public class BackgroundNotificationListener implements StanzaListener {
    @Override
    public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException {
        if (!(stanza instanceof IQ)) return;
        
        IQ notificationIQ = (IQ) stanza;
        // 匹配服务器发送的通知IQ的命名空间和元素名
        if (notificationIQ.getType() == IQ.Type.set &&
            "notification".equals(notificationIQ.getChildElementName()) &&
            "urn:xmpp:notification:0".equals(notificationIQ.getChildElementNamespace())) {
            
            // 解析通知内容
            String msgBody = notificationIQ.getChildElement().getFirstChildElement("body").getText();
            String fromUser = notificationIQ.getFrom().toString();
            
            // 在后台显示本地通知
            showBackgroundNotification(fromUser, msgBody);
        }
    }

    private void showBackgroundNotification(String from, String content) {
        // 这里的逻辑和FCM推送的通知构建一致
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "XMPP_IQ_CHANNEL")
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle("后台通知:" + from)
                .setContentText(content)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);
        
        NotificationManagerCompat.from(getApplicationContext()).notify((int) System.currentTimeMillis(), builder.build());
    }
}

步骤2:注册监听器到Smack连接

AbstractXMPPConnection xmppConnection = getYourActiveSmackConnection();
// 添加同步监听器,只监听IQ类型的Stanza
xmppConnection.addSyncStanzaListener(new BackgroundNotificationListener(), new StanzaTypeFilter(IQ.class));

几个关键注意点

  • 后台要保持Smack连接稳定:可以启用ReconnectionManager自动重连,避免连接断开导致收不到IQ通知。
  • 服务器端的自定义IQ要和客户端匹配:确保命名空间、元素名完全一致,否则监听器会过滤掉消息。
  • 通知渠道要提前创建:Android 8.0+需要先创建通知渠道才能显示通知。

内容的提问来源于stack exchange,提问作者Rajesh Gauswami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:00:41