xmpp中发送文件和接收文件的处理有些不太一样,接收文件处理比较简单,发送稍微复杂一些。
首先需要在XMPPFramework.h中添加文件传输类
//文件传输 //接收文件 #import "XMPPIncomingFileTransfer.h" //发送文件 #import "XMPPOutgoingFileTransfer.h"
1、文件接收
文件的接收是被动的,所以需要在XMPPStream初始化的地方加入文件接收模块:
//5、文件接收 _xmppIncomingFileTransfer = [[XMPPIncomingFileTransfer alloc] initWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)]; [_xmppIncomingFileTransfer activate:self.xmppStream]; [_xmppIncomingFileTransfer addDelegate:self delegateQueue:dispatch_get_main_queue()]; //设置为自动接收文件,当然也可以在代理方法中弹出一个alertView来让用户选择是否接收 [_xmppIncomingFileTransfer setAutoAcceptFileTransfers:YES];添加文件接收的代理XMPPIncomingFileTransferDelegate,
因为文件的接收XMPP不会为我们生成相应的消息,因此必须实现文件接收的代理方法:
#pragma mark ===== 文件接收======= /** 是否同意对方发文件给我 */ - (void)xmppIncomingFileTransfer:(XMPPIncomingFileTransfer *)sender didReceiveSIOffer:(XMPPIQ *)offer { NSLog(@"%s",__FUNCTION__); //弹出一个是否接收的询问框 // [self.xmppIncomingFileTransfer acceptSIOffer:offer]; } - (void)xmppIncomingFileTransfer:(XMPPIncomingFileTransfer *)sender didSucceedWithData:(NSData *)data named:(NSString *)name { XMPPJID *jid = [sender.senderJID copy]; NSLog(@"%s",__FUNCTION__); //在这个方法里面,我们通过带外来传输的文件 //因此我们的消息同步器,不会帮我们自动生成Message,因此我们需要手动存储message //根据文件后缀名,判断文件我们是否能够处理,如果不能处理则直接显示。 //图片 音频 (.wav,.mp3,.mp4) NSString *extension = [name pathExtension]; if (![@"wav" isEqualToString:extension]) { return; } //创建一个XMPPMessage对象,message必须要有from XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:jid]; //<span class="s1" style="font-family: 'Comic Sans MS';">给</span><span class="s2" style="font-family: 'Comic Sans MS';">Message</span><span class="s1" style="font-family: 'Comic Sans MS';">添加</span><span class="s2" style="font-family: 'Comic Sans MS';">from</span> [message addAttributeWithName:@"from" stringValue:sender.senderJID.bare]; [message addSubject:@"audio"]; //保存data NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; path = [path stringByAppendingPathComponent:[XMPPStream generateUUID]]; path = [path stringByAppendingPathExtension:@"wav"]; [data writeToFile:path atomically:YES]; [message addBody:path.lastPathComponent]; [self.xmppMessageArchivingCoreDataStorage archiveMessage:message outgoing:NO xmppStream:self.xmppStream]; }当[self.xmppMessageArchivingCoreDataStorage archiveMessage:message outgoing:NO xmppStream:self.xmppStream];执行完毕会发送通知,然后更新相应的历史消息。
2、文件发送
XMPP发送文件的功能依赖于对方客户端,在XMPPStream建立连接之后会询问对方客户端的特性,然后根据返回的特性,判断对方是否能够接收某一种类型的文件。
而XMPP支持的特性有:
<query xmlns="http://jabber.org/protocol/disco#info"> * <identity category="client" type="phone"/> * <feature var="http://jabber.org/protocol/si"/> * <feature var="http://jabber.org/protocol/si/profile/file-transfer"/> * <feature var="http://jabber.org/protocol/bytestreams"/> * <feature var="http://jabber.org/protocol/ibb"/> * </query>首先,在聊天控制器中添加一个property,并添加XMPPOutgoingFileTransferDelegate
@property (nonatomic, strong) XMPPOutgoingFileTransfer *xmppOutgoingFileTransfer;这里录一段音频,然后发送。
添加一个录音按钮,当按钮按下时开始录音startRecord:,按钮抬起时,发送录音sendRecord:,划出按钮区域取消录音cancelRecord:,
- (IBAction)startRecord:(id)sender { NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; path = [path stringByAppendingPathComponent:[XMPPStream generateUUID]]; path = [path stringByAppendingPathExtension:@"wav"]; NSURL *URL = [NSURL fileURLWithPath:path]; _recorder = [[AVAudioRecorder alloc] initWithURL:URL settings:nil error:nil]; [_recorder prepareToRecord]; [_recorder record]; } - (IBAction)sendRecord:(id)sender { [_recorder stop]; NSArray *resources = [[JKXMPPTool sharedInstance].xmppRosterMemoryStorage sortedResources:YES]; for (XMPPResourceMemoryStorageObject *object in resources) { if ([object.jid.bare isEqualToString:self.chatJID.bare]) { NSData *data = [[[NSData alloc] initWithContentsOfURL:_recorder.url] copy]; NSError *err; [self.xmppOutgoingFileTransfer sendData:data named:_recorder.url.lastPathComponent toRecipient:object.jid description:nil error:&err]; if (err) { NSLog(@"%@",err); } break; } } _recorder = nil; } - (IBAction)cancelRecord:(id)sender { [_recorder stop]; [[NSFileManager defaultManager] removeItemAtURL:_recorder.url error:nil]; _recorder = nil; }其中发送录音时的,如果发送失败,会在error中返回,失败信息,我这里用Spark做接收客户端,就返回了对方不支持的失败信息。
另外,发送文件也需要自己手动创建并保存一条消息,可以在发送成功的代理方法中创建并保存消息。
- (void)xmppOutgoingFileTransferDidSucceed:(XMPPOutgoingFileTransfer *)sender { NSLog(@"xmppOutgoingFileTransferDidSucceed"); XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatJID]; //将这个文件的发送者添加到message的from [message addAttributeWithName:@"from" stringValue:[JKXMPPTool sharedInstance].xmppStream.myJID.bare]; [message addSubject:@"audio"]; NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; path = [path stringByAppendingPathComponent:sender.outgoingFileName]; [message addBody:path.lastPathComponent]; [[JKXMPPTool sharedInstance].xmppMessageArchivingCoreDataStorage archiveMessage:message outgoing:NO xmppStream:[JKXMPPTool sharedInstance].xmppStream]; }
Demo地址:https://github.com/Joker-King/ChatDemo