基本串接

基本串接

概述

本指南将带您完成 IMKIT 的基本串接流程。在完成「快速开始」取得 API Key 和 Chat Server URL 后,您可以透过以下四个步骤,快速建立用户、建立聊天室、开始对谈,并让 web/native app 接收新消息与已读未读通知。


前置条件

请确认您已完成以下准备:

项目说明取得方式
API Key后端 API 认证金钥(IM-API-KEYIMKIT Dashboard
Client Key用户端连线金钥(IM-CLIENT-KEYIMKIT Dashboard
Chat Server URL您的 Chat Server 网址IMKIT Dashboard

步骤一:建立用户

透过 API 为您的系统中的使用者建立 IMKIT 用户,并取得存取权杖(Token)。

POST /admin/clients

Headers

参数类型必填说明
IM-API-KEYstring您的平台 API 金钥
Content-Typestringapplication/json; charset=utf-8

建立用户 A

const axios = require("axios");
 
const BASE_URL = "https://your-app.imkit.io";
const API_KEY = process.env.IM_API_KEY;
 
// 建立用户 A 并取得 Token
const userA = await axios.post(
  `${BASE_URL}/admin/clients`,
  {
    _id: "user-a",
    nickname: "Alice",
    avatarUrl: "https://example.com/alice.jpg",
    issueAccessToken: true,
  },
  {
    headers: {
      "IM-API-KEY": API_KEY,
      "Content-Type": "application/json; charset=utf-8",
    },
  }
);
 
const tokenA = userA.data.result.token;
console.log("用户 A Token:", tokenA);

建立用户 B

// 建立用户 B 并取得 Token
const userB = await axios.post(
  `${BASE_URL}/admin/clients`,
  {
    _id: "user-b",
    nickname: "Bob",
    avatarUrl: "https://example.com/bob.jpg",
    issueAccessToken: true,
  },
  {
    headers: {
      "IM-API-KEY": API_KEY,
      "Content-Type": "application/json; charset=utf-8",
    },
  }
);
 
const tokenB = userB.data.result.token;
console.log("用户 B Token:", tokenB);

回应范例

{
  "RC": 0,
  "RM": "OK",
  "result": {
    "_id": "user-a",
    "nickname": "Alice",
    "avatarUrl": "https://example.com/alice.jpg",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expirationDate": "2026-04-17T00:00:00.000Z",
    "lastLoginTimeMS": 1712700000000
  }
}

请将取得的 Token 安全地传递给前端,供 SDK 或 Web URL 使用。


步骤二:建立聊天室

建立一个聊天室,并将用户 A 和用户 B 加入为成员。

POST /rooms/

Headers

参数类型必填说明
IM-API-KEYstring您的平台 API 金钥
Content-Typestringapplication/json; charset=utf-8

范例请求

// 建立一对一聊天室
const room = await axios.post(
  `${BASE_URL}/rooms/`,
  {
    roomType: "direct",
    members: ["user-a", "user-b"],
  },
  {
    headers: {
      "IM-API-KEY": API_KEY,
      "Content-Type": "application/json; charset=utf-8",
    },
  }
);
 
const roomId = room.data.result._id;
console.log("聊天室 ID:", roomId);

如需建立群组聊天室,将 roomType 改为 "group" 并加入更多成员:

// 建立群组聊天室
const groupRoom = await axios.post(
  `${BASE_URL}/rooms/`,
  {
    name: "专案讨论群",
    roomType: "group",
    members: ["user-a", "user-b", "user-c"],
  },
  {
    headers: {
      "IM-API-KEY": API_KEY,
      "Content-Type": "application/json; charset=utf-8",
    },
  }
);

回应范例

{
  "RC": 0,
  "RM": "OK",
  "result": {
    "_id": "6073a1b2c3d4e5f6a7b8c9d0",
    "roomType": "direct",
    "members": ["user-a", "user-b"],
    "status": 1,
    "createdTimeMS": 1712700000000
  }
}

步骤三:开始对谈

聊天室建立完成后,将用户的 Token 带入 Web URL,即可开始对谈。

使用 Web SDK

在您的网页中嵌入 IMKIT Web SDK,并带入用户的 Token 进行初始化:

<div id="imkit-container"></div>
<script src="https://cdn.imkit.io/sdk/web/latest/imkit.min.js"></script>
<script>
  window.IMKitUI.init({
    domain: "https://your-app.imkit.io",
    clientKey: "您的_CLIENT_KEY",
    token: "用户的_TOKEN",
  });
</script>

使用 Web URL

若您已取得 IMKIT 提供的 Web URL,可直接将用户 Token 作为参数带入:

https://your-app.imkit.io/chat?token=用户的_TOKEN

您可以在自己的应用程式中透过 iframe 或直接导向的方式嵌入此 URL。

完整的 URL 参数列表(指定聊天室、深色模式、自动选择聊天室等),请参考 Web URL 参数


步骤四:接收新消息与已读未读通知

当 Web SDK 或 Web URL 已嵌入您的 app 后,下一步是让外层的 web 容器或 native app也能收到「新消息」与「已读未读」事件,用于更新标题栏未读数、native 推播中心、Tab badge 等 UI。

整体架构:

通道用途触发时机路径
Socket.IO实时事件(chat messagelastReadtypingApp 在前景且网络连接中共用
APNs / FCM 推播(IMKIT 直送)后台通知App 在后台或被终止A
APNs / FCM 推播(自家推播中心转送)后台通知App 在后台或被终止B
PUT /rooms/:id/lastRead主动回报已读用户读完消息时共用
GET /me/badge取总未读数任何时候共用

4-1:Web 端(外层容器)

在外层 web 页面(非 IMKIT chat 页)建立 Socket.IO 连线,接收实时事件。完整生命周期请参考 Socket 连线,事件格式请参考 Socket 事件

<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
<script>
  const socket = io("https://your-app.imkit.io", { forceNew: true });
 
  socket.on("connect", () => {
    // Step 1: 设定编码(建议启用 base64)
    socket.emit("conf", { encoding: "base64" }, () => {
      // Step 2: 身份验证
      socket.emit("auth2", "用户的_TOKEN", { deviceId: "web-tab-uuid" }, (ack) => {
        console.log("[socket] authed", ack);
      });
    });
  });
 
  // 收新消息:更新 tab badge / 显示桌面通知
  socket.on("chat message", (raw) => {
    const msg = decode(raw);
    console.log("新消息:", msg);
    document.title = `(${++unreadCount}) Chat`;
 
    if (Notification.permission === "granted" && document.hidden) {
      new Notification(msg.sender.nickname, { body: msg.message });
    }
  });
 
  // 对方已读:更新已读回条 UI
  socket.on("lastRead", (raw) => {
    const event = decode(raw);
    console.log(`${event.memberID} 已读到 ${event.messageID}`);
    updateReadReceipt(event.roomID, event.memberID, event.messageID);
  });
 
  // 重连后重新验证
  socket.on("reconnect", () => {
    socket.emit("auth2", "用户的_TOKEN", { deviceId: "web-tab-uuid" });
  });
 
  function decode(raw) {
    if (typeof raw !== "string") return raw;
    return JSON.parse(atob(raw));
  }
</script>

当用户读完消息时,呼叫 PUT /rooms/:id/lastRead 同步给后端:

async function markAsRead(roomId, lastMessageId) {
  await fetch(`https://your-app.imkit.io/rooms/${roomId}/lastRead`, {
    method: "PUT",
    headers: {
      "IM-CLIENT-KEY": "您的_CLIENT_KEY",
      "IM-Authorization": "用户的_TOKEN",
      "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify({ message: lastMessageId }),
  });
}

选择推播路径

Native app 的后台推播有两条互斥路径,请依您的现况择一:

路径适用情境对应 API / 设定
A. 使用 IMKIT 内建推播没有自家推播服务,希望最快上线App 呼叫 POST /me/subscribe 注册 device token;IMKIT 自动直送 APNs / FCM
B. 串接自家推播中心已有自家推播中心、IT 规范要求自管 token、需在多通道汇整推播后端设定 PUSH_GENERIC callback;app 端呼叫 /me/subscribe

⚠️ 两条路径互斥。若同时启用(既呼叫 /me/subscribe、又设定 PUSH_GENERIC 并在自家中心送同一份推播),用户会收到重复通知


4-2A:Native App — 使用 IMKIT 内建推播

仅适用路径 A。若您已有自家推播中心,请跳到 4-2B。

Native app 通常以 WebView 嵌入 IMKIT chat 页,外层需另外处理:

  1. 注册推播 token:登入后将 APNs / FCM token 注册到 IMKIT
  2. 前景接收:建立 Socket 连线显示实时 badge / 通知
  3. 后台接收:依靠 IMKIT 直送的 APNs / FCM 推播
  4. 回报已读:用户读完时呼叫 PUT /rooms/:id/lastRead

iOS(Swift)— 注册 APNs token

取得 APNs device token 后,呼叫 POST /me/subscribe

func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let token = deviceToken.map { String(format: "%02x", $0) }.joined()
    let deviceId = UIDevice.current.identifierForVendor?.uuidString ?? ""
 
    var request = URLRequest(url: URL(string: "https://your-app.imkit.io/me/subscribe")!)
    request.httpMethod = "POST"
    request.setValue("您的_CLIENT_KEY", forHTTPHeaderField: "IM-CLIENT-KEY")
    request.setValue(userToken, forHTTPHeaderField: "IM-Authorization")
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: [
        "type": "ios",
        "token": token,
        "deviceId": deviceId
    ])
 
    URLSession.shared.dataTask(with: request).resume()
}

收到推播时,可从 payload 解析消息类型(详见 推播 Payload 格式),跳转到对应聊天室。

Android(Kotlin)— 注册 FCM token

class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onNewToken(fcmToken: String) {
        val deviceId = Settings.Secure.getString(
            contentResolver, Settings.Secure.ANDROID_ID
        )
 
        val body = JSONObject().apply {
            put("type", "fcm")
            put("token", fcmToken)
            put("deviceId", deviceId)
        }.toString()
 
        val request = Request.Builder()
            .url("https://your-app.imkit.io/me/subscribe")
            .addHeader("IM-CLIENT-KEY", "您的_CLIENT_KEY")
            .addHeader("IM-Authorization", userToken)
            .addHeader("Content-Type", "application/json; charset=utf-8")
            .post(body.toRequestBody("application/json".toMediaType()))
            .build()
 
        OkHttpClient().newCall(request).enqueue(/* ... */)
    }
 
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        val locKey = remoteMessage.data["loc-key"]      // e.g. "im_loc_text"
        val locArgs = remoteMessage.data["loc-args"]    // e.g. ["Alice", "Hello"]
        // 依本地化 key 显示通知,跳转到对应聊天室
    }
}

Native Socket(前景实时 badge)

若希望 app 在前景时不依赖推播也能实时更新 badge,可在 native 端建立 Socket 连线,逻辑与 4-1 的 web 示例相同,使用对应平台的 Socket.IO 客户端(socket.io-client-swift / socket.io-client-java)。完整流程请见 Socket 连线

用户登出时取消注册

POST /me/unsubscribe

详见 取消注册装置 Token


4-2B:Native App — 串接自家推播中心

仅适用路径 B。此路径下 app 端不要呼叫 /me/subscribe,沿用自家既有的 device token 注册流程。

流程概览

IMKIT 消息事件
   ↓ (PUSH_GENERIC callback)
您的后端
   ↓ (查 token、计算 badge、组 payload)
您的推播中心
   ↓ (APNs / FCM)
用户 device

步骤 1:在 IMKIT 后台设定环境变量

PUSH_GENERIC=https://your-server.example.com/imkit/push/v2

设定完成后,凡是有推播需求的消息事件,IMKIT 会以单一 HTTP POST 将「压平后的消息物件 + pushToClients 收件者数组」发送到此 URL。

完整字段请见 外部推播服务 v2

步骤 2:实作 callback handler

以下为 Node.js + Express 示例,示范如何接收 IMKIT 事件并转送给自家推播中心:

import express from "express";
const app = express();
app.use(express.json());
 
app.post("/imkit/push/v2", async (req, res) => {
  const {
    _id: messageId,
    message,
    room,
    roomName,
    sender,
    messageType,
    pushToClients = [],
  } = req.body;
 
  // 1. 对每位收件者并行处理
  await Promise.all(
    pushToClients.map(async (clientId) => {
      // 2. 从自家数据源取装置 token(不是从 IMKIT)
      const devices = await yourDB.getDevicesByClientId(clientId);
 
      // 3. 自行计算 badge(PUSH_GENERIC 不带 receiver badge)
      const badge = await yourDB.countUnread(clientId);
 
      // 4. 组推播 payload,丢给自家推播中心
      await yourPushCenter.send({
        clientId,
        devices,
        title: roomName || sender.nickname,
        body: messageType === "text" ? message : `${sender.nickname} 传送了 ${messageType}`,
        badge,
        data: {
          roomId: room,
          messageId,
          messageType,
        },
      });
    })
  );
 
  // 立即回 200,不阻塞 IMKIT
  res.status(200).end();
});
 
app.listen(3000);

您也可以选择直接使用 IMKIT 提供的 im_loc_* 本地化 key 来组推播文案(详见 推播 Payload 格式),或在自家中心套用客制化文案逻辑。

步骤 3:App 端 — 沿用自家既有流程

App 端呼叫 IMKIT 的 /me/subscribe,沿用您原本的:

  • iOS:registerForRemoteNotifications → 把 token 上传到您自家后端
  • Android:Firebase onNewToken → 把 token 上传到您自家后端

App 收到推播时,依您自家推播中心的 payload 格式解析即可。前景实时事件、lastRead 同步、badge 取数仍走 IMKIT API(共用部分,与路径 A 完全相同)。

进阶选项:Webhook(每聊天室)

若您只想对特定聊天室启用自家推播,或需要更细的事件分流(如成员加入/离开),可改用 Webhook — 为每个聊天室个别设定 callback URL。一般「整站推播中心」场景仍建议用 PUSH_GENERIC


4-3:取得目前未读数

任何时候要重新整理未读总数,呼叫:

const res = await fetch("https://your-app.imkit.io/me/badge", {
  headers: {
    "IM-CLIENT-KEY": "您的_CLIENT_KEY",
    "IM-Authorization": "用户的_TOKEN",
  },
});
const { result } = await res.json();
console.log("总未读数:", result.badge);

详见 获取用户未读消息。重连后建议呼叫一次此 API,避免在断线期间漏算未读。


整合心法

  • 前景 Socket、后台推播:两者搭配才不会漏消息
  • 两条路径互斥:路径 A(/me/subscribe)与路径 B(PUSH_GENERIC)择一启用,同时开会造成双头推播
  • 路径 B 时 app 端勿呼叫 /me/subscribe:否则 IMKIT 会独立再推一份,与您自家推播中心重复
  • 路径 B 的 badge 自管PUSH_GENERIC callback 不带 receiver badge,需自家后端依 GET /me/badge 或自家数据源计算
  • deviceId 一致(路径 A):subscribe / socket auth2 用同一个 deviceId,伺服器才能识别「该装置目前在线、不必再推播」
  • Token 过期:Socket auth2 失败时,重新呼叫 取得 Token API 换新 token 后再连
  • 登出处理:路径 A 必须呼叫 /me/unsubscribe + disconnect socket;路径 B 则于自家推播中心移除该装置 token,避免下个用户收到前一位的推播

完整串接流程

以下是完整的后端串接范例,涵盖建立两位用户和一个聊天室的完整流程:

const axios = require("axios");
 
const BASE_URL = "https://your-app.imkit.io";
const API_KEY = process.env.IM_API_KEY;
 
const headers = {
  "IM-API-KEY": API_KEY,
  "Content-Type": "application/json; charset=utf-8",
};
 
async function setupChat() {
  // 1. 建立用户 A
  const userA = await axios.post(
    `${BASE_URL}/admin/clients`,
    { _id: "user-a", nickname: "Alice", issueAccessToken: true },
    { headers }
  );
 
  // 2. 建立用户 B
  const userB = await axios.post(
    `${BASE_URL}/admin/clients`,
    { _id: "user-b", nickname: "Bob", issueAccessToken: true },
    { headers }
  );
 
  // 3. 建立聊天室
  const room = await axios.post(
    `${BASE_URL}/rooms/`,
    { roomType: "direct", members: ["user-a", "user-b"] },
    { headers }
  );
 
  return {
    tokenA: userA.data.result.token,
    tokenB: userB.data.result.token,
    roomId: room.data.result._id,
  };
}
 
setupChat().then((result) => {
  console.log("串接完成!");
  console.log("用户 A Token:", result.tokenA);
  console.log("用户 B Token:", result.tokenB);
  console.log("聊天室 ID:", result.roomId);
});

下一步

完成基本串接后,您可以进一步了解:

© 2026 FUNTEK Software Inc. All rights reserved.