你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開發利用系統推送Notifaction和輪詢實現簡單聊天系統

iOS開發利用系統推送Notifaction和輪詢實現簡單聊天系統

編輯:IOS開發綜合

話不多說,先看一下做好的聊天軟件界面:

\

<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPgo8c3Ryb25nPjxicj4KPC9zdHJvbmc+CjxzdHJvbmc+PC9zdHJvbmc+CjxwPgo8c3Ryb25nPsrXz8jU2lN0b3J5Qm9hcmTA783PwcvSu7j2VUl0YWJsZVZpZXe6zdK7uPZ2aWV308PAtMrkyOvOxNfWu/LV39Pv0vSjrNPSsd+1xLC0xaXTw8C0x9C7u87E19a6zdPv0vSjujwvc3Ryb25nPjwvcD4KPGltZyBzcmM9"/uploadfile/Collfiles/20140813/20140813085629125.png" alt="\">
聊天裡有三種id: orderID :聊天id messageID :每條消息的ID sessionID :每個訂單的會話ID,如果為空通過orderID請求。

然後在viewDidLoad裡做一些界面上的操作和一些初始化的操作:
1.設置一下tableview的headView
\

2.初始化錄音、用戶頭像、獲取訂單詳情
    //初始換錄音
    [self initRecord];
    //獲取用戶頭像
    [self getHeadImg];
    //獲取訂單詳情
    [self getOrderDetailInfo];
3.在viewWillAppear裡: a.注冊了一些鍵盤和聊天消息的通知 b.啟動了一個20秒的NSTimer輪詢獲取聊天消息
c.self.chatArray讀取數據庫的聊天消息,如果數組為空返回,如果不為空刷新tableview d .如果是從評價頁面過來,刷新訂單狀態
4.看一下輪詢消息的代碼:
#pragma mark - 輪詢消息
- (void)runLoopMessage {
    SpeakType speaker = [YCChatInfo getSpeakerPassengerBy:self.orderInfo.bigType];
    [[YCReceiveMessageCenter defaultMessageCenter] getMessageListBySpeaker:speaker
                                     isRemote:NO
                                    andPushId:nil];
}
第一句代碼是獲取會話類型,這裡定義了一個枚舉值,主要有以下幾個角色:
//會話類型
enum SpeakType {
    //Business
    YCDriverType     = 11,
    YCPassenger      = 12,
    YCSystem         = 13,      //v5.2.2 增加系統角色
    YCLoctionAutoReply  = 14,  //v5.2.2添加本地自動回復
    YCDriverAutoReply   = 15,  //v5.2.2添加司機自動回復 司機角色
    YCLoctionUpdateVersionReply = 16, //v5.2.2 未知消息類型回復 【提示不支持的消息類型。請升級】
};
typedef NSInteger SpeakType;
然後根據會話類型去請求聊天list接口,然後請求成功後對數據進行處理:
        //isRemote 點擊推送欄消息
        if (response && [response[@"ret_code"] integerValue] == 200) {
            NSArray *array = response[@"result"];
            id topVC = [[YCAppDelegate sharedDelegate] topViewController];
            __block NSString *orderID = nil;
            __block NSString *dType = nil;
            [array enumerateObjectsUsingBlock:^(NSDictionary *result, NSUInteger idx, BOOL *stop) {
                NSString *type = [self controlMessageDispatch:result];
                dType = type;
       		//此處省略五百字
            }
        } else {
            DLog(@"輪詢數據失敗 response = %@, error = %@", response, error);
        }

如果code == 200的時候證明請求成功,然後用數組取出所有的聊天消息,然後用enumerateObjectsUsingBlock方法便利數組裡每個元素,每個元素即一條聊天消息。然後通過controlMessageDispatch來獲取消息的類型(dType):
typedef NS_ENUM(NSInteger, ClassType) {
   OrderClass = 1,
   ChatClass = 2,
   UserClass = 3,
};
第一個是訂單類型消息,第二個是聊天類型消息,第三個是賬戶消息。 如果是訂單消息,根據type去判斷是什麼狀態,然後去發不同的Notification。如果是聊天類型把result傳入:
- (void)receiveChatMessage:(id)object
方法,然後有一個消息狀態字段kChatRepeatState,如果kChatRepeatState == 20,表示已讀消息,直接返回。如果不是,用content初始化YCChatInfo:
NSDictionary *content = dic[@"content"];
YCChatInfo *item;
item = [[YCChatInfo alloc] initWithDictionary:content];
然後去判斷ChatType,有以下幾種:
//聊天 類型
enum ChatType {
    ChatText       = 1,
    ChatImage      = 2,
    ChatAudio      = 3,
    ChatPOI        = 4,
    ChatMix        = 5, //混合內容
    ChatCard       = 6,//v5.2.2卡片消息
    ChatUpdateHint     = 701 //v5.2.2不支持類型升級提示
    
};
typedef NSInteger ChatType;

如果是語音消息,需要異步先去請求下載語音消息,下載完後先顯示到界面上同事置為未讀消息然後再儲存到數據庫裡,然後回到主線程發NotifactionName:kChatMessageNotification通知聊天界面接收到聊天信息,展示到界面後然後存到數據庫中:
[[NSNotificationCenter defaultCenter] postNotificationName:kChatMessageNotification
                                                    object:nil
                                                  userInfo:@{@"chatInfo" : chatInfo}];
[self.chatStore insertChat:chatInfo];
這裡上次有個bug,聊天消息去重之後一直收不到語音消息,就是因為我先把新聊天消息先插入數據,然後再去發通知,導致往界面上顯示聊天消息是總是顯示不上去。

如果是文字消息,把state置為MessageRead已讀,然後發Notifaction通知聊天頁面,然後存到數據庫,如果是其他消息類型,把content改為“不支持的消息類型|您的當前版本過低,點擊升級客戶端”,然後在發出通知,存到數據庫裡。

如果是第三種賬戶消息,顯示小紅點,然後發Notifaction通知viewcontroller消息中心有新消息。 接著獲取到dType後
//首先判斷是否是推送消息, 且判斷該條點擊的推送id進入的
                if (isRemote && [pushId isEqualToString:result[@"id"]]) {
                    if (!orderID && ([type isEqualToString:@"new_chat"] ||
                                     [type isEqualToString:@"DRIVER_ARRIVE"] ||
                                     [type isEqualToString:@"RECEPTION_DRIVER"]||
                                     [type isEqualToString:@"SERVICE_DONE"])) {
                        if ([type isEqualToString:@"new_chat"]) {
                            orderID = result[@"content"][@"topic"];
                        } else if (![topVC isKindOfClass:[YCSelectDriverViewController class]] &&
                                   ([type isEqualToString:@"DRIVER_ARRIVE"] ||
                                    [type isEqualToString:@"RECEPTION_DRIVER"] ||
                                    [type isEqualToString:@"SERVICE_DONE"])) {
                                       orderID = result[@"content"][@"order_id"];
                        }
                    }
                }
            }];
            if (orderID) {
                if ([DefaultValueForKey(kShowWelcome) boolValue]) {
                    if (![topVC isKindOfClass:[YCWelcomeVC class]]) {
                        [[NSNotificationCenter defaultCenter] postNotificationName:kRemotePushVC
                                                                            object:nil
                                                                          userInfo:@{@"orderID" : orderID,
                                                                                     @"type":dType}];
                    }
                }
            }

首先判斷是否是推送消息, 且判斷該條點擊的推送id進入的,如果orderID不存在且如果type是新聊天消息或司機已到達或者司機接單或者服務結束就進入if判斷裡,然後在判斷type是不是聊天,如果是聊天orderID是content裡的topic字段,如果不是新聊天且當前最頂層ViewController不是YCSelectDriverViewController類且type是司機已到達或者司機接單或者服務結束就進入if判斷裡,orderID是content裡的order_id字段。
如果orderID存在的情況下先判斷歡迎頁面是不是顯示過,然後再判斷當前最頂層ViewController不是歡迎頁類,然後就發出Notifaction,然後通知view跳轉到指定的ViewController頁面。
當接收到聊天消息,經過一系列數據處理後,發出通知,然後YCChatViewController裡會接到通知調用- (void)receiveMessage:(NSNotification *)notification方法:
- (void)receiveMessage:(NSNotification *)notification {
    YCChatInfo *chatInfo  = notification.userInfo[@"chatInfo"];
    //如果此時來的消息不輸入當前會話 頁面不進行操作
    NSString *string1 = [[NSString alloc] initWithFormat:@"%@", chatInfo.orderID];
    NSString *string2 = [[NSString alloc] initWithFormat:@"%@", self.orderInfo.serverOrderId];
    if (![string1 isEqualToString:string2]) {
        return ;
    }
    NSInteger messageID = chatInfo.messageID;
    YCChatStore *chatStore = [[YCChatStore alloc]init];
    BOOL isNotRepeat = [chatStore selectDBwithMessageID:messageID];
    if (!isNotRepeat) {
        return;
    }
    [self insertRowToTableViewByIndexPath:chatInfo isSend:NO];
}
第一句話是獲取通知裡傳的聊天消息內容,然後拿chatinfo裡的orderID和通過獲取訂單詳情的接口裡獲得的orderID做比較,如果orderID不一致,直接return。如果一直就去YCChatStore裡的selectDBwithMessageID方法裡查詢數據庫是否有相同的messageID存在,如果存在直接return,如果不存在就插入界面
- (NSIndexPath *)insertRowToTableViewByIndexPath:(YCChatInfo *)chatInfo isSend:(BOOL)isSend {
    NSIndexPath *indexPath;
    [self.chatArray addObject:chatInfo];
    
    indexPath = [NSIndexPath indexPathForRow:[self.chatArray count] - 1
                                   inSection:0];
    void(^ScrollBlock)() = ^{
        DLog(@"%d",indexPath.row);
        [self.tableView scrollToRowAtIndexPath:indexPath
                              atScrollPosition:UITableViewScrollPositionBottom
                                      animated:YES];
    };
    [self.tableView insertRowsAtIndexPaths:@[indexPath]
                          withRowAnimation:YCTableViewRowAnimationFromBottom
                                completion:^{
                                    if (isSend) {
                                        ScrollBlock();
                                    }
    }];
    
    if (!isSend) {
        ScrollBlock();
    }
    
    return indexPath;
}

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated這個方法是把第幾個indexpath滑動到tableview的最底部, - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths
withRowAnimation:(YCTableViewRowAnimation)animation
completion:(void(^)(void))animationCompletion
這是插入時候的一個動畫效果。
簡單介紹一下聊天系統裡邊所有model、view、controller相關類的名字和功能:
MODEL:
YCChatInfo: 主要定義了聊天接口裡所有用到字段的定義,聊天相關的枚舉信息和聊天消息的一些BOOL判斷。 YCChatStore :主要是對聊天數據進行數據庫的建表、插入、刪除、查詢、去重、更新等操作。 YCChatRequest :封裝了聊天相關的網絡請求。 YCChatRecord:主要是錄音相關的一些封裝,包括開始錄音、結束錄音、獲取錄音時長、音頻格式轉化、以及通過SessionID獲取音頻路徑。 YCReceiveMessageCenter:相當於NotifactionCenter,是聊天消息處理的一個消息中心,所有接受的聊天消息和發送的聊天消息都會經過MessageCenter處理。
Views:
YCChatTableView :繼承tableview的類,裡邊重寫了tableview的插入動畫,就是每次來新消息時候的插入動畫。 YCChatBaseCell : 聊天裡所有的cell都繼承自此cell(文字、語音,未來還可能包括圖片、地理位置等等)裡邊主要定義了聊天時間的Label、背景圖片、頭像、司機名、發送時候的loading
YCChatAudioCell :語音聊天cell,包括播放按鈕、小紅點提示、錄音時間label
YCChatImageCell :系統中暫時沒有用到,可能是為以後聊天可以發圖片做准備 YCChatTextCell : 發送文字聊天cell
YCHeadView :頭像cell
YCRecordView : 聊天界面中按住說話的view
YCOrderRecordView :這個是下單中按住說話的view跟聊天系統沒關系
YCPlayButton :播放音頻按鈕
YCChatDriverAcceptCardCell :5.2.3版本新增預訂成功卡片
YCChatJourneyStartCell : 5.2.3版本新增司機已出發、司機已就位卡片
YCChatUpdatHintCell : 不支持類型,升級提示

Controllers:
YCChatViewController :聊天的主界面
YCChatMenuViewController:聊天右側的按鈕 YCShareJourneyCardVC:預訂成功卡片的詳細頁 YCChatMapVC:聊天卡片裡的地圖
















  1. 上一頁:
  2. 下一頁:
Copyright © Ios教程網 All Rights Reserved