用户状态订阅
更新时间: 2024/12/27 14:08:42
网易云信即时通讯 SDK(NetEase IM SDK,简称 NIM SDK)提供订阅用户状态功能,支持订阅/取消订阅用户状态,发布自定义的用户状态,查询用户状态订阅关系等。
支持平台
本文内容适用的开发平台或框架如下表所示:
Android | iOS | macOS/Windows | Web/uni-app/小程序 | Node.js/Electron | HarmonyOS | Flutter |
---|---|---|---|---|---|---|
✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️ | ✔️️ | ✔️️ |
技术原理
用户可以通过事件发布以及订阅,来实现 发布-订阅 的设计模式应用于订阅指定用户的在线状态、用户个性化信息订阅等场景。
网易云信 IM 系统已内置在线状态事件,用户无需发布,由网易云信服务器管理。具体表现为:若 A 订阅了 B 的登录事件,当 A 登录时,若 B 此时在线,则会收到 B 已登录上线的事件。若后续 B 再登录上线时,且 A 也在线,则依旧可以监听到。
如果内置的在线状态不满足业务需求,您可以按照以下流程发布自定义用户状态个性化实现业务场景。
flowchart LR
classDef default fill:#337EFF,stroke:#337EFF,stroke-width:0px,color:#FFFFFF;
A("用户 A 订阅 B<br>subscribeUserStatus")-->B("用户 B 发布自定义状态事件<br>publishCustomUserStatus")-->C("A 收到 B 状态变更的回调<br>onUserStatusChanged")-->D("按照自身业务逻<br>辑解析处理")
click A "https://doc.yunxin.163.com/messaging2/client-apis/zY2MzAxNjQ?platform=client#subscribeuserstatus"
click B "https://doc.yunxin.163.com/messaging2/client-apis/zY2MzAxNjQ?platform=client#publishcustomuserstatus"
click C "https://doc.yunxin.163.com/messaging2/client-apis/DAxNjk0Mzc?platform=client#v2nimsubscribelistener"
前提条件
若需要使用 在线状态订阅 功能,需要提前在 网易云信控制台 开通在线状态订阅功能,具体请参考 配置基础功能/全局功能。
注意事项
-
系统默认的在线状态事件包括登录、登出以及断开连接。若需要设置自定义状态,如忙碌等,请自行发布事件。
-
用户状态事件订阅是单向的,双方需要各自自行订阅。
-
单次最多订阅 100 个用户的状态,可多次调用该接口,订阅更多的用户状态,但是总订阅人数最多为 3000,若超限,则默认删除最老的订阅,即有效订阅最多为 3000 个。
-
在线状态事件会受到推送的影响。
- 如果应用被清理(退出应用等),但可以接收第三方厂商推送(APNS、小米、华为、OPPO、VIVO、魅族、FCM)消息,则默认不会触发该用户断开连接的事件(即此情况仍视为 在线 状态)。若您需要将该情况视为离线,请前往 网易云信控制台 将在线状态订阅配置项下修改推送状态。
- 如果没有集成推送,或者推送不可达时,当用户断开连接时,会触发断开连接事件。
-
当订阅者登录时,若被订阅者在线,那么会收到其在线的事件回调。但若对方离线,那么订阅者无法收到其离线的事件回调(只有后续对方重新登录,才能触发在线状态事件)。因此建议登录时将所有账号的在线状态设置为离线,这样设置,登录时无论对方是在线,还是从离线变更为在线,都能正常触发回调。
-
订阅有效期为 60 - 2592000 秒(即 60 秒至 30 天)。过期后需要重新订阅。如果未过期的情况下重复订阅,新设置的有效期会覆盖之前的有效期。
但如果在订阅后 30s 内重复订阅,该操作会被直接丢弃。因此建议 30s 后再进行操作。在 30s 后重复订阅,新设置的有效期才会覆盖之前的有效期。
监听用户状态订阅相关事件
在进行用户状态订阅相关操作前,您可以提前注册相关事件。注册成功后,当相关事件发生时,SDK 会触发对应回调通知。
用户状态订阅相关回调:
onUserStatusChanged
:其他用户的用户状态变更回调,包括在线状态和自定义状态。同账号发布状态时,多端也会同步收到回调。
Android/iOS/macOS/Windows
调用 addSubscribeListener
方法注册用户状态订阅相关监听器,监听用户状态变更事件。
示例代码:
JavaV2NIMSubscribeListener listener = new V2NIMSubscribeListener() {
@Override
public void onUserStatusChanged(List<V2NIMUserStatus> userStatusList) {
//用户状态变更
}
};
NIMClient.getService(V2NIMSubscriptionService.class).addSubscribeListener(listener);
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService addSubscribeListener:self];
- (void)onUserStatusChanged:(NSArray<V2NIMUserStatus *> *)data {
}
C++V2NIMSubscribeListener listener;
listener.onUserStatusChanged = [](nstd::vector<V2NIMUserStatusEvent> events) {
// handle user status changed event
};
subscriptionService.addSubscribeListener(listener);
如需移除用户相关监听器,可调用 removeSubscribeListener
方法。
JavaNIMClient.getService(V2NIMSubscriptionService.class).removeSubscribeListener(listener);
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService removeSubscribeListener:self];
C++subscriptionService.removeSubscribeListener(listener);
Web/uni-app/小程序/Node.js/Electron/HarmonyOS
调用 on("EventName")
方法注册用户状态订阅相关监听器,监听用户状态变更事件。
示例代码:
TypeScriptnim.V2NIMSubscriptionService.on("onUserStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
如需移除用户相关监听器,可调用 off("EventName")
方法。
TypeScriptnim.V2NIMSubscriptionService.off("onUserStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
TypeScriptv2.subscriptionService.on("userStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
如需移除用户相关监听器,可调用 off("EventName")
方法。
TypeScriptv2.subscriptionService.off("userStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
TypeScriptnim.subscriptionService.on("onUserStatusChanged", (userStatusList: V2NIMUserStatus[]) => {})
如需移除用户相关监听器,可调用 off("EventName")
方法。
TypeScriptconst func = (userStatusList: V2NIMUserStatus[]) => {}
nim.subscriptionService.off("onUserStatusChanged", func)
Flutter
调用 add
方法注册用户状态订阅相关监听器,监听用户状态变更事件。
示例代码:
Dartsubsriptions.add(
NimCore.instance.subscriptionService.onUserStatusChanged.listen((events){
//do something
})
);
如需移除用户相关监听器,可调用 cancel
方法。
Dartsubsriptions.forEach((subsription) {
subsription.cancel();
});
订阅用户状态
调用 subscribeUserStatus
方法订阅用户状态,包括在线状态或用户自定义的状态。
成功订阅用户状态后,当订阅的用户状态有变更时,会触发 onUserStatusChanged
回调。
- 单次最多订阅 100 个用户的状态,可多次调用该接口,订阅更多的用户状态,但是总订阅人数最多为 3000,若超限,则默认删除最老的订阅,即有效订阅最多为 3000 个。
- 若同一账号多端重复订阅,订阅有效期默认会覆盖(新的覆盖前一次时长)。但如果在订阅后 30s 内重复订阅,该操作会被直接丢弃。因此建议 30s 后再进行操作。在 30s 后重复订阅,新设置的有效期才会覆盖之前的有效期。
- 若传入的账号 ID 都不存在,则调用接口失败。若部分账号 ID 存在,则调用接口成功。调用结果只返回账号 ID 存在的用户状态,错误的账号 ID 不返回。
示例代码:
JavaList<String> accountIds = Arrays.asList("account1", "account2");
//订阅的有效期,时间范围为 60~2592000,单位:秒
long duration = 60L;
//订阅后是否立即同步事件状态值,默认为 false。为 true:表示立即同步当前状态值 但为了性能考虑,30S 内重复订阅,会忽略该参数
boolean immediateSync = false;
V2NIMSubscribeUserStatusOption option = new V2NIMSubscribeUserStatusOption(accountIds, duration, immediateSync);
NIMClient.getService(V2NIMSubscriptionService.class).subscribeUserStatus(option, new V2NIMSuccessCallback<List<String>>() {
@Override
public void onSuccess(List<String> failList) {
//订阅成功,返回订阅失败的 failList
}
}, new V2NIMFailureCallback() {
@Override
public void onFailure(V2NIMError error) {
//订阅失败
}
});
Objective-CV2NIMSubscribeUserStatusOption *option = [[V2NIMSubscribeUserStatusOption alloc] init];
option.accountIds = @[@"accId1",@"accId2"];
[NIMSDK.sharedSDK.v2SubscriptionService subscribeUserStatus:option success:^(NSArray<NSString *> *failedList) {
// 成功回调
} failure:^(V2NIMError * _Nonnull error) {
// 失败回调
}];
C++V2NIMSubscribeUserStatusOption option;
option.accountIds.push_back("account1");
subscriptionService.subscribeUserStatus(
option,
[](nstd::vector<nstd::string> failedAccounts) {
// subscribe user status succeeded
},
[](V2NIMError error) {
// subscribe user status failed, handle error
});
TypeScripttry {
const failedAccounts = await nim.V2NIMSubscriptionService.subscribeUserStatus({
accountIds: ['user1', 'user2'],
duration: 3600 * 24
})
if (failedAccounts.length > 0) {
console.error('subscribeUserStatus failed accounts', failedAccounts)
}
} catch(err) {
console.error('subscribeUserStatus err': err)
}
TypeScripttry {
const result = await v2.subscriptionService.subscribeUserStatus({
accountIds: ['account1', 'account2'],
})
if (failedAccounts.length > 0) {
console.error('subscribeUserStatus failed accounts', failedAccounts)
}
} catch(err) {
console.error('subscribeUserStatus err': err)
}
TypeScriptconst params = {
accountIds: ['aa', 'bb'],
duration: 60,
immediateSync: false
} as V2NIMSubscribeUserStatusOption
const subscriptionList = await nim.subscriptionService.subscribeUserStatus(params)
Dartvar option = NIMSubscribeUserStatusOption(accountIds: ['account'])
NimCore.instance.subscriptionService.subscribeUserStatus(option).then((value) async {
if(value.isSuccess){
// 订阅成功
}
})
取消订阅用户状态
调用 unsubscribeUserStatus
方法取消用户状态的订阅。
示例代码:
JavaList<String> accountIds = Arrays.asList("account1", "account2");
V2NIMUnsubscribeUserStatusOption option = new V2NIMUnsubscribeUserStatusOption(accountIds);
NIMClient.getService(V2NIMSubscriptionService.class).unsubscribeUserStatus(option, new V2NIMSuccessCallback<List<String>>() {
@Override
public void onSuccess(List<String> failList) {
//取消订阅成功,返回取消订阅失败的 failList
}
}, new V2NIMFailureCallback() {
@Override
public void onFailure(V2NIMError error) {
//取消订阅失败
}
});
Objective-CV2NIMUnsubscribeUserStatusOption *option = [[V2NIMUnsubscribeUserStatusOption alloc] init];
option.accountIds = @[@"accId1",@"accId2"];
[NIMSDK.sharedSDK.v2SubscriptionService unsubscribeUserStatus:option success:^(NSArray<NSString *> *failedList) {
// 成功回调
} failure:^(V2NIMError * _Nonnull error) {
// 失败回调
}];
C++V2NIMUnsubscribeUserStatusOption option;
option.accountIds.push_back("account1");
subscriptionService.unsubscribeUserStatus(
option,
[](nstd::vector<nstd::string> failedAccounts) {
// unsubscribe user status succeeded
},
[](V2NIMError error) {
// unsubscribe user status failed, handle error
});
TypeScripttry {
const failedAccounts = await nim.V2NIMSubscriptionService.unsubscribeUserStatus({
accountIds: ['user1', 'user2']
})
if (failedAccounts.length > 0) {
console.error('unsubscribeUserStatus failed accounts', failedAccounts)
}
} catch(err) {
console.error('unsubscribeUserStatus err': err)
}
TypeScripttry {
const result = await v2.subscriptionService.unsubscribeUserStatus({
accountIds: ['account1', 'account2'],
})
if (failedAccounts.length > 0) {
console.error('unsubscribeUserStatus failed accounts', failedAccounts)
}
} catch(err) {
console.error('unsubscribeUserStatus err': err)
}
TypeScriptconst params = {
accountIds: ['aa', 'bb']
} as V2NIMUnsubscribeUserStatusOption
const unsubscriptionList = await nim.subscriptionService.unsubscribeUserStatus(params)
Dartvar option = NIMUnsubscribeUserStatusOption(accountIds: ['account'])
NimCore.instance.subscriptionService.unsubscribeUserStatus(option).then((value) async {
if(value.isSuccess){
// 取消订阅成功
}
});
查询用户状态订阅关系
调用 queryUserStatusSubscriptions
方法查询用户状态订阅关系。
传入账号列表,查询自己订阅了其中哪些账号的状态,调用接口成功后,返回订阅的账号列表。
示例代码:
JavaList<String> accountIds = Arrays.asList("account1", "account2");
NIMClient.getService(V2NIMSubscriptionService.class).queryUserStatusSubscriptions(accountIds, new V2NIMSuccessCallback<List<V2NIMUserStatusSubscribeResult>>() {
@Override
public void onSuccess(List<V2NIMUserStatusSubscribeResult> v2NIMUserStatusSubscribeResults) {
//查询成功
}
}, new V2NIMFailureCallback() {
@Override
public void onFailure(V2NIMError error) {
//查询失败
}
});
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService queryUserStatusSubscriptions:@[@"accId1",@"accId2"] success:^(NSArray<V2NIMUserStatusSubscribeResult *> *resultList) {
// 成功回调
} failure:^(V2NIMError * _Nonnull error) {
// 失败回调
}];
C++nstd::vector<nstd::string> accountIds;
accountIds.push_back("account1");
subscriptionService.queryUserStatusSubscriptions(
accountIds,
[](nstd::vector<nstd::string> subscribedAccounts) {
// query user status subscribe succeeded
},
[](V2NIMError error) {
// query user status subscribe failed, handle error
});
TypeScripttry {
const result = await nim.V2NIMSubscriptionService.queryUserStatusSubscriptions(['user1', 'user2'])
console.log('queryUserStatusSubscriptions result', result)
} catch(err) {
console.error('queryUserStatusSubscriptions err': err)
}
TypeScripttry {
const result = await v2.subscriptionService.queryUserStatusSubscriptions(['account1', 'account2'])
console.log('queryUserStatusSubscriptions result', result)
} catch(err) {
console.error('queryUserStatusSubscriptions err': err)
}
TypeScriptconst query = await subscriptionService.queryUserStatusSubscriptions(['a','b'])
DartNimCore.instance.subscriptionService.queryUserStatusSubscriptions(accountIds).then((value){
if(value.isSuccess){
// 查询用户订阅状态成功
}
});
发布用户自定义状态
调用 publishCustomUserStatus
方法发布用户自定义状态。
如果默认在线状态不满足业务需求,可以发布自定义用户状态。
示例代码:
Java//自定义设置值:10000 以上,包括一万,一万以内为预定义值
int statusType = 10001;
//状态的有效期,单位秒,范围为 60s 到 7days
long duration = 60L;
//用户发布状态时设置的扩展字段
String extension = "{\"key\":\"value\"}";
//用户发布状态时是否只广播给在线的订阅者,默认值为 TRUE
boolean onlineOnly = true;
// 用户发布状态时是否需要多端同步,默认值为 FALSE
boolean multiSync = false;
//自定义用户状态参数
V2NIMCustomUserStatusParams params = new V2NIMCustomUserStatusParams.Builder(statusType,duration)
.extension(extension)
.onlineOnly(onlineOnly)
.multiSync(multiSync)
.build();
NIMClient.getService(V2NIMSubscriptionService.class).publishCustomUserStatus(params, new V2NIMSuccessCallback<V2NIMCustomUserStatusPublishResult>() {
@Override
public void onSuccess(V2NIMCustomUserStatusPublishResult v2NIMCustomUserStatusPublishResult) {
//发布自定义用户状态成功
}
}, new V2NIMFailureCallback() {
@Override
public void onFailure(V2NIMError error) {
//发布自定义用户状态失败
}
});
Objective-C V2NIMCustomUserStatusParams *params = [[V2NIMCustomUserStatusParams alloc] init];
params.statusType = 10001;
[NIMSDK.sharedSDK.v2SubscriptionService publishCustomUserStatus:params success:^(V2NIMCustomUserStatusPublishResult *resultList) {
// 成功回调
} failure:^(V2NIMError * _Nonnull error) {
// 失败回调
}];
C++V2NIMCustomUserStatusParams params;
params.statusType = 100001;
subscriptionService.publishCustomUserStatus(
params,
[]() {
// publish custom user status succeeded
},
[](V2NIMError error) {
// publish custom user status failed, handle error
});
TypeScripttry {
const result = await nim.V2NIMSubscriptionService.publishCustomUserStatus({
/**
* 自定义设置值:10000 以上,不包括一万,一万以内为预定义值。小于 1 万,返回参数错误
*/
statusType: 10001
/**
* 状态的有效期,单位秒,范围为 60s 到 7days
*/
duration: 3600 * 24
/**
* 用户发布状态时是否只广播给在线的订阅者。默认为 true
*/
onlineOnly: false
/**
* 用户发布状态时是否需要多端同步。默认为 false
*/
multiSync: true
})
console.log('publishCustomUserStatus result', result)
} catch(err) {
console.error('publishCustomUserStatus err': err)
}
TypeScripttry {
const result = await v2.subscriptionService.publishCustomUserStatus({
statusType: 10001,
duration: 60
})
console.log('publishCustomUserStatus result', result)
} catch(err) {
console.error('publishCustomUserStatus err': err)
}
TypeScriptconst params = {
statusType: 10001,
duration: 60,
extension: JSON.stringify(extensionMap),
onlineOnly: true,
multiSync: false
} as V2NIMCustomUserStatusParams
const subscriptionList = await nim.subscriptionService.publishCustomUserStatus(params)
DartNimCore.instance.subscriptionService.publishCustomUserStatus(params).then((value){
if (value.isSuccess) {
// 发布用户自定义状态成功
}
});
涉及接口
API | 说明 |
---|---|
addSubscribeListener |
注册用户状态订阅相关监听器 |
removeSubscribeListener |
取消注册用户状态订阅相关监听器 |
subscribeUserStatus |
订阅用户状态 |
unsubscribeUserStatus |
取消订阅用户状态 |
queryUserStatusSubscriptions |
查询用户状态订阅关系 |
publishCustomUserStatus |
发布用户自定义状态 |
API | 说明 |
---|---|
on("EventName") |
注册用户状态订阅相关监听器 |
off("EventName") |
取消注册用户状态订阅相关监听器 |
subscribeUserStatus |
订阅用户状态 |
unsubscribeUserStatus |
取消订阅用户状态 |
queryUserStatusSubscriptions |
查询用户状态订阅关系 |
publishCustomUserStatus |
发布用户自定义状态 |
API | 说明 |
---|---|
add |
注册用户状态订阅相关监听器 |
cancel |
取消注册用户状态订阅相关监听器 |
subscribeUserStatus |
订阅用户状态 |
unsubscribeUserStatus |
取消订阅用户状态 |
queryUserStatusSubscriptions |
查询用户状态订阅关系 |
publishCustomUserStatus |
发布用户自定义状态 |