在即时通讯应用中,实时位置共享功能是一个常见需求。
本文基于环信 IM SDK,手把手教大家实现低延迟、高可用的实时位置共享功能,助你快速实现需求开发。

方案描述

实时位置共享允许用户聊天时向对方持续发送自己的当前位置,对方可在地图上实时查看其位置变化。

技术原理

实时位置共享基于环信 SDK 的 透传消息消息类型 机制实现,实现流程如下:

在这里插入图片描述

  1. 位置采集与发送:用户 A 开启位置共享,实时监听自己的位置变化,同时在坐标变化时向用户 B 发送一条带有坐标的透传信息。

  2. 消息接收与解析:用户 B 在线时会实时收到透传消息,解析消息中的位置数据后,在地图界面上更新用户 A 的位置标记。

透传消息是一种特殊类型消息,收发双方不会存数据库。在本方案中,透传消息只发送给在线用户。

实现过程

本文以Android端代码为例,其他端请访问环信文档。

准备工作

发送位置信息的透传消息

当地理位置发生变化时,调用以下方法发送包含位置信息的透传消息:

// toChatUsername 为当前聊天对象的环信用户 ID(需要根据实际业务逻辑获取)private void sendLocationMessage(double latitude, double longitude) {
    String action = "share_location";
    EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD);
    EMCmdMessageBody cmdBody = new EMCmdMessageBody(action);
    // 将该透传消息只发送给在线用户
    cmdBody.deliverOnlineOnly(true);
    
    cmdMsg.addBody(cmdBody);
    // 设置接收方为当前聊天对象
    cmdMsg.setTo(toChatUsername);
    cmdMsg.setChatType(EMMessage.ChatType.Chat);

    // 使用 JSONObject 封装位置数据
    JSONObject locationData = new JSONObject();
    try {
        locationData.put("latitude", latitude);
        locationData.put("longitude", longitude);
    } catch (JSONException e) {
        e.printStackTrace();
    }
    // 将位置数据放入扩展字段
    cmdMsg.setAttribute("location", locationData.toString());

    EMClient.getInstance().chatManager().sendMessage(cmdMsg);}

接收并解析透传消息

接收透传消息包括接收在线透传消息和接收离线透传消息。

鉴于位置共享的实时性,这里只处理在线时收到的共享位置。收到透传消息后,解析位置信息并在地图上显示。

EMMessageListener msgListener = new EMMessageListener() {
    @Override
    public void onCmdMessageReceived(List<EMMessage> messages) {
        for (EMMessage message : messages) {
            EMCmdMessageBody cmdBody = (EMCmdMessageBody) message.getBody();
            String action = cmdBody.action();
            if ("share_location".equals(action)) {
                // 获取扩展属性,需要处理异常或使用带默认值的方法
                String locationStr = message.getStringAttribute("location", null);
                if (locationStr != null) {
                    try {
                        JSONObject locationData = new JSONObject(locationStr);
                        double latitude = locationData.getDouble("latitude");
                        double longitude = locationData.getDouble("longitude");
                        
                        // 在主线程更新 UI,例如在地图上显示位置
                        runOnUiThread(() -> {
                            // 更新地图位置标记
                        });
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // 其他回调方法...
    @Override
    public void onMessageReceived(List<EMMessage> messages) {}
    @Override
    public void onMessageRead(List<EMMessage> messages) {}
    @Override
    public void onMessageDelivered(List<EMMessage> messages) {}
    @Override
    public void onMessageRecalledWithExt(List<EMRecallMessageInfo> recallMessageInfo) {}
    @Override
    public void onMessageChanged(EMMessage message, Object change) {}};EMClient.getInstance().chatManager().addMessageListener(msgListener);

注意事项

为避免内存泄漏,务必在 Activity 销毁时移除已注册的监听器。

// 在 Activity 中@Overrideprotected void onDestroy() {
   
    // 移除消息监听器
    if (msgListener != null) {
        EMClient.getInstance().chatManager().removeMessageListener(msgListener);
    }
     super.onDestroy();}

本次基于环信SDK的实战开发,我们实现了实时位置共享功能。如遇到其他问题,请至 环信官网 联系技术支持咨询。

参考文档: