# NIMSDK 集成说明文档 ## 目录 - [1. 项目概述](#1-项目概述) - [2. NIMSDK导入配置](#2-nimsdk导入配置) - [3. NIMSDK初始化流程](#3-nimsdk初始化流程) - [4. 关键配置参数说明](#4-关键配置参数说明) - [5. 自定义消息处理](#5-自定义消息处理) - [6. 登录管理](#6-登录管理) - [7. 消息接收处理](#7-消息接收处理) - [8. 推送通知集成](#8-推送通知集成) - [9. 最佳实践](#9-最佳实践) - [10. 常见问题](#10-常见问题) ## 1. 项目概述 ### 1.1 项目简介 YuMi是一个基于iOS平台的社交应用,使用Objective-C开发,采用MVP架构模式。项目集成了网易云信SDK(NIMSDK)用于实现即时通讯功能。 ### 1.2 技术栈 - **开发语言**: Objective-C - **架构模式**: MVP (Model-View-Presenter) - **即时通讯**: 网易云信 NIMSDK_LITE - **依赖管理**: CocoaPods - **最低支持版本**: iOS 11.0 ### 1.3 主要功能模块 - 用户登录注册 - 即时消息通讯 - 聊天室功能 - 动态发布 - 个人中心 - 房间直播 ## 2. NIMSDK导入配置 ### 2.1 Podfile配置 在项目的`Podfile`中添加NIMSDK依赖: ```ruby # 云信SDK pod 'NIMSDK_LITE' ``` ### 2.2 头文件导入 在需要使用NIMSDK的文件中导入头文件: ```objc #import ``` ### 2.3 项目结构 ``` YuMi/ ├── Appdelegate/ │ ├── AppDelegate.m # 主应用代理 │ └── AppDelegate+ThirdConfig.m # 第三方SDK配置 ├── Modules/ │ ├── YMMessage/ # 消息模块 │ │ └── Tool/ │ │ └── CustomAttachmentDecoder # 自定义消息解码器 │ ├── YMTabbar/ # 主界面模块 │ └── YMRoom/ # 房间模块 └── Global/ └── YUMIConstant.h # 常量定义 ``` ## 3. NIMSDK初始化流程 ### 3.1 初始化时序图 ```mermaid sequenceDiagram participant App as AppDelegate participant ThirdConfig as AppDelegate+ThirdConfig participant NIMSDK as NIMSDK participant Config as NIMSDKConfig participant Decoder as CustomAttachmentDecoder App->>ThirdConfig: initThirdConfig() ThirdConfig->>ThirdConfig: configNIMSDK() ThirdConfig->>NIMSDK: registerWithOption(option) ThirdConfig->>Decoder: registerCustomDecoder() ThirdConfig->>Config: shouldConsiderRevokedMessageUnreadCount = YES ThirdConfig->>Config: setShouldSyncStickTopSessionInfos(YES) ThirdConfig->>Config: enabledHttpsForInfo = NO (DEBUG) ThirdConfig->>Config: enabledHttpsForMessage = NO (DEBUG) Note over App: 应用启动完成 App->>App: loadMainPage() App->>App: 检查登录状态 App->>NIMSDK: 自动登录或手动登录 ``` ### 3.2 初始化代码实现 #### 3.2.1 主应用代理初始化 ```objc // AppDelegate.m - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 初始化第三方SDK配置 [self initThirdConfig]; // 其他初始化代码... return YES; } ``` #### 3.2.2 NIMSDK配置方法 ```objc // AppDelegate+ThirdConfig.m - (void)configNIMSDK { // 1. 获取云信AppKey NSString *appKey = KeyWithType(KeyType_NetEase); NIMSDKOption *option = [NIMSDKOption optionWithAppKey:appKey]; // 2. 配置APNS证书名称 #ifdef DEBUG option.apnsCername = @"pikoDevelopPush"; #else option.apnsCername = @"newPiko"; #endif // 3. 注册SDK [[NIMSDK sharedSDK] registerWithOption:option]; // 4. 注册自定义消息解码器 [NIMCustomObject registerCustomDecoder:[[CustomAttachmentDecoder alloc] init]]; // 5. 配置SDK参数 [NIMSDKConfig sharedConfig].shouldConsiderRevokedMessageUnreadCount = YES; [[NIMSDKConfig sharedConfig] setShouldSyncStickTopSessionInfos:YES]; // 6. DEBUG模式下禁用HTTPS #ifdef DEBUG [NIMSDKConfig sharedConfig].enabledHttpsForInfo = NO; [NIMSDKConfig sharedConfig].enabledHttpsForMessage = NO; #endif } ``` ## 4. 关键配置参数说明 ### 4.1 AppKey配置 项目支持多环境配置,通过`YUMIConstant.m`中的`KeyWithType`方法获取: ```objc // 测试环境 @(KeyType_NetEase): @"79bc37000f4018a2a24ea9dc6ca08d32" // 生产环境 @(KeyType_NetEase): @"7371d729710cd6ce3a50163b956b5eb6" ``` ### 4.2 APNS推送配置 ```objc // 开发环境 option.apnsCername = @"pikoDevelopPush"; // 生产环境 option.apnsCername = @"newPiko"; ``` ### 4.3 SDK配置参数详解 | 参数 | 值 | 说明 | |------|----|----| | `shouldConsiderRevokedMessageUnreadCount` | `YES` | 撤回消息计入未读数 | | `shouldSyncStickTopSessionInfos` | `YES` | 同步置顶会话信息 | | `enabledHttpsForInfo` | `NO` (DEBUG) | DEBUG模式禁用HTTPS信息传输 | | `enabledHttpsForMessage` | `NO` (DEBUG) | DEBUG模式禁用HTTPS消息传输 | ## 5. 自定义消息处理 ### 5.1 自定义附件解码器 #### 5.1.1 解码器接口定义 ```objc // CustomAttachmentDecoder.h @interface CustomAttachmentDecoder : NSObject @end ``` #### 5.1.2 解码器实现 ```objc // CustomAttachmentDecoder.m - (id)decodeAttachment:(NSString *)content { id attachment; NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; if (data) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; if ([dict isKindOfClass:[NSDictionary class]]) { int first = [dict[@"first"] intValue]; int second = [dict[@"second"] intValue]; id originalData = dict[@"data"]; AttachmentModel *model = [[AttachmentModel alloc] init]; model.first = (short)first; model.second = (short)second; model.data = originalData; attachment = model; } } return attachment; } ``` ### 5.2 消息类型定义 自定义消息通过`AttachmentModel`定义结构: ```objc @interface AttachmentModel : NSObject @property (nonatomic, assign) short first; // 消息类型标识 @property (nonatomic, assign) short second; // 消息子类型标识 @property (nonatomic, strong) id data; // 消息数据内容 @end ``` ### 5.3 消息类型示例 ```objc // 打招呼消息 if (attachment.first == CustomMessageType_FindNew && attachment.second == Custom_Message_Find_New_Greet_New_User) { // 处理新用户打招呼消息 FindNewGreetMessageModel *greetInfo = [FindNewGreetMessageModel modelWithDictionary:attachment.data]; // 显示打招呼弹窗 } ``` ## 6. 登录管理 ### 6.1 登录状态检查 ```objc // 检查是否已登录 if ([NIMSDK sharedSDK].loginManager.isLogined) { // 已登录,执行相关操作 } else { // 未登录,跳转登录页面 } ``` ### 6.2 自动登录处理 ```objc // NIMLoginManagerDelegate - (void)onAutoLoginFailed:(NSError *)error { // 如果非上次登录设备 autoLogin 会返回 417 if (error.code == 417) { @weakify(self); AccountModel* accountModel = [AccountInfoStorage instance].getCurrentAccountInfo; [[NIMSDK sharedSDK].loginManager login:accountModel.uid token:accountModel.netEaseToken completion:^(NSError * _Nullable error) { if (error) { @strongify(self); [self.presenter logout]; } }]; return; } [self.presenter logout]; } ``` ### 6.3 踢出处理 ```objc // NIMLoginManagerDelegate - (void)onKickout:(NIMLoginKickoutResult *)result { // 显示踢出提示 [XNDJTDDLoadingTool showErrorWithMessage:YMLocalizedString(@"TabbarViewController0")]; // 清理房间状态 if ([XPRoomMiniManager shareManager].getRoomInfo) { [[RtcManager instance] exitRoom]; [[NIMSDK sharedSDK].chatroomManager exitChatroom:roomId completion:nil]; [self.roomMineView hiddenRoomMiniView]; } // 执行登出 [self.presenter logout]; } ``` ### 6.4 手动登录 ```objc // 执行登录 [[NIMSDK sharedSDK].loginManager login:accountModel.uid token:accountModel.netEaseToken completion:^(NSError * _Nullable error) { if (error) { // 登录失败处理 NSLog(@"登录失败: %@", error); } else { // 登录成功处理 NSLog(@"登录成功"); } }]; ``` ## 7. 消息接收处理 ### 7.1 消息接收代理 ```objc // NIMChatManagerDelegate - (void)onRecvMessages:(NSArray *)messages { if ([AccountInfoStorage instance].getTicket.length == 0) { return; } for (NIMMessage *message in messages) { if (message.session.sessionType == NIMSessionTypeP2P) { if (message.messageType == NIMMessageTypeCustom) { NIMCustomObject *obj = (NIMCustomObject *)message.messageObject; if (obj.attachment != nil && [obj.attachment isKindOfClass:[AttachmentModel class]]) { AttachmentModel *attachment = (AttachmentModel *)obj.attachment; // 处理自定义消息 [self handleCustomMessage:attachment]; } } } } } ``` ### 7.2 自定义消息处理 ```objc - (void)handleCustomMessage:(AttachmentModel *)attachment { switch (attachment.first) { case CustomMessageType_FindNew: [self handleFindNewMessage:attachment]; break; case CustomMessageType_Gift: [self handleGiftMessage:attachment]; break; default: break; } } - (void)handleFindNewMessage:(AttachmentModel *)attachment { if (attachment.second == Custom_Message_Find_New_Greet_New_User) { FindNewGreetMessageModel *greetInfo = [FindNewGreetMessageModel modelWithDictionary:attachment.data]; if (greetInfo.uid.integerValue != [AccountInfoStorage instance].getUid.integerValue) { // 显示打招呼弹窗 [self showGreetAlert:greetInfo]; } } } ``` ### 7.3 广播消息处理 ```objc // NIMBroadcastManagerDelegate - (void)onReceiveBroadcastMessage:(NIMBroadcastMessage *)broadcastMessage { if ([AccountInfoStorage instance].getUid.length == 0) { return; } // 处理广播消息 NSString *content = broadcastMessage.content; // 解析并处理广播内容 } ``` ## 8. 推送通知集成 ### 8.1 推送权限申请 ```objc - (void)registerNot { if (@available(iOS 10.0, *)) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted) { [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) { dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] registerForRemoteNotifications]; }); } }]; } }]; } } ``` ### 8.2 设备Token更新 ```objc - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // 上传devicetoken至云信服务器 [[NIMSDK sharedSDK] updateApnsToken:deviceToken]; } ``` ### 8.3 推送消息处理 ```objc - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSString *data = userInfo[@"data"]; if (data) { NSDictionary *dataDic = [data mj_JSONObject]; NSString *userId = dataDic[@"uid"]; if (userId) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:kOpenRoomNotification object:nil userInfo:@{@"type": @"kOpenChat", @"uid": userId, @"isNoAttention": @(YES)}]; ClientConfig *config = [ClientConfig shareConfig]; config.pushChatId = userId; }); return; } } completionHandler(UIBackgroundFetchResultNewData); } ``` ### 8.4 应用状态处理 ```objc - (void)applicationDidEnterBackground:(UIApplication *)application { // 设置应用角标为未读消息数 NSInteger count = [NIMSDK sharedSDK].conversationManager.allUnreadCount; [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count]; } - (void)applicationDidBecomeActive:(UIApplication *)application { // 应用激活时清除角标 [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; [[NSNotificationCenter defaultCenter] postNotificationName:@"kAppDidBecomeActive" object:nil]; } ``` ## 9. 最佳实践 ### 9.1 初始化最佳实践 1. **在应用启动时初始化**: 在`AppDelegate`的`didFinishLaunchingWithOptions`中调用 2. **配置环境参数**: 区分开发和生产环境的配置 3. **注册自定义解码器**: 在SDK注册后立即注册自定义解码器 4. **设置代理**: 在适当的时机添加和移除代理 ### 9.2 登录管理最佳实践 1. **自动登录**: 优先使用自动登录,减少用户等待时间 2. **错误处理**: 对登录失败进行适当的错误处理和重试 3. **状态同步**: 保持本地登录状态与服务器状态同步 4. **踢出处理**: 妥善处理被踢出的情况,清理相关状态 ### 9.3 消息处理最佳实践 1. **消息过滤**: 根据业务需求过滤不需要的消息 2. **自定义消息**: 合理设计自定义消息结构 3. **性能优化**: 避免在消息处理中进行耗时操作 4. **内存管理**: 及时释放不需要的消息对象 ### 9.4 推送通知最佳实践 1. **权限申请**: 在合适的时机申请推送权限 2. **Token更新**: 及时更新设备Token 3. **消息解析**: 正确解析推送消息内容 4. **状态处理**: 根据应用状态处理推送消息 ## 10. 常见问题 ### 10.1 初始化问题 **Q: SDK初始化失败怎么办?** A: 检查AppKey是否正确,网络连接是否正常,证书配置是否正确。 **Q: 自定义解码器注册失败?** A: 确保在SDK注册后注册解码器,解码器类实现了正确的协议。 ### 10.2 登录问题 **Q: 自动登录失败,错误码417?** A: 这是正常情况,表示非上次登录设备,需要重新输入账号密码登录。 **Q: 登录后立即被踢出?** A: 检查账号是否在其他设备登录,或者Token是否过期。 ### 10.3 消息问题 **Q: 自定义消息无法解析?** A: 检查消息格式是否正确,解码器是否正确注册。 **Q: 消息发送失败?** A: 检查网络连接,登录状态,以及消息内容格式。 ### 10.4 推送问题 **Q: 推送通知无法接收?** A: 检查推送权限是否开启,证书配置是否正确,设备Token是否正确上传。 **Q: 推送消息解析错误?** A: 检查推送消息格式,确保解析逻辑正确。 ## 11. 总结 本项目对NIMSDK的集成非常完整,包括: 1. **完整的初始化流程**: 从SDK注册到配置参数设置 2. **自定义消息处理**: 实现了自定义附件解码器 3. **登录状态管理**: 包含自动登录、踢出处理等 4. **推送通知集成**: 完整的APNS推送处理 5. **消息接收处理**: 支持自定义消息类型的处理 6. **多环境配置**: 区分开发和生产环境的配置 整个集成方案遵循了NIMSDK的最佳实践,代码结构清晰,功能完整,为项目的即时通讯功能提供了坚实的基础。 --- **文档版本**: 1.0 **最后更新**: 2024年12月 **维护人员**: 开发团队