!4 iOS sdk init

Merge pull request !4 from Siter/master
This commit is contained in:
远方夕阳 2020-11-25 14:41:25 +08:00 committed by Gitee
commit 9f94692734
56 changed files with 3997 additions and 0 deletions

View File

@ -0,0 +1,23 @@
//
// CIMHeader.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#ifndef CIMHeader_h
#define CIMHeader_h
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMSendMessageData.h"
#import "CIMService.h"
#endif /* CIMHeader_h */

View File

@ -0,0 +1,103 @@
//
// CIMMessageObserver.h
// CIMKit
//
// Created by mason on 2020/11/18.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "CIMMessageModel.h"
@class CIMService;
/// 消息回调
@protocol CIMPeerMessageObserver <NSObject>
/// 接受到消息
/// @param msg msg description
-(void)cimHandleMessage:(CIMMessageModel * _Nonnull)msg;
/// 消息解析失败
/// @param data data description
-(void)cimHandleMessageError:(NSData * _Nonnull)data;
@end
/// 服务器连接回调
@protocol CIMConnectionObserver <NSObject>
@optional
/// 用户绑定成功
/// @param bindSuccess bindSuccess description
-(void)cimDidBindUserSuccess:(BOOL)bindSuccess;
/// 连接成功
-(void)cimDidConnectSuccess;
/// 断开连接
-(void)cimDidConnectClose;
/// 连接失败
/// @param error res description
-(void)cimDidConnectError:(NSError *_Nullable)error;
@end
NS_ASSUME_NONNULL_BEGIN
@interface CIMService : NSObject
+(CIMService*)instance;
/// 配置IM服务器
/// @param host host description
/// @param port port description
-(void)configHost:(NSString *)host onPort:(NSInteger)port;
/// 连接服务器并绑定用户
/// @param userId userId description
-(void)connectionBindUserId:(NSString *)userId;
/// 添加消息监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 添加连接状态监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 移除监听
/// @param observer observer description
-(void)removeMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 移除监听回调
/// @param observer observer description
-(void)removeConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 退出后台 断开连接
-(void)enterBackground;
/// 进入前台重新连接
-(void)enterForeground;
/// 重新连接
-(void)reconnect;
/// 断开连接
-(void)disconnect;
@end
NS_ASSUME_NONNULL_END

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>BundleSDK.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>CIMKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
</dict>
<key>CimKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:CIMKit.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "738DD480-4B9A-428F-9E08-217C62231C5A"
type = "0"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
<BreakpointContent
uuid = "31134BDC-4640-4F6F-88B2-50F52FC3C0F6"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
breakpointStackSelectionBehavior = "1"
scope = "1"
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -0,0 +1,16 @@
//
// AViewController.h
// CIMKit
//
// Created by mason on 2020/11/19.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AViewController : UIViewController
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,41 @@
//
// AViewController.m
// CIMKit
//
// Created by mason on 2020/11/19.
//
#import "AViewController.h"
#import "CIMService.h"
@interface AViewController ()<CIMPeerMessageObserver>
@end
@implementation AViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.whiteColor;
[[CIMService instance] addMessageObserver:self];
}
- (void)cimhandleMessage:(CIMMessageModel *)msg{
NSLog(@"AViewController:%@",msg.content);
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

View File

@ -0,0 +1,15 @@
//
// AppDelegate.h
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end

View File

@ -0,0 +1,47 @@
//
// AppDelegate.m
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import "AppDelegate.h"
#import "CIMHeader.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application{
[[CIMService instance] enterBackground];
}
- (void)applicationWillEnterForeground:(UIApplication *)application{
[[CIMService instance] enterForeground];
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end

View File

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,23 @@
//
// CIMHeader.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#ifndef CIMHeader_h
#define CIMHeader_h
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMSendMessageData.h"
#import "CIMService.h"
#endif /* CIMHeader_h */

View File

@ -0,0 +1,50 @@
//
// CIMMessageDeCode.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import <Foundation/Foundation.h>
#import "CIMService.h"
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMSendMessageData.h"
#import "ReplyBody.pbobjc.h"
NS_ASSUME_NONNULL_BEGIN
typedef enum CIMMessageType: NSUInteger {
CIMMessageTypeC_H_RS = 0,//客户端心跳响应
CIMMessageTypeS_H_RQ,//服务端心跳请求
CIMMessageTypeMESSAGE,//服务端推送的消息
CIMMessageTypeSENT_BODY,//客户端发送的sentBody请求
CIMMessageTypeREPLY_BODY//sentBody请求的异步响应replyBody
} CIMMessageType;
@interface CIMMessageHandler : NSObject
/// 处理服务数据
/// @param data data description
-(void)doCode:(nullable NSData *)data socket:(GCDAsyncSocket *)sock;
-(void)addPeerMessageObservers:(id<CIMPeerMessageObserver>)objects;
-(void)addConnectionObservers:(id<CIMConnectionObserver>)objects;
-(void)removePeerMessageObservers:(id<CIMPeerMessageObserver>)objects;
-(void)removeConnectionObservers:(id<CIMConnectionObserver>)objects;
-(void)handlerMessage:(CIMMessageModel *)message;
-(void)handlerMessageError:(NSData *)data;
-(void)handlerBindUser:(BOOL)bindSuccess;
-(void)handlerConnectSuccess;
-(void)handlerConnectClose;
-(void)handlerConnectError:(NSError *)error;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,228 @@
//
// CIMMessageDeCode.m
// CIMKit
//
// Created by Siter By:750692607@qq.com on 2020/11/13.
//
#import "CIMMessageHandler.h"
@interface CIMMessageHandler()
@property(strong,nonatomic)NSData * data;
@property(strong,nonatomic)NSMutableArray * connectionObservers;
@property(strong,nonatomic)NSMutableArray * messageObservers;
@property(copy,nonatomic)NSString *mainQueueLabel;
@end
@implementation CIMMessageHandler
- (instancetype)init
{
self = [super init];
if (self) {
const char *label = dispatch_queue_get_label(dispatch_get_main_queue());
self.mainQueueLabel = label ? [[NSString alloc] initWithUTF8String:label] : @"";
self.connectionObservers = [NSMutableArray array];
self.messageObservers = [NSMutableArray array];
}
return self;
}
///
/// @param data data description
-(void)doCode:(nullable NSData *)data socket:(GCDAsyncSocket *)sock{
self.data = data;
//TLV
int allDateLenght = [self getMessageVauleLenght] + 3;
do {
[sock readDataWithTimeout:-1 tag:0];
} while (self.data.length != allDateLenght);
NSData *headTagData = [data subdataWithRange:NSMakeRange(0, 1)];//
CIMMessageType messageType = (CIMMessageType)[headTagData convertDataToHexStr].integerValue;
//
if(messageType == CIMMessageTypeS_H_RQ){
[sock writeData:[CIMSendMessageData initHeartbeatData] withTimeout:-1 tag:0];
return;
}
//
if(messageType == CIMMessageTypeREPLY_BODY){
NSData * messageData = [data subdataWithRange:NSMakeRange(3, [self getMessageVauleLenght])];
NSError * error;
ReplyBodyModel * replyBodyModel = [[ReplyBodyModel alloc] initWithData:messageData error:&error];
if(!error){
[self handlerBindUser:[replyBodyModel.code isEqualToString:@"200"]];
}else{
[self handlerBindUser:NO];
}
return;
}
//
if(messageType == CIMMessageTypeMESSAGE){
NSData * messageData = [data subdataWithRange:NSMakeRange(3, [self getMessageVauleLenght])];
NSError * error;
MessageModel * messgae = [[MessageModel alloc] initWithData:messageData error:&error];
if(!error){
//
[self handlerMessage:[CIMMessageModel initWithProtoMdoel:messgae]];
}else{
[self handlerMessageError:data];
}
return;
}
}
#pragma mark Observe methods
-(void)handlerConnectSuccess{
[self runOnMainThread:^{
for (NSValue *value in self.messageObservers) {
id<CIMConnectionObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimDidConnectSuccess)]) {
[ob cimDidConnectSuccess];
}
}
}];
}
-(void)handlerConnectError:(NSError *)error{
[self runOnMainThread:^{
for (NSValue *value in self.messageObservers) {
id<CIMConnectionObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimDidConnectError:)]) {
[ob cimDidConnectError:error];
}
}
}];
}
-(void)handlerMessage:(CIMMessageModel *)message{
[self runOnMainThread:^{
for (NSValue *value in self.messageObservers) {
id<CIMPeerMessageObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimHandleMessage:)]) {
[ob cimHandleMessage:message];
}
}
}];
}
-(void)handlerMessageError:(NSData *)data{
[self runOnMainThread:^{
for (NSValue *value in self.messageObservers) {
id<CIMPeerMessageObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimHandleMessageError:)]) {
[ob cimHandleMessageError:data];
}
}
}];
}
-(void)handlerConnectClose{
[self runOnMainThread:^{
for (NSValue *value in self.messageObservers) {
id<CIMConnectionObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimDidConnectClose)]) {
[ob cimDidConnectClose];
}
}
}];
}
-(void)handlerBindUser:(BOOL)bindSuccess{
[self runOnMainThread:^{
for (NSValue *value in self.connectionObservers) {
id<CIMConnectionObserver> ob = [value nonretainedObjectValue];
if ([ob respondsToSelector:@selector(cimDidBindUserSuccess:)]) {
[ob cimDidBindUserSuccess:bindSuccess];
}
}
}];
}
-(void)addPeerMessageObservers:(id<CIMPeerMessageObserver>)objects{
NSValue *value = [NSValue valueWithNonretainedObject:objects];
if (![self.messageObservers containsObject:value]) {
[self.messageObservers addObject:value];
}
}
-(void)addConnectionObservers:(id<CIMConnectionObserver>)objects{
NSValue *value = [NSValue valueWithNonretainedObject:objects];
if (![self.connectionObservers containsObject:value]) {
[self.connectionObservers addObject:value];
}
}
-(void)removePeerMessageObservers:(id<CIMPeerMessageObserver>)objects{
NSValue *value = [NSValue valueWithNonretainedObject:objects];
if (![self.messageObservers containsObject:value]) {
[self.messageObservers removeObject:value];
}
}
-(void)removeConnectionObservers:(id<CIMConnectionObserver>)objects{
NSValue *value = [NSValue valueWithNonretainedObject:objects];
if ([self.connectionObservers containsObject:value]) {
[self.connectionObservers removeObject:value];
}
}
#pragma mark private methods
-(void)runOnQueue:(NSString*)queueLabel block:(dispatch_block_t)block {
const char *s = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
NSString *label = s ? [[NSString alloc] initWithUTF8String:s] : @"";
if ([queueLabel isEqualToString:label]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), ^{
block();
});
}
}
-(void)runOnMainThread:(dispatch_block_t)block {
[self runOnQueue:self.mainQueueLabel block:block];
}
/// data
-(int)getMessageVauleLenght{
NSData * lv = [self.data subdataWithRange:NSMakeRange(1, 1)];
NSData * hv = [self.data subdataWithRange:NSMakeRange(2, 1)];
int lvString = [[lv convertDataToHexStr] hexToDecimal].intValue;
int hvString = [[hv convertDataToHexStr] hexToDecimal].intValue;
return lvString | hvString << 8;
}
- (NSData *)data{
if(!_data){
_data = [[NSData alloc] init];
}
return _data;
}
@end

View File

@ -0,0 +1,23 @@
//
// CIMSendMessage.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface CIMSendMessageData : NSObject
/// 心跳包数据
+(NSData *)initHeartbeatData;
/// 绑定用户数据
/// @param userId userId description
+(NSData *)initBindUserData:(NSString *)userId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,81 @@
//
// CIMSendMessage.m
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import "CIMSendMessageData.h"
#import "CIMHeader.h"
#import "SentBody.pbobjc.h"
#import <UIKit/UIDevice.h>
@implementation CIMSendMessageData
///
+(NSData *)initHeartbeatData{
NSData * model = [@"CR" convertBytesStringToData];
NSInteger lenght = model.length;
Byte type = 0;
Byte head[3] ;
head[0] = type;
head[1] = lenght & 0xff;
head[2] = (lenght >> 8) & 0xff;
NSMutableData * sendData = [[NSMutableData alloc] initWithBytes:head length:3];
[sendData appendData:model];
return sendData;
}
///
/// @param userId userId description
+(NSData *)initBindUserData:(NSString *)userId{
SentBodyModel * body = [SentBodyModel new];
body.key = @"client_bind";
body.timestamp = (int64_t)[NSDate timeIntervalSinceReferenceDate] *1000;
body.data_p[@"account"] = userId;
body.data_p[@"deviceId"] = [[self class] deviceId];
body.data_p[@"channel"] = @"ios";
NSData *modeData = body.data;
NSInteger lenght = modeData.length;
Byte type = 3;
Byte head[3] ;
head[0] = type;
head[1] = lenght & 0xff;
head[2] = (lenght >> 8) & 0xff;
NSMutableData * sendData = [[NSMutableData alloc] initWithBytes:head length:3];
[sendData appendData:modeData];
return sendData;
}
+(NSData *)initMessageData:(NSString *)userId{
SentBodyModel * body = [SentBodyModel new];
body.key = @"client_bind";
body.timestamp = (int64_t)[NSDate timeIntervalSinceReferenceDate] *1000;
body.data_p[@"account"] = userId;
body.data_p[@"deviceId"] = [[self class] deviceId];
body.data_p[@"channel"] = @"ios";
NSData *modeData = body.data;
NSInteger lenght = modeData.length;
Byte type = 3;
Byte head[3] ;
head[0] = type;
head[1] = lenght & 0xff;
head[2] = (lenght >> 8) & 0xff;
NSMutableData * sendData = [[NSMutableData alloc] initWithBytes:head length:3];
[sendData appendData:modeData];
return sendData;
}
+(NSString *)deviceId{
return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
}
@end

View File

@ -0,0 +1,36 @@
//
// CIMMessageModel.h
// CIMKit
//
// Created by mason on 2020/11/19.
//
#import <Foundation/Foundation.h>
#import "Message.pbobjc.h"
NS_ASSUME_NONNULL_BEGIN
@interface CIMMessageModel : NSObject
@property(nonatomic, readwrite) int64_t id_p;
@property(nonatomic, readwrite, copy) NSString *action;
@property(nonatomic, readwrite, copy) NSString *content;
@property(nonatomic, readwrite, copy) NSString *sender;
@property(nonatomic, readwrite, copy) NSString *receiver;
@property(nonatomic, readwrite, copy) NSString *extra;
@property(nonatomic, readwrite, copy) NSString *title;
@property(nonatomic, readwrite, copy) NSString *format;
@property(nonatomic, readwrite) int64_t timestamp;
+(CIMMessageModel *)initWithProtoMdoel:(MessageModel *)model;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,28 @@
//
// CIMMessageModel.m
// CIMKit
//
// Created by mason on 2020/11/19.
//
#import "CIMMessageModel.h"
@implementation CIMMessageModel
+(CIMMessageModel *)initWithProtoMdoel:(MessageModel *)model{
CIMMessageModel * cimMessageModel = [CIMMessageModel new];
cimMessageModel.id_p = model.id_p;
cimMessageModel.title = model.title;
cimMessageModel.action = model.action;
cimMessageModel.timestamp = model.timestamp;
cimMessageModel.extra = model.extra;
cimMessageModel.format = model.format;
cimMessageModel.sender = model.sender;
cimMessageModel.content = model.content;
cimMessageModel.receiver = model.receiver;
return cimMessageModel;
}
@end

View File

@ -0,0 +1,89 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Message.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers.h>
#else
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CF_EXTERN_C_BEGIN
NS_ASSUME_NONNULL_BEGIN
#pragma mark - MessageRoot
/**
* Exposes the extension registry for this file.
*
* The base class provides:
* @code
* + (GPBExtensionRegistry *)extensionRegistry;
* @endcode
* which is a @c GPBExtensionRegistry that includes all the extensions defined by
* this file and all files that it depends on.
**/
@interface MessageRoot : GPBRootObject
@end
#pragma mark - Model
typedef GPB_ENUM(MessageModel_FieldNumber) {
MessageModel_FieldNumber_Id_p = 1,
MessageModel_FieldNumber_Action = 2,
MessageModel_FieldNumber_Content = 3,
MessageModel_FieldNumber_Sender = 4,
MessageModel_FieldNumber_Receiver = 5,
MessageModel_FieldNumber_Extra = 6,
MessageModel_FieldNumber_Title = 7,
MessageModel_FieldNumber_Format = 8,
MessageModel_FieldNumber_Timestamp = 9,
};
@interface MessageModel : GPBMessage
@property(nonatomic, readwrite) int64_t id_p;
@property(nonatomic, readwrite, copy, null_resettable) NSString *action;
@property(nonatomic, readwrite, copy, null_resettable) NSString *content;
@property(nonatomic, readwrite, copy, null_resettable) NSString *sender;
@property(nonatomic, readwrite, copy, null_resettable) NSString *receiver;
@property(nonatomic, readwrite, copy, null_resettable) NSString *extra;
@property(nonatomic, readwrite, copy, null_resettable) NSString *title;
@property(nonatomic, readwrite, copy, null_resettable) NSString *format;
@property(nonatomic, readwrite) int64_t timestamp;
@end
NS_ASSUME_NONNULL_END
CF_EXTERN_C_END
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,181 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Message.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers_RuntimeSupport.h>
#else
#import "GPBProtocolBuffers_RuntimeSupport.h"
#endif
#import "Message.pbobjc.h"
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma mark - MessageRoot
@implementation MessageRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - MessageRoot_FileDescriptor
static GPBFileDescriptor *MessageRoot_FileDescriptor(void) {
// This is called by +initialize so there is no need to worry
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@""
syntax:GPBFileSyntaxProto3];
}
return descriptor;
}
#pragma mark - Model
@implementation MessageModel
@dynamic id_p;
@dynamic action;
@dynamic content;
@dynamic sender;
@dynamic receiver;
@dynamic extra;
@dynamic title;
@dynamic format;
@dynamic timestamp;
typedef struct Model__storage_ {
uint32_t _has_storage_[1];
NSString *action;
NSString *content;
NSString *sender;
NSString *receiver;
NSString *extra;
NSString *title;
NSString *format;
int64_t id_p;
int64_t timestamp;
} Model__storage_;
// This method is threadsafe because it is initially called
// in +initialize for each subclass.
+ (GPBDescriptor *)descriptor {
static GPBDescriptor *descriptor = nil;
if (!descriptor) {
static GPBMessageFieldDescription fields[] = {
{
.name = "id_p",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Id_p,
.hasIndex = 0,
.offset = (uint32_t)offsetof(Model__storage_, id_p),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
},
{
.name = "action",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Action,
.hasIndex = 1,
.offset = (uint32_t)offsetof(Model__storage_, action),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "content",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Content,
.hasIndex = 2,
.offset = (uint32_t)offsetof(Model__storage_, content),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "sender",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Sender,
.hasIndex = 3,
.offset = (uint32_t)offsetof(Model__storage_, sender),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "receiver",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Receiver,
.hasIndex = 4,
.offset = (uint32_t)offsetof(Model__storage_, receiver),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "extra",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Extra,
.hasIndex = 5,
.offset = (uint32_t)offsetof(Model__storage_, extra),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "title",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Title,
.hasIndex = 6,
.offset = (uint32_t)offsetof(Model__storage_, title),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "format",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Format,
.hasIndex = 7,
.offset = (uint32_t)offsetof(Model__storage_, format),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "timestamp",
.dataTypeSpecific.className = NULL,
.number = MessageModel_FieldNumber_Timestamp,
.hasIndex = 8,
.offset = (uint32_t)offsetof(Model__storage_, timestamp),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
},
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:[MessageModel class]
rootClass:[MessageRoot class]
file:MessageRoot_FileDescriptor()
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(Model__storage_)
flags:GPBDescriptorInitializationFlag_None];
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
}
@end
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,79 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: ReplyBody.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers.h>
#else
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CF_EXTERN_C_BEGIN
NS_ASSUME_NONNULL_BEGIN
#pragma mark - ReplyBodyRoot
/**
* Exposes the extension registry for this file.
*
* The base class provides:
* @code
* + (GPBExtensionRegistry *)extensionRegistry;
* @endcode
* which is a @c GPBExtensionRegistry that includes all the extensions defined by
* this file and all files that it depends on.
**/
@interface ReplyBodyRoot : GPBRootObject
@end
#pragma mark - Model
typedef GPB_ENUM(ReplyBodyModel_FieldNumber) {
ReplyBodyModel_FieldNumber_Key = 1,
ReplyBodyModel_FieldNumber_Code = 2,
ReplyBodyModel_FieldNumber_Message = 3,
ReplyBodyModel_FieldNumber_Timestamp = 4,
ReplyBodyModel_FieldNumber_Data_p = 5,
};
@interface ReplyBodyModel : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *key;
@property(nonatomic, readwrite, copy, null_resettable) NSString *code;
@property(nonatomic, readwrite, copy, null_resettable) NSString *message;
@property(nonatomic, readwrite) int64_t timestamp;
@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, NSString*> *data_p;
/** The number of items in @c data_p without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger data_p_Count;
@end
NS_ASSUME_NONNULL_END
CF_EXTERN_C_END
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,137 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: ReplyBody.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers_RuntimeSupport.h>
#else
#import "GPBProtocolBuffers_RuntimeSupport.h"
#endif
#import "ReplyBody.pbobjc.h"
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma mark - ReplyBodyRoot
@implementation ReplyBodyRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - ReplyBodyRoot_FileDescriptor
static GPBFileDescriptor *ReplyBodyRoot_FileDescriptor(void) {
// This is called by +initialize so there is no need to worry
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@""
syntax:GPBFileSyntaxProto3];
}
return descriptor;
}
#pragma mark - Model
@implementation ReplyBodyModel
@dynamic key;
@dynamic code;
@dynamic message;
@dynamic timestamp;
@dynamic data_p, data_p_Count;
typedef struct Model__storage_ {
uint32_t _has_storage_[1];
NSString *key;
NSString *code;
NSString *message;
NSMutableDictionary *data_p;
int64_t timestamp;
} Model__storage_;
// This method is threadsafe because it is initially called
// in +initialize for each subclass.
+ (GPBDescriptor *)descriptor {
static GPBDescriptor *descriptor = nil;
if (!descriptor) {
static GPBMessageFieldDescription fields[] = {
{
.name = "key",
.dataTypeSpecific.className = NULL,
.number = ReplyBodyModel_FieldNumber_Key,
.hasIndex = 0,
.offset = (uint32_t)offsetof(Model__storage_, key),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "code",
.dataTypeSpecific.className = NULL,
.number = ReplyBodyModel_FieldNumber_Code,
.hasIndex = 1,
.offset = (uint32_t)offsetof(Model__storage_, code),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "message",
.dataTypeSpecific.className = NULL,
.number = ReplyBodyModel_FieldNumber_Message,
.hasIndex = 2,
.offset = (uint32_t)offsetof(Model__storage_, message),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "timestamp",
.dataTypeSpecific.className = NULL,
.number = ReplyBodyModel_FieldNumber_Timestamp,
.hasIndex = 3,
.offset = (uint32_t)offsetof(Model__storage_, timestamp),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
},
{
.name = "data_p",
.dataTypeSpecific.className = NULL,
.number = ReplyBodyModel_FieldNumber_Data_p,
.hasIndex = GPBNoHasBit,
.offset = (uint32_t)offsetof(Model__storage_, data_p),
.flags = GPBFieldMapKeyString,
.dataType = GPBDataTypeString,
},
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:[ReplyBodyModel class]
rootClass:[ReplyBodyRoot class]
file:ReplyBodyRoot_FileDescriptor()
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(Model__storage_)
flags:GPBDescriptorInitializationFlag_None];
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
}
@end
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,73 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: SentBody.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers.h>
#else
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CF_EXTERN_C_BEGIN
NS_ASSUME_NONNULL_BEGIN
#pragma mark - SentBodyRoot
/**
* Exposes the extension registry for this file.
*
* The base class provides:
* @code
* + (GPBExtensionRegistry *)extensionRegistry;
* @endcode
* which is a @c GPBExtensionRegistry that includes all the extensions defined by
* this file and all files that it depends on.
**/
@interface SentBodyRoot : GPBRootObject
@end
#pragma mark - Model
typedef GPB_ENUM(Model_FieldNumber) {
Model_FieldNumber_Key = 1,
Model_FieldNumber_Timestamp = 2,
Model_FieldNumber_Data_p = 3,
};
@interface SentBodyModel : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *key;
@property(nonatomic, readwrite) int64_t timestamp;
@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, NSString*> *data_p;
/** The number of items in @c data_p without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger data_p_Count;
@end
NS_ASSUME_NONNULL_END
CF_EXTERN_C_END
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,118 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: SentBody.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers_RuntimeSupport.h>
#else
#import "GPBProtocolBuffers_RuntimeSupport.h"
#endif
#import "SentBody.pbobjc.h"
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma mark - SentBodyRoot
@implementation SentBodyRoot
// No extensions in the file and no imports, so no need to generate
// +extensionRegistry.
@end
#pragma mark - SentBodyRoot_FileDescriptor
static GPBFileDescriptor *SentBodyRoot_FileDescriptor(void) {
// This is called by +initialize so there is no need to worry
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@""
syntax:GPBFileSyntaxProto3];
}
return descriptor;
}
#pragma mark - Model
@implementation SentBodyModel
@dynamic key;
@dynamic timestamp;
@dynamic data_p, data_p_Count;
typedef struct Model__storage_ {
uint32_t _has_storage_[1];
NSString *key;
NSMutableDictionary *data_p;
int64_t timestamp;
} Model__storage_;
// This method is threadsafe because it is initially called
// in +initialize for each subclass.
+ (GPBDescriptor *)descriptor {
static GPBDescriptor *descriptor = nil;
if (!descriptor) {
static GPBMessageFieldDescription fields[] = {
{
.name = "key",
.dataTypeSpecific.className = NULL,
.number = Model_FieldNumber_Key,
.hasIndex = 0,
.offset = (uint32_t)offsetof(Model__storage_, key),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeString,
},
{
.name = "timestamp",
.dataTypeSpecific.className = NULL,
.number = Model_FieldNumber_Timestamp,
.hasIndex = 1,
.offset = (uint32_t)offsetof(Model__storage_, timestamp),
.flags = GPBFieldOptional,
.dataType = GPBDataTypeInt64,
},
{
.name = "data_p",
.dataTypeSpecific.className = NULL,
.number = Model_FieldNumber_Data_p,
.hasIndex = GPBNoHasBit,
.offset = (uint32_t)offsetof(Model__storage_, data_p),
.flags = GPBFieldMapKeyString,
.dataType = GPBDataTypeString,
},
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:[SentBodyModel class]
rootClass:[SentBodyRoot class]
file:SentBodyRoot_FileDescriptor()
fields:fields
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(Model__storage_)
flags:GPBDescriptorInitializationFlag_None];
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
}
@end
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)

View File

@ -0,0 +1,103 @@
//
// CIMMessageObserver.h
// CIMKit
//
// Created by mason on 2020/11/18.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "CIMMessageModel.h"
@class CIMService;
/// 消息回调
@protocol CIMPeerMessageObserver <NSObject>
/// 接受到消息
/// @param msg msg description
-(void)cimHandleMessage:(CIMMessageModel * _Nonnull)msg;
/// 消息解析失败
/// @param data data description
-(void)cimHandleMessageError:(NSData * _Nonnull)data;
@end
/// 服务器连接回调
@protocol CIMConnectionObserver <NSObject>
@optional
/// 用户绑定成功
/// @param bindSuccess bindSuccess description
-(void)cimDidBindUserSuccess:(BOOL)bindSuccess;
/// 连接成功
-(void)cimDidConnectSuccess;
/// 断开连接
-(void)cimDidConnectClose;
/// 连接失败
/// @param error res description
-(void)cimDidConnectError:(NSError *_Nullable)error;
@end
NS_ASSUME_NONNULL_BEGIN
@interface CIMService : NSObject
+(CIMService*)instance;
/// 配置IM服务器
/// @param host host description
/// @param port port description
-(void)configHost:(NSString *)host onPort:(NSInteger)port;
/// 连接服务器并绑定用户
/// @param userId userId description
-(void)connectionBindUserId:(NSString *)userId;
/// 添加消息监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 添加连接状态监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 移除监听
/// @param observer observer description
-(void)removeMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 移除监听回调
/// @param observer observer description
-(void)removeConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 退出后台 断开连接
-(void)enterBackground;
/// 进入前台重新连接
-(void)enterForeground;
/// 重新连接
-(void)reconnect;
/// 断开连接
-(void)disconnect;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,164 @@
//
// CIMMessageObserver.m
// CIMKit
//
// Created by mason on 2020/11/18.
//
#import "CIMService.h"
#import "CIMSendMessageData.h"
#import "CIMMessageHandler.h"
@interface CIMService()<GCDAsyncSocketDelegate>
@property (assign, nonatomic)BOOL deBugLog;
@property(nonatomic,copy,readonly)NSString * host;
@property(nonatomic,assign,readonly)NSInteger port;
@property (strong, nonatomic) GCDAsyncSocket * clientSocket;
@property (strong, nonatomic)dispatch_queue_t queue;
@property (strong, nonatomic)CIMMessageHandler *handler;
@property (copy, nonatomic)NSString *userId;
@end
@implementation CIMService
+(CIMService*)instance {
static CIMService *imService;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!imService) {
imService = [[CIMService alloc] init];
}
});
return imService;
}
-(id)init {
self = [super init];
if (self) {
}
return self;
}
-(void)configHost:(NSString *)host onPort:(NSInteger)port{
_host = host;
_port = port;
}
- (void)connectionBindUserId:(NSString *)userId{
if(userId.length == 0){
[self.handler handlerBindUser:NO];
return;
}
self.userId = userId;
NSAssert(self.host.length > 1, @"定调用configHost 配置host和port");
NSAssert(self.port > 1, @"定调用configHost 配置host和port");
//
NSError *error;
[self.clientSocket connectToHost:self.host onPort:self.port error:&error];
if (error) {
[self.handler handlerConnectError:error];
}else{
NSLog(@"socket 成功");
[self.clientSocket writeData:[CIMSendMessageData initBindUserData:userId] withTimeout:-1 tag:0];
}
}
#pragma mark Observe
- (void)addMessageObserver:(id<CIMPeerMessageObserver>)observer{
[self.handler addPeerMessageObservers:observer];
}
- (void)addConnectionObserver:(id<CIMConnectionObserver>)observer{
[self.handler addConnectionObservers:observer];
}
- (void)removeMessageObserver:(id<CIMPeerMessageObserver>)observer{
[self.handler removePeerMessageObservers:observer];
}
- (void)removeConnectionObserver:(id<CIMConnectionObserver>)observer{
[self.handler removeConnectionObservers:observer];
}
#pragma mark -Connection methods
-(void)enterBackground{
if(self.clientSocket.isConnected){
[self.clientSocket disconnect];
}
}
-(void)enterForeground{
if(!self.clientSocket.isConnected){
[self connectionBindUserId:self.userId];
}
}
-(void)reconnect{
if(!self.clientSocket.isConnected){
[self connectionBindUserId:self.userId];
}
}
-(void)disconnect{
if(self.clientSocket.isConnected){
[self.clientSocket disconnect];
self.clientSocket = nil;
}
}
#pragma mark - GCDAsyncSocketDelegate
//
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
NSLog(@"socket 连接成功");
[self.clientSocket readDataWithTimeout:-1 tag:0];
[self.handler handlerConnectSuccess];
}
//
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSLog(@"socket 断开连接%@",err.localizedDescription);
[self.handler handlerConnectClose];
}
//
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
[self.clientSocket readDataWithTimeout:-1 tag:0];
//
NSLog(@"didReadData");
[self.handler doCode:data socket:sock];
}
#pragma mark lazy
- (GCDAsyncSocket *)clientSocket{
if(!_clientSocket){
self.queue = dispatch_queue_create("com.cim.IMQueue", DISPATCH_QUEUE_CONCURRENT);
_clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:self.queue];
}
return _clientSocket;
}
- (CIMMessageHandler *)handler{
if(!_handler){
_handler = [[CIMMessageHandler alloc] init];
}
return _handler;
}
@end

View File

@ -0,0 +1,20 @@
//
// NSData+IM.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSData (IM)
- (NSString *)convertDataToHexStr;
+ (NSString *)convertDataToHexStr:(NSData *)data;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,57 @@
//
// NSData+IM.m
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import "NSData+IM.h"
@implementation NSData (IM)
- (NSString *)convertDataToHexStr{
if (!self || [self length] == 0) {
return @"";
}
NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[self length]];
[self enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i = 0; i < byteRange.length; i++) {
NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
if ([hexStr length] == 2) {
[string appendString:hexStr];
} else {
[string appendFormat:@"0%@", hexStr];
}
}
}];
return string;
}
+ (NSString *)convertDataToHexStr:(NSData *)data
{
if (!data || [data length] == 0) {
return @"";
}
NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i = 0; i < byteRange.length; i++) {
NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
if ([hexStr length] == 2) {
[string appendString:hexStr];
} else {
[string appendFormat:@"0%@", hexStr];
}
}
}];
return string;
}
@end

View File

@ -0,0 +1,24 @@
//
// NSString+IM.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (IM)
-(NSData*) convertBytesStringToData ;
- (NSString *)hexToDecimal ;
//data -> 16进制
+(NSString *)hexStringFormData:(NSData *)data;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,155 @@
//
// NSString+IM.m
// CIMKit
//
// Created by mason on 2020/11/13.
//
#import "NSString+IM.h"
#
@implementation NSString (IM)
/**
stringNSData
@return NSData
*/
-(NSData*) convertBytesStringToData {
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= self.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [self substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
/**
@return
*/
- (NSString *)decimalToHex {
long long int tmpid = [self intValue];
NSString *nLetterValue;
NSString *str = @"";
long long int ttmpig;
for (int i = 0; i < 9; i++) {
ttmpig = tmpid % 16;
tmpid = tmpid / 16;
switch (ttmpig) {
case 10:
nLetterValue = @"A";
break;
case 11:
nLetterValue = @"B";
break;
case 12:
nLetterValue = @"C";
break;
case 13:
nLetterValue = @"D";
break;
case 14:
nLetterValue = @"E";
break;
case 15:
nLetterValue = @"F";
break;
default:
nLetterValue = [[NSString alloc]initWithFormat:@"%lli", ttmpig];
}
str = [nLetterValue stringByAppendingString:str];
if (tmpid == 0) {
break;
}
}
return str;
}
/**
length 0
@return
*/
- (NSString *)decimalToHexWithLength:(NSUInteger)length{
NSString* subString = [self decimalToHex];
NSUInteger moreL = length - subString.length;
if (moreL>0) {
for (int i = 0; i<moreL; i++) {
subString = [NSString stringWithFormat:@"0%@",subString];
}
}
return subString;
}
/**
@return
*/
- (NSString *)hexToDecimal {
return [NSString stringWithFormat:@"%lu",strtoul([self UTF8String],0,16)];
}
/*
@return
*/
- (NSString *)binaryToDecimal {
int ll = 0 ;
int temp = 0 ;
for (int i = 0; i < self.length; i ++) {
temp = [[self substringWithRange:NSMakeRange(i, 1)] intValue];
temp = temp * powf(2, self.length - i - 1);
ll += temp;
}
NSString * result = [NSString stringWithFormat:@"%d",ll];
return result;
}
/**
@return
*/
- (NSString *)decimalToBinary {
NSInteger num = [self integerValue];
NSInteger remainder = 0; //
NSInteger divisor = 0; //
NSString * prepare = @"";
while (true) {
remainder = num%2;
divisor = num/2;
num = divisor;
prepare = [prepare stringByAppendingFormat:@"%d",(int)remainder];
if (divisor == 0) {
break;
}
}
NSString * result = @"";
for (NSInteger i = prepare.length - 1; i >= 0; i --) {
result = [result stringByAppendingFormat:@"%@",
[prepare substringWithRange:NSMakeRange(i , 1)]];
}
return [NSString stringWithFormat:@"%08d",[result intValue]];
}
+(NSString *)hexStringFormData:(NSData *)data
{
return [[[[NSString stringWithFormat:@"%@",data]
stringByReplacingOccurrencesOfString:@"<" withString:@""]
stringByReplacingOccurrencesOfString:@">" withString:@""]
stringByReplacingOccurrencesOfString:@" " withString:@""];
}
@end

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleShortVersionString</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,15 @@
//
// SceneDelegate.h
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import <UIKit/UIKit.h>
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow * window;
@end

View File

@ -0,0 +1,61 @@
//
// SceneDelegate.m
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import "SceneDelegate.h"
#import "CIMHeader.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidEnterBackground:(UIScene *)scene{
[[CIMService instance] enterBackground];
}
- (void)sceneWillEnterForeground:(UIScene *)scene{
[[CIMService instance] enterForeground];
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
@end

View File

@ -0,0 +1,14 @@
//
// ViewController.h
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

View File

@ -0,0 +1,88 @@
//
// ViewController.m
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import "ViewController.h"
#import "SocketRocket.h"
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMHeader.h"
#import "AViewController.h"
@interface ViewController ()<GCDAsyncSocketDelegate,CIMPeerMessageObserver,CIMConnectionObserver>
@property (strong, nonatomic) SRWebSocket *imWebSocket;
@property (strong, nonatomic) GCDAsyncSocket * clientSocket;
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self presentViewController:[AViewController new] animated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.redColor;
[[CIMService instance] configHost:@"192.168.51.197" onPort:23456];
[[CIMService instance] connectionBindUserId:@"111111"];
[[CIMService instance] addMessageObserver:self];
[[CIMService instance] addConnectionObserver:self];
[[CIMService instance] removeMessageObserver:self];
[[CIMService instance] removeConnectionObserver:self];
}
- (void)cimDidConnectClose{
NSLog(@"cimDidConnectClose");
}
- (void)cimDidConnectError:(NSError *)error{
NSLog(@"cimDidConnectError");
}
- (void)cimDidConnectSuccess{
NSLog(@"cimDidConnectSuccess");
}
- (void)cimDidBindUserSuccess:(BOOL)bindSuccess{
NSLog(@"cimDidBindUserSuccess");
}
- (void)cimHandleMessage:(CIMMessageModel *)msg{
NSLog(@"ViewController:%@\nu用户%@(%lld)\n---------",msg.content,msg.sender,msg.timestamp);
}
- (void)cimHandleMessageError:(NSData *)data{
NSLog(@"cimHandleMessageError");
}
@end

View File

@ -0,0 +1,18 @@
//
// main.m
// CIMKit
//
// Created by mason on 2020/11/7.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

View File

@ -0,0 +1,36 @@
//
// CimKitTests.m
// CimKitTests
//
// Created by mason on 2020/11/21.
//
#import <XCTest/XCTest.h>
@interface CimKitTests : XCTestCase
@end
@implementation CimKitTests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,47 @@
//
// CIMKitUITests.m
// CIMKitUITests
//
// Created by mason on 2020/11/7.
//
#import <XCTest/XCTest.h>
@interface CIMKitUITests : XCTestCase
@end
@implementation CIMKitUITests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// UI tests must launch the application that they test.
XCUIApplication *app = [[XCUIApplication alloc] init];
[app launch];
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testLaunchPerformance {
if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
// This measures how long it takes to launch your application.
[self measureWithMetrics:@[[[XCTApplicationLaunchMetric alloc] init]] block:^{
[[[XCUIApplication alloc] init] launch];
}];
}
}
@end

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,31 @@
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'CIMKit' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for CIMKit
pod "SocketRocket", '~> 0.5.1'
pod "Protobuf", '~> 3.13.0'
pod "CocoaAsyncSocket", '~> 7.6.4'
target 'CimKit' do
pod "SocketRocket", '~> 0.5.1'
pod "Protobuf", '~> 3.13.0'
pod "CocoaAsyncSocket", '~> 7.6.4'
end
target 'CIMKitTests' do
inherit! :search_paths
# Pods for testing
end
target 'CIMKitUITests' do
# Pods for testing
end
end

View File

@ -0,0 +1,24 @@
PODS:
- CocoaAsyncSocket (7.6.4)
- Protobuf (3.13.0)
- SocketRocket (0.5.1)
DEPENDENCIES:
- CocoaAsyncSocket (~> 7.6.4)
- Protobuf (~> 3.13.0)
- SocketRocket (~> 0.5.1)
SPEC REPOS:
trunk:
- CocoaAsyncSocket
- Protobuf
- SocketRocket
SPEC CHECKSUMS:
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
PODFILE CHECKSUM: fe21b8def5ac502f6af111678a5b83f7c4803c28
COCOAPODS: 1.9.3

View File

@ -0,0 +1,23 @@
//
// CIMHeader.h
// CIMKit
//
// Created by mason on 2020/11/13.
//
#ifndef CIMHeader_h
#define CIMHeader_h
#import "GCDAsyncSocket.h"
#import "SentBody.pbobjc.h"
#import "Message.pbobjc.h"
#import "NSData+IM.h"
#import "NSString+IM.h"
#import "CIMSendMessageData.h"
#import "CIMService.h"
#endif /* CIMHeader_h */

View File

@ -0,0 +1,103 @@
//
// CIMMessageObserver.h
// CIMKit
//
// Created by mason on 2020/11/18.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "CIMMessageModel.h"
@class CIMService;
/// 消息回调
@protocol CIMPeerMessageObserver <NSObject>
/// 接受到消息
/// @param msg msg description
-(void)cimHandleMessage:(CIMMessageModel * _Nonnull)msg;
/// 消息解析失败
/// @param data data description
-(void)cimHandleMessageError:(NSData * _Nonnull)data;
@end
/// 服务器连接回调
@protocol CIMConnectionObserver <NSObject>
@optional
/// 用户绑定成功
/// @param bindSuccess bindSuccess description
-(void)cimDidBindUserSuccess:(BOOL)bindSuccess;
/// 连接成功
-(void)cimDidConnectSuccess;
/// 断开连接
-(void)cimDidConnectClose;
/// 连接失败
/// @param error res description
-(void)cimDidConnectError:(NSError *_Nullable)error;
@end
NS_ASSUME_NONNULL_BEGIN
@interface CIMService : NSObject
+(CIMService*)instance;
/// 配置IM服务器
/// @param host host description
/// @param port port description
-(void)configHost:(NSString *)host onPort:(NSInteger)port;
/// 连接服务器并绑定用户
/// @param userId userId description
-(void)connectionBindUserId:(NSString *)userId;
/// 添加消息监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 添加连接状态监听回调
/// @param observer observer description (可添加多个)不同时记得Remove
-(void)addConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 移除监听
/// @param observer observer description
-(void)removeMessageObserver:(id<CIMPeerMessageObserver>)observer;
/// 移除监听回调
/// @param observer observer description
-(void)removeConnectionObserver:(id<CIMConnectionObserver>)observer;
/// 退出后台 断开连接
-(void)enterBackground;
/// 进入前台重新连接
-(void)enterForeground;
/// 重新连接
-(void)reconnect;
/// 断开连接
-(void)disconnect;
@end
NS_ASSUME_NONNULL_END

BIN
doc/CimKit iOS教程.pdf Normal file

Binary file not shown.