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

來源:互聯網
上載者:User

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

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




首先在StoryBoard裡拖了一個UItableView和一個view用來輸入文字或者語音,右邊的按鈕用來切換文字和語音:


聊天裡有三種id:orderID :聊天idmessageID :每條訊息的IDsessionID :每個訂單的會話ID,如果為空白通過orderID請求。

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


2.初始化錄音、帳戶圖片、擷取訂單詳情
    //初始換錄音    [self initRecord];    //擷取帳戶圖片    [self getHeadImg];    //擷取訂單詳情    [self getOrderDetailInfo];
3.在viewWillAppear裡:a.註冊了一些鍵盤和聊天訊息的通知b.啟動了一個20秒的NSTimer輪詢擷取聊天訊息
c.self.chatArray讀取資料庫的聊天訊息,如果數組為空白返回,如果不為空白重新整理tableviewd .如果是從評價頁面過來,重新整理訂單狀態
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:聊天卡片裡的地圖
















聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.