用户状态订阅

更新时间: 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 方法注册用户状态订阅相关监听器,监听用户状态变更事件。

示例代码

Android
JavaV2NIMSubscribeListener listener = new V2NIMSubscribeListener() {
  @Override
  public void onUserStatusChanged(List<V2NIMUserStatus> userStatusList) {
   //用户状态变更
  }
};
NIMClient.getService(V2NIMSubscriptionService.class).addSubscribeListener(listener);
iOS
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService addSubscribeListener:self];
- (void)onUserStatusChanged:(NSArray<V2NIMUserStatus *> *)data {
}
macOS/Windows
C++V2NIMSubscribeListener listener;
listener.onUserStatusChanged = [](nstd::vector<V2NIMUserStatusEvent> events) {
    // handle user status changed event
};
subscriptionService.addSubscribeListener(listener);

如需移除用户相关监听器,可调用 removeSubscribeListener 方法。

Android
JavaNIMClient.getService(V2NIMSubscriptionService.class).removeSubscribeListener(listener);
iOS
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService removeSubscribeListener:self];
macOS/Windows
C++subscriptionService.removeSubscribeListener(listener);

Web/uni-app/小程序/Node.js/Electron/HarmonyOS

调用 on("EventName") 方法注册用户状态订阅相关监听器,监听用户状态变更事件。

示例代码

Web/uni-app/小程序
TypeScriptnim.V2NIMSubscriptionService.on("onUserStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})

如需移除用户相关监听器,可调用 off("EventName") 方法。

TypeScriptnim.V2NIMSubscriptionService.off("onUserStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
Node.js/Electron
TypeScriptv2.subscriptionService.on("userStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})

如需移除用户相关监听器,可调用 off("EventName") 方法。

TypeScriptv2.subscriptionService.off("userStatusChanged", function (userStatusList: Array<V2NIMUserStatus>) {})
HarmonyOS
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 不返回。

示例代码

Android
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) {
   //订阅失败
  }
});
iOS
Objective-CV2NIMSubscribeUserStatusOption *option = [[V2NIMSubscribeUserStatusOption alloc] init];
    option.accountIds = @[@"accId1",@"accId2"];
    [NIMSDK.sharedSDK.v2SubscriptionService subscribeUserStatus:option success:^(NSArray<NSString *> *failedList) {
           // 成功回调
        } failure:^(V2NIMError * _Nonnull error) {
            // 失败回调
        }];
macOS/Windows
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
    });
Web/uni-app/小程序
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)
}
Node.js/Electron
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)
}
HarmonyOS
TypeScriptconst params = {
  accountIds: ['aa', 'bb'],
  duration: 60,
  immediateSync: false
} as V2NIMSubscribeUserStatusOption

const subscriptionList = await nim.subscriptionService.subscribeUserStatus(params)
Flutter
Dartvar option = NIMSubscribeUserStatusOption(accountIds: ['account'])

    NimCore.instance.subscriptionService.subscribeUserStatus(option).then((value) async {
       if(value.isSuccess){
         // 订阅成功
       }
    })

取消订阅用户状态

调用 unsubscribeUserStatus 方法取消用户状态的订阅。

示例代码

Android
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) {
   //取消订阅失败
  }
});
iOS
Objective-CV2NIMUnsubscribeUserStatusOption *option = [[V2NIMUnsubscribeUserStatusOption alloc] init];
    option.accountIds = @[@"accId1",@"accId2"];
    [NIMSDK.sharedSDK.v2SubscriptionService unsubscribeUserStatus:option success:^(NSArray<NSString *> *failedList) {
        // 成功回调
    } failure:^(V2NIMError * _Nonnull error) {
        // 失败回调
    }];
macOS/Windows
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
    });
Web/uni-app/小程序
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)
}
Node.js/Electron
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)
}
HarmonyOS
TypeScriptconst params = {
  accountIds: ['aa', 'bb']
} as V2NIMUnsubscribeUserStatusOption

const unsubscriptionList = await nim.subscriptionService.unsubscribeUserStatus(params)
Flutter
Dartvar option = NIMUnsubscribeUserStatusOption(accountIds: ['account'])

    NimCore.instance.subscriptionService.unsubscribeUserStatus(option).then((value) async {
       if(value.isSuccess){
         // 取消订阅成功
       }
    });

查询用户状态订阅关系

调用 queryUserStatusSubscriptions 方法查询用户状态订阅关系。

传入账号列表,查询自己订阅了其中哪些账号的状态,调用接口成功后,返回订阅的账号列表。

示例代码

Android
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) {
   //查询失败
  }
});
iOS
Objective-C[NIMSDK.sharedSDK.v2SubscriptionService queryUserStatusSubscriptions:@[@"accId1",@"accId2"] success:^(NSArray<V2NIMUserStatusSubscribeResult *> *resultList) {
        // 成功回调
    } failure:^(V2NIMError * _Nonnull error) {
        // 失败回调
    }];
macOS/Windows
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
    });
Web/uni-app/小程序
TypeScripttry {
    const result = await nim.V2NIMSubscriptionService.queryUserStatusSubscriptions(['user1', 'user2'])
   console.log('queryUserStatusSubscriptions result', result)
 } catch(err) {
    console.error('queryUserStatusSubscriptions err': err)
 }
Node.js/Electron
TypeScripttry {
    const result = await v2.subscriptionService.queryUserStatusSubscriptions(['account1', 'account2'])
   console.log('queryUserStatusSubscriptions result', result)
 } catch(err) {
    console.error('queryUserStatusSubscriptions err': err)
 }
HarmonyOS
TypeScriptconst query = await subscriptionService.queryUserStatusSubscriptions(['a','b'])
Flutter
DartNimCore.instance.subscriptionService.queryUserStatusSubscriptions(accountIds).then((value){
       if(value.isSuccess){
         // 查询用户订阅状态成功
       }
    });

发布用户自定义状态

调用 publishCustomUserStatus 方法发布用户自定义状态。

如果默认在线状态不满足业务需求,可以发布自定义用户状态。

示例代码

Android
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) {
   //发布自定义用户状态失败
  }
});
iOS
Objective-C V2NIMCustomUserStatusParams *params = [[V2NIMCustomUserStatusParams alloc] init];
    params.statusType = 10001;
    [NIMSDK.sharedSDK.v2SubscriptionService publishCustomUserStatus:params success:^(V2NIMCustomUserStatusPublishResult *resultList) {
        // 成功回调
    } failure:^(V2NIMError * _Nonnull error) {
        // 失败回调
    }];
macOS/Windows
C++V2NIMCustomUserStatusParams params;
params.statusType = 100001;
subscriptionService.publishCustomUserStatus(
    params,
    []() {
        // publish custom user status succeeded
    },
    [](V2NIMError error) {
        // publish custom user status failed, handle error
    });
Web/uni-app/小程序
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)
 }
Node.js/Electron
TypeScripttry {
    const result = await v2.subscriptionService.publishCustomUserStatus({
        statusType: 10001,
        duration: 60
    })
   console.log('publishCustomUserStatus result', result)
 } catch(err) {
    console.error('publishCustomUserStatus err': err)
 }
HarmonyOS
TypeScriptconst params = {
  statusType: 10001,
  duration: 60,
  extension: JSON.stringify(extensionMap),
  onlineOnly: true,
  multiSync: false
} as V2NIMCustomUserStatusParams

const subscriptionList = await nim.subscriptionService.publishCustomUserStatus(params)
Flutter
DartNimCore.instance.subscriptionService.publishCustomUserStatus(params).then((value){
      if (value.isSuccess) {
        // 发布用户自定义状态成功
      }
    });

涉及接口

Android/iOS/macOS/Windows
API 说明
addSubscribeListener 注册用户状态订阅相关监听器
removeSubscribeListener 取消注册用户状态订阅相关监听器
subscribeUserStatus 订阅用户状态
unsubscribeUserStatus 取消订阅用户状态
queryUserStatusSubscriptions 查询用户状态订阅关系
publishCustomUserStatus 发布用户自定义状态
Web/uni-app/小程序/Node.js/Electron/HarmonyOS
API 说明
on("EventName") 注册用户状态订阅相关监听器
off("EventName") 取消注册用户状态订阅相关监听器
subscribeUserStatus 订阅用户状态
unsubscribeUserStatus 取消订阅用户状态
queryUserStatusSubscriptions 查询用户状态订阅关系
publishCustomUserStatus 发布用户自定义状态
Flutter
API 说明
add 注册用户状态订阅相关监听器
cancel 取消注册用户状态订阅相关监听器
subscribeUserStatus 订阅用户状态
unsubscribeUserStatus 取消订阅用户状态
queryUserStatusSubscriptions 查询用户状态订阅关系
publishCustomUserStatus 发布用户自定义状态
此文档是否对你有帮助?
有帮助
去反馈
  • 支持平台
  • 技术原理
  • 前提条件
  • 注意事项
  • 监听用户状态订阅相关事件
  • 订阅用户状态
  • 取消订阅用户状态
  • 查询用户状态订阅关系
  • 发布用户自定义状态
  • 涉及接口