zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    windows命令行下导入excel数据到SQLite数据库
    Android Studio如何提示函数用法
    在不root手机的情况上读取Data目录上的文件
    OSI七层模型
    设计模式之代理模式
    Android中Javascript中的调用
    cf #205 B Codeforces Round #205 (Div. 2) B. Two Heaps
    uva 10600 次小生成树
    防2B && 图论模板 && 7788
    最大匹配 && 最佳完美匹配 模板
  • 原文地址:https://www.cnblogs.com/wanghang/p/6298863.html
Copyright © 2011-2022 走看看