如何实现类似WhatsApp蓝色勾选标记的消息阅读状态?

12
我正在开发一个应用程序,其中聊天是其中一个模块,为了聊天,我正在使用XMPP。 当我发送消息时,我会使用DeliveryReceiptManager获取该消息的传递状态。
DeliveryReceiptManager.getInstanceFor(connection).enableAutoReceipts();
DeliveryReceiptManager.getInstanceFor(connection).addReceiptReceivedListener(new ReceiptReceivedListener()
{
        @Override
        public void onReceiptReceived(String arg0, String arg1, String arg2)
        {
            Log.v("app", arg0 + ", " + arg1 + ", " + arg2);
        }
});

但我需要展示消息是否已被用户阅读,就像 WhatsApp 的蓝色勾号一样,有谁能帮助我,我在这里被卡住了。该如何实现这个消息已读的概念。

先行致谢。

3个回答

22

创建自定义数据包扩展类

public class ReadReceipt implements PacketExtension
{

public static final String NAMESPACE = "urn:xmpp:read";
public static final String ELEMENT = "read";

private String id; /// original ID of the delivered message

public ReadReceipt(String id)
{
    this.id = id;
}

public String getId()
{
    return id;
}

@Override
public String getElementName()
{
    return ELEMENT;
}

@Override
public String getNamespace()
{
    return NAMESPACE;
}

@Override
public String toXML()
{
    return "<read xmlns='" + NAMESPACE + "' id='" + id + "'/>";
}

public static class Provider extends EmbeddedExtensionProvider
{
    @Override
    protected PacketExtension createReturnExtension(String currentElement, String currentNamespace,
            Map<String, String> attributeMap, List<? extends PacketExtension> content)
    {
        return new ReadReceipt(attributeMap.get("id"));
    }
}
}

当进入聊天列表时,发送与该数据包ID相同的消息标签,如下所示。
Message message = new Message(userJid);
ReadReceipt read = new ReadReceipt(messagePacketID);
message.addExtension(read);
mConnection.sendPacket(sendReadStatus);

mConnection是xmmppConnection对象

向消息对象添加数据包扩展

在连接到服务器之前,将此扩展提供程序添加到ProviderManager中

ProviderManager.getInstance().addExtensionProvider(ReadReceipt.ELEMENT, ReadReceipt.NAMESPACE, new ReadReceipt.Provider());

创建packetListener类以接收接收者的阅读回执。
public class ReadReceiptManager implements PacketListener
    {



  private static Map<Connection, ReadReceiptManager> instances = Collections.synchronizedMap(new WeakHashMap<Connection, ReadReceiptManager>());
    static 
    {
        Connection.addConnectionCreationListener(new ConnectionCreationListener() 
        {
            public void connectionCreated(Connection connection) 
            {
                getInstanceFor(connection);
            }
        });
    }

private Set<ReceiptReceivedListener> receiptReceivedListeners = Collections.synchronizedSet(new HashSet<ReceiptReceivedListener>());

private ReadReceiptManager(Connection connection) 
{
    ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
    sdm.addFeature(ReadReceipt.NAMESPACE);
    instances.put(connection, this);

    connection.addPacketListener(this, new PacketExtensionFilter(ReadReceipt.NAMESPACE));
}

 public static synchronized ReadReceiptManager getInstanceFor(Connection connection) 
 {
    ReadReceiptManager receiptManager = instances.get(connection);

    if (receiptManager == null) 
    {
        receiptManager = new ReadReceiptManager(connection);
    }

    return receiptManager;
}

@Override
public void processPacket(Packet packet) 
{
    ReadReceipt dr = (ReadReceipt)packet.getExtension(ReadReceipt.ELEMENT, ReadReceipt.NAMESPACE);

    if (dr != null) 
    {
        for (ReceiptReceivedListener l : receiptReceivedListeners) 
        {
            l.onReceiptReceived(packet.getFrom(), packet.getTo(), dr.getId());
        }
    }
}

public void addReadReceivedListener(ReceiptReceivedListener listener) {
    receiptReceivedListeners.add(listener);
}

public void removeRemoveReceivedListener(ReceiptReceivedListener listener) {
    receiptReceivedListeners.remove(listener);
  }
 }

最后,将监听器添加到您的XMPP连接对象中,它会成功运行。

            ReadReceiptReceivedListener readListener = new ReadReceiptReceivedListener()
                {
                    @Override
                    public void onReceiptReceived(String fromJid, String toJid, String packetId) 
                    {
                        Log.i("Read", "Message Read Successfully");
                    }
                };  
                ReadReceiptManager.getInstanceFor(connection).addReadReceivedListener(readListener);

1
嗨@SRK...在哪里添加Message message = new Message(userJid)?ReadReceipt read = new ReadReceipt(messagePacketID); message.addExtension(read); mConnection.sendPacket(sendReadStatus)。 - BMM
1
@SRK,你能告诉我sendReadStatus是什么吗? - chhameed
ReadReceiptReceivedListener是一个自定义的包监听器类,它接收阅读状态。 - Rakesh Kalashetti
我在我的连接中使用了这个例子,奇怪的是,通过添加这个监听器,我不能再发送消息了,但我仍然可以接收消息。有人知道是什么原因导致了这种行为吗?也许是ProviderManager引起的? - Opiatefuchs
我的假设是,通过像您的示例中添加ProviderManager扩展提供程序,它必须覆盖设置中的某些内容。如果我在家里并检查出了问题,我会尝试一下。如果不是我的错误,我将发布如何避免这个问题的方法。 - Opiatefuchs
显示剩余22条评论

1

1
xep-0022已被XMPP标准基金会废弃。不建议实现此处描述的协议。建议希望实现类似功能的开发人员实现取代它的协议(XEP-0085,XEP-0184)。 - Shubham AgaRwal

0
创建一个带有不同属性的消息,指示它是已读回执,在接收者阅读消息时发送。在发送方端,当您收到带有已读回执属性的消息时,请将该消息标记为已读,显示两个蓝色勾号。
<message id='xxxxx' from='xxxxxxxx' to='xxxxxxxxx'>
<status_id>101</status_id>
</message>

在这里,status_id=101,我已经使用了发送阅读回执的功能,这将在接收端进行识别。


消息 msg = new Message(); msg.setFrom(arg0); msg.setTo(arg0); msg.setPacketID(arg0) connection.sendPacket(msg); 如何将状态 ID 设置为此消息,因为没有像状态这样的标记。 - NareshRavva
你需要修改消息类以保存status_id标签。你可以在Message类中添加statusId的setter和getter方法,并修改Message类中的toXml()方法。同时,还需要修改PacketParseUtils类以解析status_id并使用setter将其设置为消息状态id。当你在代码中使用时,在发送已读回执时,请使用statusId的setter方法进行设置。 - Iqbal S
1
你不需要修改消息类,只需添加自定义元素的扩展即可。Smack被设计为可以通过这种方式进行扩展。 - Robin
我同意Robin的观点,这就是我的意思。 - Iqbal S

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