AAR
minSdk 23 · 已 R8 混淆 · 自带 keep 规则
读取版本中…开发者 · IM SDK
读取发布通道…
Circllo IM SDK 是即时通讯平台的官方客户端 SDK,只提供数据与事件,不带 UI,界面完全由你自己决定。 iOS 与 Android 是同一套业务契约的两个实现,行为一致、同号发版。
下载地址由各端清单文件(android.json / ios.json)动态生成,文件名带版本与构建号,历史版本不会被就地覆盖。
先分清三个角色:你的 App(集成 SDK)、你的后端(签发 UserSig)、Circllo IM 平台(收发消息)。
TEST 与 PROD 解析到同一套测试网关,PROD 不代表生产 IM 已开通。把下载的 .aar 放进模块的 libs/,然后声明依赖。SDK 自带 consumer-rules.pro,接入方无需再写 keep 规则。
dependencies {
implementation(files("libs/impaas-sdk-release.aar"))
// AAR 不传递依赖,这几个要自己声明
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("androidx.security:security-crypto:1.1.0-alpha06")
implementation("com.google.crypto.tink:tink-android:1.8.0")
}SDK 的 library manifest 已经声明并会自动合并进宿主 App,通常无需重复添加;下面两条列出来只是让你知道 SDK 用到什么。
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
建议放在 Application.onCreate。网关地址由 SDK 内置,接入方只需要给 appId 和环境枚举,不需要也不能传 host。
import wang.into.im.impaas.core.IMPaaSEnvironment
IMPaaSClient.init(
context = applicationContext,
config = IMPaaSConfig(
appId = "APP_ID", // 开通时分配,公开
environment = IMPaaSEnvironment.TEST, // TEST / PROD,网关地址由 SDK 内置
),
)回调都在主线程,可直接刷 UI。未知事件会降级透出,不抛异常也不丢消息。
IMPaaSClient.addListener(object : IMPaaSListener {
override fun onConnected() { /* 长连就绪 */ }
override fun onNewMessage(message: IMPaaSMessage) { /* 按 messageId 去重后刷 UI */ }
override fun onMessageEvent(event: IMEvent) { /* message.* 其余事件 */ }
override fun onUnknownEvent(event: IMEvent) { /* 表外事件,降级不抛不丢 */ }
override fun onKicked(reason: KickReason) { /* 顶号/封禁,引导重登 */ }
})
// refresh_token 也失效时:重新向你的后端取 UserSig 再 login
IMPaaSClient.onNeedReLogin = { /* ... */ }三个值先从你的后端取(那里才有 AppSecret),拿到后原样透传。成功后 SDK 自动建立长连。
IMPaaSClient.login(
userId = "player_888",
userSig = sig.userSig,
expireAt = sig.expireAt, // 绝对 Unix 秒,必须 > 0
nonce = sig.nonce, // 8~64 字符,不可复用
) { result ->
result.onSuccess { /* SDK 已自动建立 WSS */ }
.onFailure { e -> /* e is IMPaaSError */ }
}val msg = IMPaaSMessage.text("hello", conversationId = "conv_id")
IMPaaSClient.message.send(msg) { result ->
result.onSuccess { sent -> /* messageId / seqId / createdAt 已回填 */ }
.onFailure { e -> /* 失败 */ }
}解压下载的 zip,把 IMPaaSSDK.xcframework 拖进工程,在 target 的 General → Frameworks, Libraries, and Embedded Content 里确认已添加。包内已含真机(arm64)与模拟器(arm64 + x86_64)两个切片,不需要自己处理架构。
# 解压用 ditto,保留符号链接;用 unzip 可能解出结构不对的框架 ditto -x -k impaas-sdk-ios-*.xcframework.zip .
网关地址由 SDK 内置,接入方只需要给 appId 和环境,不需要也不能传 host。
import IMPaaSSDK
IMPaaSClient.shared.initialize(
config: .init(appId: "APP_ID", // 开通时分配,公开
environment: .test) // .test / .prod,网关地址由 SDK 内置
)监听器被弱引用持有,回调都在主线程。协议方法全部可选,只覆写关心的。
IMPaaSClient.shared.addListener(self)
// refresh_token 也失效时:重新向你的后端取 UserSig 再 login
IMPaaSClient.shared.onNeedReLogin = { [weak self] in
self?.fetchSigFromYourBackend { self?.login($0) }
}
// MARK: IMPaaSListener
func onConnected() { /* 长连就绪 */ }
func onNewMessage(_ message: IMPaaSMessage) { /* 按 messageId 去重后刷 UI */ }
func onUnknownEvent(_ event: IMEvent) { /* 表外事件,降级不抛不丢 */ }
func onKicked(_ reason: KickReason) { /* 引导用户重登 */ }三个值先从你的后端取(那里才有 AppSecret),拿到后原样透传。
IMPaaSClient.shared.login(userId: "player_888",
userSig: s.userSig,
expireAt: s.expireAt, // 绝对 Unix 秒,必须 > 0
nonce: s.nonce) { result in
switch result {
case .success: print("logged in")
case .failure(let error): print("login failed: \(error.localizedDescription)")
}
}let msg = IMPaaSMessage.text("hello", to: "conv_id")
IMPaaSClient.shared.message.send(msg) { result in
switch result {
case .success(let sent): print("message_id=\(sent.messageId ?? "-")")
case .failure(let error): print("send failed: \(error)")
}
}seq_id(会话内序号)或 created_at。send 只认 conversation_id。群 id 就是 conversation_id,没有单独的 group_id。onNeedReLogin。需要 appId、网关地址或完整的 API 参考(getting-started · android-integration · ios-integration · api-reference), 发信到 hello@circllo.app 联系我们。