{"id":20732403,"url":"https://github.com/jpush/jchat-ios","last_synced_at":"2025-06-12T06:33:50.582Z","repository":{"id":31538889,"uuid":"35103468","full_name":"jpush/jchat-ios","owner":"jpush","description":"JChat iOS app, a real app based on JMessage SDK.","archived":false,"fork":false,"pushed_at":"2019-08-28T01:54:53.000Z","size":50919,"stargazers_count":101,"open_issues_count":9,"forks_count":35,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-04-23T22:07:31.530Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://docs.jiguang.cn","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jpush.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-05T14:05:40.000Z","updated_at":"2025-02-16T10:56:24.000Z","dependencies_parsed_at":"2022-09-04T16:00:47.103Z","dependency_job_id":null,"html_url":"https://github.com/jpush/jchat-ios","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpush%2Fjchat-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpush%2Fjchat-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpush%2Fjchat-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jpush%2Fjchat-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jpush","download_url":"https://codeload.github.com/jpush/jchat-ios/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250522299,"owners_count":21444511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T05:19:13.925Z","updated_at":"2025-04-23T22:08:31.131Z","avatar_url":"https://github.com/jpush.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JChat iOS\n## JChat-iOS 现在只处理 bug，不再添加新功能，新功能将会在 [jchat-swift](https://github.com/jpush/jchat-swift) 上更新。\n### 介绍\n\nJChat 是一个聊天 App。\n\nJChat 具有完备的即时通讯功能。主要有：\n\n- 基本的聊天类型：文本、语音、图片；\n- 单聊与群聊；\n- 用户属性，包括头像；\n- 黑名单；\n- 好友通讯录；\n- [消息同步功能](https://github.com/jpush/jchat-ios/releases/tag/v3.1.0)\n\nJChat 的功能基于 JMessage SDK 来开发。它是一个 JMessage SDK 的完备的 Demo，但不仅仅是 Demo。我们的预期与目标是，当你的业务需要一个企业级的聊天 App 时，可以基于这里提供的源代码，更换 Logo 与应用名称，就可以直接用上。\n\nJChat 当前提供 Android 与 iOS 版本。稍后也将提供 Web 版本。\n\n- [JChat Android](https://github.com/jpush/jchat-android)\n\n### 运行\n\n本源代码项目要编译运行跑起来，需要注意以下几个地方。\n- 工程使用 cocoapods 管理依赖如果没有安装 pod 需要先行安装 👉 [CocoaPods](https://cocoapods.org) \n- 成功安装 cocoapods 后在终端执行如下命令安装依赖（在 Podfile 文件所在目录）\n```\npod install\n```\n##### 打开项目文件 JChat.xcworkspace\n- 因为这是一个 [CocoaPods](https://cocoapods.org) 项目。打开 .xcodeproj 项目目录将缺少依赖。\n\n\t\n##### 配置运行的基本属性\n\n- appKey：JPush appKey 是 JMessage SDK 运行的基本参数。请到 [JPush 官方网站](https://jpush.cn)登录控制台创建应用获取。\n- bundle_id：这是一个 iOS 应用的基本属性。你需要登录到 Apple 开发者网站去创建应用。\n\n### JMessage 文档\n\n- [JMessage iOS 集成指南](http://docs.jpush.io/guideline/jmessage_ios_guide/)\n- [JMessage iOS 说明](http://docs.jpush.io/client/im_sdk_ios/)\n- [JMessage iOS API Docs](http://docs.jpush.io/client/jmessage_ios_appledoc_html/)\n\n### JMessage 升级\n\nJMessage 当前版本为 2.0.x。与之前 1.0.x 版本有比较大的变更。\n\n因为变更太大，所以这次变更有点不够友好，大部分 API 有调整，包括对象结构。这会导致集成 JMessage SDK 1.0.x 版本的 App 切换到新版本时，会编译不通过，某些 API 调用需要调整。调整的具体思路，可参考本项目 JChat iOS 源代码，以及 JMessage iOS 相关文档。\n\n## JChat 介绍\n\n## JChat 工程结构\n![如图](https://github.com/jpush/jchat-ios/blob/master/READMERecource/JChat流程图.png)\n\n## JChat 代码结构\n主要分为五个功能模块：用户详情 (UserInfo)，会话列表 (Conversation List)，会话 (Conversation) 登录 (Login) 和 设置 (Setting)。每个功能模块按照 MVC 模式划分，部分模块还有一些 Util 类。\n\nCustomUI\n自定义 View\n\nCategory\n通用 Category\n\nUtil\n通用辅助类\n\n## 主要功能索引\n### JMessage 初始化代码\n建议在 AppDelegate didFinishLaunchingWithOptions 方式初始化，如JChat 所示\n```\n- (BOOL)application:(UIApplication *)application\ndidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  [self initLogger];\n\n  // init third-party SDK\n  [JMessage addDelegate:self withConversation:nil];// 这句代码放到前面目的是，应用启动是会做数据库是否升级盘点，如果需要升级，则锁定数据库，进行升级\n  \n  [JMessage setupJMessage:launchOptions\n                   appKey:JMSSAGE_APPKEY\n                  channel:CHANNEL apsForProduction:NO\n                 category:nil];\n  \n  [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |\n                                                    UIUserNotificationTypeSound |\n                                                    UIUserNotificationTypeAlert)\n                                        categories:nil];\n  \n  [self registerJPushStatusNotification];\n  \n  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\n  self.window.rootViewController = [UIViewController new];\n  [self.window makeKeyAndVisible];\n  [self setupMainTabBar];\n  [self setupRootView];\n  \n  [JCHATFileManager initWithFilePath];//demo 初始化存储路径\n  \n  return YES;\n}\n\n```\n\n注册SDK\n注册APNS\n成功获得APNS token 传入JPUSHService 如下代码所示\n```\n- (void)application:(UIApplication *)application\ndidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {\n  [JPUSHService registerDeviceToken:deviceToken];\n}\n```\n\n### 注册 登录\n首次使用JMessage 需要有JMessage 账户，通过如下代码注册一个新用户。JChat 项目在JCHATRegisterViewController 类中执行了注册操作，并且在注册完成回调执行登录操作(登录操作也可以移动到其它地方进行，具体看程序业务)。\n```\n- (IBAction)registerBtnClick:(id)sender {\n  DDLogDebug(@\"Action - registerBtnClick\");\n  if ([self.usernameTextField.text isEqualToString:@\"\"]) {\n    [MBProgressHUD showMessage:@\"用户名不能为空\" view:self.view];\n    return;\n  }\n  \n  if ([self.passwordTextField.text isEqualToString:@\"\"]) {\n    [MBProgressHUD showMessage:@\"密码不能为空\" view:self.view];\n    return;\n  }\n  \n  [self.usernameTextField resignFirstResponder];\n  [self.passwordTextField resignFirstResponder];\n  \n  NSString *username = self.usernameTextField.text.stringByTrimingWhitespace;\n  NSString *password = self.passwordTextField.text.stringByTrimingWhitespace;\n  \n  if ([self checkValidUsername:username AndPassword:password]) {\n    [MBProgressHUD showMessage:@\"正在注册\" view:self.view];\n    [[JCHATTimeOutManager ins] startTimerWithVC:self];\n    [JMSGUser registerWithUsername:username\n                          password:password\n                 completionHandler:^(id resultObject, NSError *error) {\n                   [[JCHATTimeOutManager ins] stopTimer];\n                   if (error == nil) {\n                     [MBProgressHUD hideHUDForView:self.view animated:YES];\n                     [MBProgressHUD showMessage:@\"注册成功\" view:self.view];\n                     [[JCHATTimeOutManager ins] startTimerWithVC:self];\n                     [JMSGUser loginWithUsername:username\n                                        password:password\n                               completionHandler:^(id resultObject, NSError *error) {\n                                 [[JCHATTimeOutManager ins] stopTimer];\n                                 if (error == nil) {\n                                   [[NSUserDefaults standardUserDefaults] setObject:username forKey:kuserName];\n                                   [[NSUserDefaults standardUserDefaults] setObject:username forKey:klastLoginUserName];\n                                   \n                                   [MBProgressHUD hideAllHUDsForView:self.view animated:YES];\n                                   JCHATSetDetailViewController *detailVC = [[JCHATSetDetailViewController alloc] init];\n                                   [self.navigationController pushViewController:detailVC animated:YES];\n                                   [MBProgressHUD hideAllHUDsForView:self.view animated:YES];\n                                 } else {\n                                   DDLogDebug(@\"login fail error  %@\",error);\n                                   NSString *alert = [JCHATStringUtils errorAlert:error];\n                                   alert = [JCHATStringUtils errorAlert:error];\n                                   [MBProgressHUD hideAllHUDsForView:self.view animated:YES];\n                                   [MBProgressHUD showMessage:alert view:self.view];\n                                   DDLogError(alert);\n                                 }\n                               }];\n                   } else {\n                     NSString *alert = @\"注册失败\";\n                     alert = [JCHATStringUtils errorAlert:error];\n                     [MBProgressHUD hideHUDForView:self.view animated:YES];\n                     [MBProgressHUD showMessage:alert view:self.view];\n                   }\n                 }];\n  }\n}\n```\n注册完成会回调 handler ，如下代码。如果出现错误会返回的error 部位nil，注意resultOvject 不同接口会返回不同类型的值或者nil，详细信息可以关注 [JMessage 官方文档](http://docs.jpush.io/client/im_sdk_ios/#summary)\n```\ntypedef void (^JMSGCompletionHandler)(id resultObject, NSError *error);\n```\n\n### 会话 (Conversation)\n会话是一个用户与用户之间聊天的载体，要有会话用户之间才能收发消息\n获得会话有两种方式 1. 创建会话 2. 获取历史会话\n#### 1.创建会话\n如下代码分别创建了 单聊会话，和群聊会话, JChat 在JCHATConversationListViewController类 实现创建会话操作\n```\n\n- (void)skipToSingleChatView :(NSNotification *)notification {\n  JMSGUser *user = [[notification object] copy];\n  __block JCHATConversationViewController *sendMessageCtl =[[JCHATConversationViewController alloc] init];\n  __weak typeof(self)weakSelf = self;\n  sendMessageCtl.superViewController = self;\n  [JMSGConversation createSingleConversationWithUsername:user.username completionHandler:^(id resultObject, NSError *error) {\n    __strong __typeof(weakSelf)strongSelf = weakSelf;\n    if (error == nil) {\n      sendMessageCtl.conversation = resultObject;\n      JPIMMAINTHEAD(^{\n        sendMessageCtl.hidesBottomBarWhenPushed = YES;\n        [strongSelf.navigationController pushViewController:sendMessageCtl animated:YES];\n      });\n    } else {\n      DDLogDebug(@\"createSingleConversationWithUsername\");\n    }\n  }];\n}\n```\n\n#### 2. 获取历史会话\nJCHat在JCHATConversationListViewController类中获取所有历史会话的具体代码如下\n```\n- (void)getConversationList {\n  [self.addBgView setHidden:YES];\n  [JMSGConversation allConversations:^(id resultObject, NSError *error) {\n    NSLog(@\"the result\");\n    JPIMMAINTHEAD(^{\n      if (error == nil) {\n        _conversationArr = [self sortConversation:resultObject];\n        _unreadCount = 0;\n        for (NSInteger i=0; i \u003c [_conversationArr count]; i++) {\n          JMSGConversation *conversation = [_conversationArr objectAtIndex:i];\n          _unreadCount = _unreadCount + [conversation.unreadCount integerValue];\n        }\n        [self saveBadge:_unreadCount];\n      } else {\n        _conversationArr = nil;\n      }\n      [self.chatTableView reloadData];\n    });\n  }];\n}\n```\n#### 3. 添加代理\n若想监听conversation 的消息需要把某个对象设为conversation的delegate（可以是任何对象），比如JChat JCHATConversationViewController类需要监听发送回调，受消息回调则必须先设置代理，具体代码如下\n```\n- (void)addDelegate {\n  [JMessage addDelegate:self withConversation:self.conversation];\n}\n```\n\n#### 4. 发送消息\nJMSGMessage 是消息的实体。需要自己创建要发送的消息，JChat JCHATConversationViewController类中发送消息的代码如下\n```  \n  - (void)prepareTextMessage:(NSString *)text {\n  DDLogDebug(@\"Action - prepareTextMessage\");\n  if ([text isEqualToString:@\"\"] || text == nil) {\n    return;\n  }\n  [[JCHATSendMsgManager ins] updateConversation:_conversation withDraft:@\"\"];\n  JMSGMessage *message = nil;\n  JMSGTextContent *textContent = [[JMSGTextContent alloc] initWithText:text];\n  JCHATChatModel *model = [[JCHATChatModel alloc] init];\n  \n  message = [_conversation createMessageWithContent:textContent];\n  [_conversation sendMessage:message];// 发送该条消息\n  [self addmessageShowTimeData:message.timestamp];\n  [model setChatModelWith:message conversationType:_conversation];\n  [self addMessage:model];\n}\n```\n\n#### 5. 接收消息\n前面已经说了可以给conversation 添加回调delegate，收到消息也是通过回调函数来获取的，JChat JCHATConversationViewController类 收到消息回调方法如下\n```\n- (void)onReceiveMessage:(JMSGMessage *)message\n                   error:(NSError *)error {\n  if (error != nil) {\n    JCHATChatModel *model = [[JCHATChatModel alloc] init];\n    [model setErrorMessageChatModelWithError:error];\n    [self addMessage:model];\n    return;\n  }\n  \n  if (![self.conversation isMessageForThisConversation:message]) {\n    return;\n  }\n  \n  if (message.contentType == kJMSGContentTypeCustom) {\n    return;\n  }\n  DDLogDebug(@\"Event - receiveMessageNotification\");\n  JPIMMAINTHEAD((^{\n    if (!message) {\n      DDLogWarn(@\"get the nil message .\");\n      return;\n    }\n    \n    if (_allMessageDic[message.msgId] != nil) {\n      DDLogDebug(@\"该条消息已加载\");\n      return;\n    }\n    \n    if (message.contentType == kJMSGContentTypeEventNotification) {\n      if (((JMSGEventContent *)message.content).eventType == kJMSGEventNotificationRemoveGroupMembers\n          \u0026\u0026 ![((JMSGGroup *)_conversation.target) isMyselfGroupMember]) {\n        [self setupNavigation];\n      }\n    }\n    \n    if (_conversation.conversationType == kJMSGConversationTypeSingle) {\n    } else if (![((JMSGGroup *)_conversation.target).gid isEqualToString:((JMSGGroup *)message.target).gid]){\n      return;\n    }\n    \n    JCHATChatModel *model = [[JCHATChatModel alloc] init];\n    [model setChatModelWith:message conversationType:_conversation];\n    if (message.contentType == kJMSGContentTypeImage) {\n      [_imgDataArr addObject:model];\n    }\n    model.photoIndex = [_imgDataArr count] -1;\n    [self addmessageShowTimeData:message.timestamp];\n    [self addMessage:model];\n  }));\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpush%2Fjchat-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjpush%2Fjchat-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpush%2Fjchat-ios/lists"}