xmpp整理筆記:發送圖片資訊和聲音資訊,xmpp圖片資訊

來源:互聯網
上載者:User

xmpp整理筆記:發送圖片資訊和聲音資訊,xmpp圖片資訊

圖片和音頻檔案發送的基本思路就是:

先將圖片轉化成二進位檔案,然後將二進位檔案進行base64編碼,編碼後成字串。在即將發送的message內添加一個子節點,節點的stringValue(節點的值)設定這個編碼後的字串。然後訊息發出後取出訊息檔案的時候,通過messageType 先判斷是不是圖片資訊,如果是圖片資訊先通過自己之前設定的節點名稱,把這個子節點的stringValue取出來,應該是一個base64之後的字串,

往期回顧:

xmpp整理筆記:聊天資訊的發送與顯示  http://www.cnblogs.com/dsxniubility/p/4307073.html

xmpp整理筆記:環境的快速配置(附安裝包)  http://www.cnblogs.com/dsxniubility/p/4304570.html

xmpp整理筆記:xmppFramework架構的匯入和介紹  http://www.cnblogs.com/dsxniubility/p/4307057.html

xmpp整理筆記:使用者網路連接及好友管理 http://www.cnblogs.com/dsxniubility/p/4307066.html

 一。圖片發送

如果你不是在董鉑然部落格園看到本文,請點擊查看原文

圖片是通過介面的加號點擊彈出相簿介面,然後點擊相簿中的某張圖片,相簿退下,圖片發出

- (IBAction)setPhoto {    UIImagePickerController *picker = [[UIImagePickerController alloc]init];        picker.delegate = self;        [self presentViewController:picker animated:YES completion:nil];}

 這是加號點擊方法,之後設定UIImagePickerController的代理,然後再遵守對應的協議

這裡需要注意的是,遵守了UIImagePickerControllerDelegate的 同時還必須要遵守 UINavigationControllerDelegate。協議

下面就是彈出相簿點擊了一張圖片後觸發的代理方法,都是常用方法在此也不過多解釋。

#pragma mark - ******************** imgPickerController代理方法- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{    UIImage *image = info[UIImagePickerControllerOriginalImage];        NSData *data = UIImagePNGRepresentation(image);        [self sendMessageWithData:data bodyName:@"image"];        [self dismissViewControllerAnimated:YES completion:nil];}

 其中的sendMessageWithData: bodyName: 是自訂的方法

此方法的功能就是傳入一個data二進位檔案 和 檔案的類型,就把這個檔案發出去。

之所有在後面有bodyName,讓使用者傳入一個類型名,是為了區分發送圖片和發送音頻

方法內代碼如下:

/** 發送二進位檔案 */- (void)sendMessageWithData:(NSData *)data bodyName:(NSString *)name{    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatJID];        [message addBody:name];        // 轉換成base64的編碼    NSString *base64str = [data base64EncodedStringWithOptions:0];        // 設定節點內容    XMPPElement *attachment = [XMPPElement elementWithName:@"attachment" stringValue:base64str];        // 包含子節點    [message addChild:attachment];        // 發送訊息    [[SXXMPPTools sharedXMPPTools].xmppStream sendElement:message];}

 這個方法內流程就是一開始說得,先編碼再發送。這個自訂的方法同樣適用於發送音頻資訊。

 

 

二。圖片的顯示

這個是在tableView資料來源方法中,取出資訊即將賦值之前多了一層判斷,如果是圖片資訊,採用下面的方法賦值。

 

關於基本發送流程哪裡忘了可以查看普通文本資訊的發送方法:

if ([message.body isEqualToString:@"image"]) {        XMPPMessage *msg = message.message;                for (XMPPElement *node in msg.children) {                        // 取出訊息的解碼            NSString *base64str = node.stringValue;            NSData *data = [[NSData alloc]initWithBase64EncodedString:base64str options:0];            UIImage *image = [[UIImage alloc]initWithData:data];                // 把圖片在label中顯示            NSTextAttachment *attach = [[NSTextAttachment alloc]init];            attach.image = [image scaleImageWithWidth:200];            NSAttributedString *attachStr = [NSAttributedString attributedStringWithAttachment:attach];                        // 用了這個label的屬性賦值方法,就可以忽略那個普通的賦值方法            cell.messageLabel.attributedText = attachStr;                        [self.view endEditing:YES];        }    }

 這其中用到了一個 scaleImageWithWidth:方法,這個方法是傳入一個允許的最大寬度width,然後這個方法內部先判斷,如片大小是否超過最大值,如果沒有超過最大值就是圖片有多大發多大,如果圖片的尺寸超過了最大寬度,就把圖片的整體尺寸都等比例縮小到正好等於最大寬度的尺寸。這其中要用到Quartz2D的內容相關的知識。

這個方法可以寫成UIimage的分類,代碼如下

/** 把圖片縮小到指定的寬度範圍內為止 */- (UIImage *)scaleImageWithWidth:(CGFloat)width{    if (self.size.width <width || width <= 0) {        return self;    }    CGFloat scale = self.size.width/width;    CGFloat height = self.size.height/scale;        CGRect rect = CGRectMake(0, 0, width, height);        // 開始上下文 目標大小是 這麼大    UIGraphicsBeginImageContext(rect.size);        // 在指定地區內繪製映像    [self drawInRect:rect];        // 從上下文中獲得繪製結果    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();        // 關閉上下文返回結果    UIGraphicsEndImageContext();    return resultImage;}

 

 

三。音訊發送

音訊發送,與之前圖片的發送,有一定的相似,也有一些不同。音頻發送的核心思想,是按下按鈕開始錄音,鬆開手結束錄音並且儲存錄音。因此需要處理按鈕的按下和抬手兩個監聽方法。但是其中有一個蘋果的bug: 自訂的按鈕無法同時處理TouchUpInSide 和 TouchDown。 就是按下按鈕不鬆手是一個列印,手一鬆開一個列印。這是不行的,都是手一松兩個同時列印。(除非按鈕特別大,一般小按鈕無法同時監聽這兩個點擊事件)。但是蘋果內建的系統按鈕卻可以,不管多小,比如buttonWithTypeAdd(小加號按鈕)都可以,因此設定點擊聲音按鈕之後下面出現一個inputView,上面是可以同時處理這兩個時間的按鈕。通過這個按鈕來控制開始錄音和結束錄音。儲存之後,也是轉化成data二進位檔案,然後再通過base64編碼。然後加入子節點,和圖片類似發過去。接收的時候,也是取出節點內的stringValue解碼。但是顯示在tableview的cell中的是聲音的時間,點擊這個cell觸發聲音播放時間。從而播放音頻。播放時cell內部的某些樣式變化也是可以控制的。

先把介面中的聲音按鈕的點擊事件連線。

- (IBAction)setRecord {    // 切換焦點,彈出錄音按鈕    [self.recordText becomeFirstResponder];}

 其實就是自己隨便寫了個textField 點擊時就讓他擷取焦點,然後下面彈出一個輸入框上面有按鈕

這個textField的懶載入如下

- (UITextField *)recordText {    if (_recordText == nil) {        _recordText = [[UITextField alloc] init];                UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];        _recordText.inputView = btn;                [btn addTarget:self action:@selector(startRecord) forControlEvents:UIControlEventTouchDown];        [btn addTarget:self action:@selector(stopRecord) forControlEvents:UIControlEventTouchUpInside];                [self.inputMessageView addSubview:_recordText];    }    return _recordText;}

 

對於音頻檔案的一系列處理操作,最好抽出一個工具類寫好,然後在需要的時候直接調用,並且以後其他項目也可以拖過去直接使用。

首先需要用到的屬性如下。

@interface SXRecordTools ()<AVAudioPlayerDelegate>/** 錄音器 */@property(nonatomic,strong) AVAudioRecorder *recorder;/** 錄音地址 */@property(nonatomic,strong) NSURL *recordURL;/** 播放器 */@property(nonatomic,strong) AVAudioPlayer *player;/** 播放完成時回調 */@property(nonatomic,copy) void (^palyCompletion)();@end

 至於其中的開始錄音和結束錄音方法如下

/** 開始錄音 */- (void)startRecord{    [self.recorder record];}/** 停止錄音 */- (void)stopRecordSuccess:(void (^)(NSURL *url,NSTimeInterval time))success andFailed:(void (^)())failed{    // 只有在這裡才能取到currentTime    NSTimeInterval time = self.recorder.currentTime;    [self.recorder stop];        if (time < 1.5) {        if (failed) {            failed();        }    }else{        if (success) {            success(self.recordURL,time);        }    }}

 開始錄音和結束錄音,架構中都自己有方法。主要是判斷了一下,音訊時間長度,小於1.5秒會回調錄音失敗的代碼塊。

這裡需要注意的是, recorder.currentTime 當前錄音的時間長度,只有在這個方法中才能取到,出了方法就取不到值了。

然後在控制器中,那個小加號按鈕的按下和抬起的監聽方法中調用工具類中的方法

#pragma mark - ******************** 錄音方法- (void)startRecord {    NSLog(@"開始錄音");    [[SXRecordTools sharedRecorder] startRecord];}- (void)stopRecord {    NSLog(@"停止錄音");    [[SXRecordTools sharedRecorder] stopRecordSuccess:^(NSURL *url, NSTimeInterval time) {        // 發送聲音資料        NSData *data = [NSData dataWithContentsOfURL:url];        [self sendMessageWithData:data bodyName:[NSString stringWithFormat:@"audio:%.1f秒", time]];            } andFailed:^{                [[[UIAlertView alloc] initWithTitle:@"提示" message:@"時間太短" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil] show];    }];}

可以清楚的看到,發送聲音調sendMessageWithData:時把聲音的時間長度當做參數bodyName 傳入。 然後就會將這個字串存到message的子節點內發出。

 

 

四。音頻檔案的顯示

也是和圖片一樣,對於本行取出的資訊先判斷是不是音頻資訊,如果是,遍曆節點,取出字串,並且截取了一下,截取掉“audio:”,讓tableView的cell中只顯示 時間長度,

else if ([message.body hasPrefix:@"audio"]){                XMPPMessage *msg = message.message;                for (XMPPElement *node in msg.children) {                    NSString *base64str = node.stringValue;                        NSData *data = [[NSData alloc]initWithBase64EncodedString:base64str options:0];                        NSString *newstr = [message.body substringFromIndex:6];            cell.messageLabel.text = newstr;                        cell.audioData = data;        }    }

 這個audioData是個專門用來存放音效檔的資訊。但是表格是可以重用的,為了讓一個剛剛重用的cell裡面的音頻檔案別形成衝突,疊加。建議在剛取出cell時就加上一行

cell.audioData = nil;

 

 

五。關於音效檔的播放

雖然,架構自己就有音效檔的播放方法,但是還需要做很多附加操作,建議先在工具類中寫一個方法,就是播放data檔案,並且設定完成後的回調代碼。即playData:completion: 。在播放的方法中先判斷聲音是否現正播放,如果現正播放則不做任何操作。然後在方法中設定player的代理,這樣可以通過代理方法來監聽音效檔何時播放完,觸發代理方法。因此這個傳入的completion代碼塊必須要先用成員變數記錄下,然後在音效檔播放完的代理方法中再執行此代碼塊

- (void)playData:(NSData *)data completion:(void(^)())completion{    // 判斷是否現正播放    if (self.player.isPlaying) {        [self.player stop];    }    // 記錄塊代碼    self.palyCompletion = completion;        // 監聽播放器播放狀態    self.player = [[AVAudioPlayer alloc]initWithData:data error:NULL];    self.player.delegate = self;    [self.player play];}

 

代理方法在音效檔播放完的代理方法中再執行儲存的代碼塊

#pragma mark - ******************** 完成播放時的代理方法- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{    if (self.palyCompletion) {        self.palyCompletion();    }}

 

工具類中的方法寫完了之後,可以去外面調用了。給自己這個自訂的SXChatCell添加一個點擊方法。預設情況下按鈕是預設顏色的,點擊時顏色變成紅色,然後播放完成時的回調代碼再把顏色恢複成預設顏色。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    // 如果有音頻資料,直接播放音頻    if (self.audioData != nil) {        // 播放音頻        self.messageLabel.textColor = [UIColor redColor];        // 如果單例的塊代碼中包含self,一定使用weakSelf        __weak SXChatCell *weakSelf = self;        [[SXRecordTools sharedRecorder] playData:self.audioData completion:^{            weakSelf.messageLabel.textColor = [UIColor blackColor];        }];    }}

紅色的那個cell是現正播放

 

如果你不是在董鉑然部落格園看到本文,請點擊查看原文

到此之後,就完成了完整的圖片及音頻檔案的發送。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.