上一篇內(nèi)容中我們已經(jīng)提到 XMPP
消息的傳遞就是 XML
串的傳遞,而用戶之間聊天內(nèi)容是處于 </Message>
節(jié)點(diǎn)中团甲。
// 這就是一個(gè)最基本的 </Message> 節(jié)點(diǎn)
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'>
<body>Thrice the brinded cat hath mew'd.</body>
</message>
那么自定義 </Message>
節(jié)點(diǎn)有什么用呢馅而?
IM 發(fā)展到現(xiàn)在 語音 、 圖片 這類二進(jìn)制文件譬圣,甚至還有一些 應(yīng)用內(nèi)分享 都逐漸成為標(biāo)配功能瓮恭,而要實(shí)現(xiàn)這些功能我們就需要 自定義 </Message>
節(jié)點(diǎn) 。
如何自定義 </Message>
節(jié)點(diǎn)
剛剛講到自定義 </Message>
節(jié)點(diǎn)的目的就是我們要實(shí)現(xiàn)一些定制功能厘熟。那么為了區(qū)分這些功能我們就自己定義一個(gè)類型放入 </Message>
節(jié)點(diǎn)中屯蹦。
// 常見的幾處放入自定義節(jié)點(diǎn)的位置
1维哈、</Message> 的屬性中
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'
customtype='customtype'>
<body>Thrice the brinded cat</body>
</message>
2、</Message> 的子節(jié)點(diǎn)中
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'>
<body>Thrice the brinded cat</customtype>
<customtype>customtype</customtype>
</message>
3登澜、</Message> 下的 </body> 節(jié)點(diǎn)中
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'>
<body> customtype | Thrice the brinded cat</body>
</message>
應(yīng)用內(nèi)分享
其實(shí)懂得在 </Message>
節(jié)點(diǎn)的什么位置插入類型字段阔挠,應(yīng)用內(nèi)分享就不是問題了,比如我想發(fā)送一個(gè)音樂類型的分享消息脑蠕。
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'>
<body>id | title | singer | second</body>
<customtype>music</customtype>
</message>
這樣我們就可以根據(jù) </customtype>
取出的字符串知道我們分享的內(nèi)容是音樂類型购撼,再從 </body>
中按規(guī)則解析我們所需要的內(nèi)容并展示在 UI 上。
二進(jìn)制文件分享
二進(jìn)制文件分享比起應(yīng)用內(nèi)分享就稍微復(fù)雜一些谴仙。大體有兩總方式:
使用普通消息類型發(fā)送
優(yōu)點(diǎn):不需要對方在線迂求,可通過離線消息獲取
缺點(diǎn):文件大小限制大
使用 XEP - 0096 文件傳輸協(xié)議發(fā)送
優(yōu)點(diǎn):文件大小基本無限制,但大文件需要分次發(fā)送
缺點(diǎn):必須得對方在線
兩總方式總的來說思路是一樣的:把文件進(jìn)行 base64
編碼轉(zhuǎn)成字符串拼接到 XML
中晃跺。我們這里暫時(shí)只討論 語音 揩局、圖片 兩總常見文件( 使用第一種方式 ),XEP - 0096 協(xié)議以后有空再細(xì)說掀虎。
語音消息
iOS 下的錄音基本為以下兩種方式:
- 使用
PCM
編碼保存為WAV
格式的音頻文件 - 使用
ACC
編碼保存為M4A
格式的音頻文件
但是這倆種方式的音頻文件都有一個(gè)共同的問題——壓縮率低凌盯。所以 我們就需要在 base64
編碼之前將音頻文件轉(zhuǎn)成一個(gè)壓縮率高的格式。
現(xiàn)在比較流行的高壓縮比格式有倆種 MP3
和 AMR
烹玉,這里因?yàn)槭橇奶觳恍枰貏e高的音質(zhì)驰怎,個(gè)人推薦使用 AMR
。
如果你需要錄音并轉(zhuǎn)成 MP3
格式春霍,推薦 iOSMp3Recorder
如果你需要錄音并轉(zhuǎn)成 AMR
格式砸西,推薦 VoiceConvert
// 使用上面?zhèn)z個(gè)開源的工具,我們可以很方便的得到錄音數(shù)據(jù)址儒,通過代理調(diào)用下面這個(gè)方法
- (void)needSendVoice:(NSData *)voice time:(NSInteger)second
{
if (voice) {
// 這里是實(shí)現(xiàn)了一個(gè)工具類快速生成 XMPPMessage 的 Body
NSString *message = [XMPPManagerHelper voiceMessageWithSecond:second];
// base64 編碼
NSString *encodeData = [voice base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
// 發(fā)送消息
[self sendFileMessage:message withEncodeData:encodeData];
}
}
// 拼接并發(fā)送消息
- (void)sendFileMessage:(NSString *)message withEncodeData:(NSString *)encodeData
{
NSString *type = _isGroupChat ? @"groupchat" : @"chat";
// 這里自定義了一個(gè) file 節(jié)點(diǎn), 將編碼完成后的字符串放入 file 節(jié)點(diǎn)中
DDXMLElement *file = [DDXMLElement elementWithName:@"file" stringValue:encodeData];
__weak typeof(self) weakSelf = self;
__block IMMessageModel *model = [getXMPPManager() sendMessage:message
to:_jid
type:type
extend:file
statusHandle:^(BOOL status)
{
NSLog(@"收到 Message 發(fā)送回調(diào) : %@", @(status));
if (status) {
model.status = IMMessageStatusCompleted;
} else {
model.status = IMMessageStatusFailed;
}
[model update];
[weakSelf loadChatDatas];
}];
[_chatDatas addObject:model];
[_tableView reloadData];
[self scrollToEndMessage];
}
最后發(fā)出的消息格式如下:
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'
id='ea430-deg'>
<body>語音</body>
<file>CZ63hd+MKX+e2ZhB2RzaXanVVVaYgQIoIXneouFGIYNtFh1QnhllldBiCyC7SkVvy+YiiEXmOKRJsG2ShTbCeBPvH8Y4IROEAv7pzyECiXd8QMkpjQGKTkFqMirbz/cq5wPE5+F7/m/Xs</file>
<customtype>Audio</customtype>
</message>
圖片消息
圖片消息與語音消息類似芹枷,只需要修改下類型就好
<message from='darkcave@chat.shakespeare.lit/firstwitch'
to='hecate@shakespeare.lit/broom'
type='groupchat'
id='ea430-det'>
<body>圖片</body>
<file>CZ63hd+MKX+e2ZhB2RzaXanVVVaYgQIoIXneouFGIYNtFh1QnhllldBiCyC7SkVvy+YiiEXmOKRJsG2ShTbCeBPvH8Y4IROEAv7pzyECiXd8QMkpjQGKTkFqMirbz/cq5wPE5+F7/m/Xs</file>
<customtype>Photo</customtype>
</message>
但針對圖片來說,現(xiàn)在大部分 IM 的做法是上傳高清圖在自己服務(wù)器莲趣,同時(shí)從 XMPP
發(fā)送一張略縮圖給對方鸳慈,這樣可以保證對方消息接收的速度,也可以留存清晰的圖片喧伞。下面給出一個(gè)生成略縮圖的方法走芋。
- (UIImage *)imageCompressScale:(float)scale
{
CGSize size = self.size;
CGFloat width = size.width;
CGFloat height = size.height;
CGFloat scaledWidth = width * scale;
CGFloat scaledHeight = height * scale;
UIGraphicsBeginImageContext(size); // this will crop
[self drawInRect:CGRectMake(0, 0, scaledWidth, scaledHeight)];
UIImage* newImage= UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}