小说网站 搜小说 无限网 烟雨红尘 小说爱好者 免费小说 免费小说网站

XMPP系列(五)---文件传输

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

posted on 2015-07-28 23:47  王小航  阅读(369)  评论(0编辑  收藏  举报

导航