iOS中 蓝牙2.0详解/ios蓝牙设备详解-阿里云开发者社区

开发者社区> ghost丶桃子> 正文

iOS中 蓝牙2.0详解/ios蓝牙设备详解

简介:
+关注继续查看

每日更新关注:http://weibo.com/hanjunqiang  新浪微博

整体布局如下:

    程序结构如右图:

每日更新关注:http://weibo.com/hanjunqiang  新浪微博

==========================================================================

指定根视图:

[objc] view plain copy
  1. RootViewController * rootVC = [[RootViewController alloc] init];  
  2. UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:rootVC];  
  3. self.window.rootViewController= nav;  
根视图:

[objc] view plain copy
  1. #import "RootViewController.h"  
  2. #import "BlueSessionManager.h"  
  3. #import "ChatCell.h"  
  4. #import "ChatItem.h"  
  5.   
  6. #import <AssetsLibrary/AssetsLibrary.h>  
  7. #import <AVFoundation/AVFoundation.h>  
  8.   
  9.   
  10. #define kRecordAudioFile @"myRecord.caf"  
  11.   
  12. // 判断大小  
  13. #define HEIGHT [UIScreen mainScreen].bounds.size.height  
  14. #define WIDTH [UIScreen mainScreen].bounds.size.width  
  15. #define ChatHeight 45.0  
  16.   
  17. @interface RootViewController ()<NSStreamDelegate,UITableViewDataSource,UITableViewDelegate,UITextViewDelegate,UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,AVAudioRecorderDelegate,AVAudioPlayerDelegate>  
  18. {  
  19.     float _sendBackViewHeight;  
  20.     float _sendTextViewHeight;  
  21.       
  22.     UIImagePickerController * _picker;  
  23.     UIView * _backRemindRecordView;  
  24. }  
  25.   
  26. // DataAndBlue  
  27. @property(strongnonatomicBlueSessionManager *sessionManager;  
  28.   
  29. @property(strongnonatomicNSMutableArray *datasource;  
  30. @property(strongnonatomicNSMutableArray * myDataArray;  
  31.   
  32. @property(strongnonatomicNSMutableData *streamData;  
  33. @property(strongnonatomicNSOutputStream *outputStream;  
  34. @property(strongnonatomicNSInputStream *inputStream;  
  35.   
  36. // UI  
  37. @property(strongnonatomicUITableView * tableView;  
  38. @property(strongnonatomicUIView * sendBackView;  
  39. @property(strongnonatomicUITextView * sendTextView;  
  40. @property(strongnonatomicUIButton * sendButton;  
  41.   
  42.   
  43. // 语音播放  
  44. @property (nonatomic,strongAVAudioRecorder *audioRecorder;//音频录音机  
  45. //音频播放器,用于播放录音文件  
  46. @property (nonatomic,strongAVAudioPlayer *audioPlayer;  
  47.   
  48. @property (nonatomic,strongNSTimer *timer;//录音声波监控(注意这里暂时不对播放进行监控)  
  49.   
  50.   
  51.   
  52. @property (strongnonatomicUIProgressView *audioPower;//音频波动  
  53.   
  54.   
  55.   
  56.   
  57. @end  
  58.   
  59. @implementation RootViewController  
  60.   
  61. - (void)viewDidLoad {  
  62.     [super viewDidLoad];  
  63.       
  64.     [self makeBlueData];  
  65.       
  66.     [self readyUI];  
  67.       
  68.     [self buildVideoForWe];  
  69.       
  70.       
  71.     // Do any additional setup after loading the view  
  72. }  
  73.   
  74.   
  75.   
  76.   
  77. #pragma mark  基本制作  
  78.   
  79. - (void)readyUI  
  80. {  
  81.     self.title = @"蓝牙设置";  
  82.     self.view.backgroundColor = [UIColor whiteColor];  
  83.     self.automaticallyAdjustsScrollViewInsets = NO;  
  84.       
  85.     NSArray * buttonTitleArray = @[@"寻找设备",@"打开天线"];  
  86.     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:buttonTitleArray[0] style:UIBarButtonItemStyleDone target:self action:@selector(lookOtherDevice)];  
  87.     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:buttonTitleArray[1] style:UIBarButtonItemStyleDone target:self action:@selector(showSelfAdvertiser)];  
  88.     [self makeUIView];  
  89.       
  90. }  
  91. - (void)lookOtherDevice  
  92. {  
  93.     [self.sessionManager browseWithControllerInViewController:self connected:^{  
  94.         NSLog(@"connected");  
  95.     }                                                 canceled:^{  
  96.         NSLog(@"cancelled");  
  97.     }];  
  98. }  
  99.   
  100.   
  101. - (void)showSelfAdvertiser  
  102. {  
  103.     [self.sessionManager advertiseForBrowserViewController];  
  104. }  
  105.   
  106. #pragma mark 制作页面UI  
  107. - (void)makeUIView  
  108. {  
  109. //    NSLog(@"width === %f,height===== %f",WIDTH,HEIGHT);  
  110.       
  111.     self.myDataArray = [NSMutableArray arrayWithCapacity:0];  
  112.       
  113.     self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(064, WIDTH, HEIGHT - 64 - ChatHeight - 10)];  
  114.     self.tableView.delegate = self;  
  115.     self.tableView.dataSource = self;  
  116.     self.tableView.separatorStyle = UITableViewCellSelectionStyleNone;  
  117.      
  118.     [self.view addSubview:self.tableView];  
  119.       
  120.      
  121.       
  122.       
  123.      
  124. //-------------------------------------------------------------------------//  
  125.       
  126.     self.sendBackView = [[UIView alloc] initWithFrame:CGRectMake(0, HEIGHT - ChatHeight, WIDTH, ChatHeight)];  
  127.     self.sendBackView.backgroundColor = [UIColor colorWithRed:240/255.0 green:240/255.0 blue:240/255.0 alpha:1.0];  
  128.     [self.view addSubview:self.sendBackView];  
  129.       
  130. //    float heightView = self.sendBackView.frame.size.height;  
  131.       
  132.     self.sendTextView = [[UITextView alloc] initWithFrame:CGRectMake(105, WIDTH - 10 - 9035)];  
  133. //    self.sendTextView.backgroundColor = [UIColor lightGrayColor];  
  134.     self.sendTextView.returnKeyType = UIReturnKeySend;  
  135.     self.sendTextView.font = [UIFont systemFontOfSize:17];  
  136.     self.sendTextView.editable = YES;  
  137.     self.sendTextView.delegate = self;  
  138.     [self.sendBackView addSubview:self.sendTextView];  
  139.       
  140.     UIButton * addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];  
  141.     addButton.frame = CGRectMake(WIDTH - 8523737);  
  142.     [addButton addTarget:self action:@selector(addNextImage) forControlEvents:UIControlEventTouchUpInside];  
  143.     [self.sendBackView addSubview:addButton];  
  144.       
  145.     self.sendButton = [UIButton buttonWithType:UIButtonTypeCustom];  
  146.     self.sendButton.frame = CGRectMake(WIDTH - 4554030);  
  147.       
  148.     [self.sendButton setImage:[UIImage imageNamed:@"record.png"] forState:UIControlStateNormal];  
  149.     [self.sendButton addTarget:self action:@selector(videoRecord) forControlEvents:UIControlEventTouchUpInside];  
  150.     [self.sendBackView addSubview:self.sendButton];  
  151.       
  152.     
  153.       
  154.       
  155.     // 增加通知  
  156.     [self addTheNoticeForKeyDownUp];  
  157.       
  158. }  
  159.   
  160.   
  161. #pragma mark 图片的传输---------///////  
  162.   
  163. - (void)addNextImage  
  164. {  
  165.      
  166.     UIActionSheet *chooseImageSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"照相机",@"相册", nil nil];  
  167.     [chooseImageSheet showInView:self.view];  
  168. }  
  169.   
  170.   
  171.   
  172.   
  173. #pragma mark UIActionSheetDelegate Method  
  174. -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex  
  175. {  
  176.     _picker = [[UIImagePickerController alloc] init];  
  177.     _picker.delegate = self;  
  178.       
  179.     switch (buttonIndex) {  
  180.         case 0://Take picture  
  181.               
  182.        
  183.             if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])  
  184.             {  
  185.                   
  186.                 _picker.sourceType = UIImagePickerControllerSourceTypeCamera;  
  187.             }  
  188.           
  189.             [self presentViewController:_picker animated:NO completion:nil];  
  190.               
  191.               
  192.         
  193.             break;  
  194.               
  195.         case 1:  
  196.             //From album  
  197.             _picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  
  198.               
  199.             [self presentViewController:_picker animated:NO completion:^{  
  200.                   
  201.                 // 改变状态栏的颜色  为正常  这是这个独有的地方需要处理的  
  202.                 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];  
  203.             }];  
  204.             break;  
  205.               
  206.         default:  
  207.               
  208.             break;  
  209.     }  
  210. }  
  211.   
  212.   
  213.   
  214.   
  215.   
  216.   
  217.   
  218. // 相册  
  219. -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info  
  220. {  
  221.       
  222.     NSString *type = [info objectForKey:UIImagePickerControllerMediaType];  
  223.     //当选择的类型是图片  
  224.     if ([type isEqualToString:@"public.image"])  
  225.     {  
  226.         //先把图片转成NSData  
  227.         UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage];  
  228.         NSData *data;  
  229.         if (UIImagePNGRepresentation(image) == nil)  
  230.         {  
  231.             data = UIImageJPEGRepresentation(image, 1.0);  
  232.         }  
  233.         else  
  234.         {  
  235.             data = UIImagePNGRepresentation(image);  
  236.         }  
  237.           
  238.         //图片保存的路径  
  239.         //这里将图片放在沙盒的documents文件夹中  
  240.         NSString * DocumentsPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];  
  241.           
  242.         //文件管理器  
  243.         NSFileManager *fileManager = [NSFileManager defaultManager];  
  244.           
  245.         //把刚刚图片转换的data对象拷贝至沙盒中 并保存为image.png  
  246.         [fileManager createDirectoryAtPath:DocumentsPath withIntermediateDirectories:YES attributes:nil error:nil];  
  247.         [fileManager createFileAtPath:[DocumentsPath stringByAppendingString:@"/image.png"] contents:data attributes:nil];  
  248.           
  249.         //得到选择后沙盒中图片的完整路径  
  250.         NSString * filePath = [[NSString alloc]initWithFormat:@"%@%@",DocumentsPath,  @"/image.png"];  
  251.           
  252.           
  253.           
  254.         [_picker dismissViewControllerAnimated:NO completion:^{  
  255.               
  256.             // 改变状态栏的颜色  改变为白色  
  257.             [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];  
  258.               
  259.               
  260.               
  261.             // 这边是真正的发送  
  262.             if(!self.sessionManager.isConnected)  
  263.             {  
  264.                 UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"蓝牙已经断开了,请重新连接!" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"知道了", nil nil];  
  265.                 [alertView show];  
  266.                 return;  
  267.             }  
  268.               
  269.             ChatItem * chatItem = [[ChatItem alloc] init];  
  270.             chatItem.isSelf = YES;  
  271.             chatItem.states = picStates;  
  272.             chatItem.picImage = image;  
  273.             [self.datasource addObject:chatItem];  
  274.               
  275.               
  276.             [self insertTheTableToButtom];  
  277.               
  278.               
  279.             [self sendAsResource:filePath];  
  280.              
  281.         }];  
  282.     }  
  283.   
  284.     
  285. }  
  286. - (void)sendAsResource:(NSString *)path  
  287. {  
  288.       
  289.     NSLog(@"dispaly ====%@",self.sessionManager.firstPeer.displayName);  
  290.     NSString * name = [NSString stringWithFormat:@"%@ForPic",[[UIDevice currentDevice] name]];  
  291.     NSURL * url = [NSURL fileURLWithPath:path];  
  292.       
  293.     NSProgress *progress = [self.sessionManager sendResourceWithName:name atURL:url toPeer:self.sessionManager.firstPeer complete:^(NSError *error) {  
  294.         if(!error) {  
  295.             NSLog(@"finished sending resource");  
  296.         }  
  297.         else {  
  298.             NSLog(@"%@", error);  
  299.         }  
  300.     }];  
  301.     NSLog(@"%@", @(progress.fractionCompleted));  
  302. }  
  303.   
  304.   
  305. #pragma mark 普通数据的传输  
  306. - (void)sendWeNeedNews  
  307. {  
  308.     if(!self.sessionManager.isConnected)  
  309.     {  
  310.         UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"蓝牙已经断开了,请重新连接!" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"知道了", nil nil];  
  311.         [alertView show];  
  312.         return;  
  313.     }  
  314.     if([self.sendTextView.text isEqualToString:@""])  
  315.     {  
  316.         return;  
  317.     }  
  318.       
  319.       
  320.     ChatItem * chatItem = [[ChatItem alloc] init];  
  321.     chatItem.isSelf = YES;  
  322.     chatItem.states = textStates;  
  323.     chatItem.content = self.sendTextView.text;  
  324.     [self.datasource addObject:chatItem];  
  325.     // 加到数组里面  
  326.       
  327.     // 添加行   indexPath描述位置的具体信息  
  328.     [self insertTheTableToButtom];  
  329.       
  330.     NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.sendTextView.text];  
  331.     NSError *error = [self.sessionManager sendDataToAllPeers:data];  
  332.     if(!error) {  
  333.         //there was no error.  
  334.     }  
  335.     else {  
  336.         NSLog(@"%@", error);  
  337.     }  
  338.       
  339.     [self returnTheNewBack];  
  340. }  
  341. - (void)returnTheNewBack  
  342. {  
  343.     // 归零  
  344.     self.sendTextView.text = @"";  
  345.     [self.sendTextView resignFirstResponder];  
  346.     self.tableView.frame = CGRectMake(064, WIDTH, HEIGHT - 64 - ChatHeight - 10 );  
  347.     self.sendBackView.frame = CGRectMake(0, HEIGHT - ChatHeight , WIDTH, ChatHeight);  
  348.       
  349. }  
  350.   
  351. // 这是一种很好的键盘下移方式  
  352. -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text  
  353. {  
  354.       
  355.     if ([text isEqualToString:@"\n"]) {  
  356.           
  357.         [self sendWeNeedNews];  
  358.   
  359.         return NO;  
  360.     }  
  361.       
  362.       
  363.       
  364.       
  365.     return YES;  
  366. }  
  367.   
  368. - (void)textViewDidChange:(UITextView *)textView  
  369. {  
  370.   
  371.     // 随机改变其高度  
  372.       
  373.     float textHeight = [self heightForString:textView.text fontSize:16 andWidth:textView.frame.size.width];  
  374.     _sendTextViewHeight = textHeight;  
  375. //    NSLog(@"teztheight ===== %f",textHeight);  
  376.       
  377.       
  378.     self.sendTextView.frame = CGRectMake(105, WIDTH - 10 - 90, _sendTextViewHeight);  
  379.     self.sendBackView.frame = CGRectMake(0, HEIGHT -  _sendBackViewHeight - _sendTextViewHeight - 10, WIDTH, _sendTextViewHeight + 10);  
  380.     
  381.       
  382. }  
  383.   
  384. - (float) heightForString:(NSString *)value fontSize:(float)fontSize andWidth:(float)width  
  385. {  
  386.     UITextView *detailTextView = [[UITextView alloc]initWithFrame:CGRectMake(00, width, 0)];  
  387.     detailTextView.font = [UIFont systemFontOfSize:fontSize];  
  388.     detailTextView.text = value;  
  389.     CGSize deSize = [detailTextView sizeThatFits:CGSizeMake(width,CGFLOAT_MAX)];  
  390.     return deSize.height;  
  391. }  
  392.   
  393.   
  394.   
  395. #pragma mark 以下是为了配合  键盘上移的变化  
  396.   
  397. - (void)addTheNoticeForKeyDownUp  
  398. {  
  399.     [ [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyBoardDidShow:) name:UIKeyboardDidShowNotification object:nil];  
  400.     [ [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];  
  401. }  
  402.   
  403. - (void)dealloc  
  404. {  
  405.     [[NSNotificationCenter defaultCenter] removeObserver:self];  
  406. }  
  407.   
  408. -(void)handleKeyBoardDidShow:(NSNotification *)paramNotification  
  409. {  
  410.     CGSize size = [[paramNotification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;  
  411.       
  412.     _sendBackViewHeight = size.height;  
  413.       
  414.     [UIView animateWithDuration:0.000001 animations:^{  
  415.         self.tableView.frame = CGRectMake(064, WIDTH, HEIGHT - 64 - ChatHeight - size.height);  
  416.         self.sendBackView.frame = CGRectMake(0, HEIGHT - ChatHeight - size.height, WIDTH, ChatHeight);  
  417.           
  418.     }];  
  419.       
  420. }  
  421. -(void)handleKeyboardWillHide:(NSNotification *)paramNotification  
  422. {  
  423.     [UIView animateWithDuration:0.1 animations:^{  
  424.         if(_sendTextViewHeight > 0)  
  425.         {  
  426.             self.tableView.frame = CGRectMake(064, WIDTH, HEIGHT - 64 - _sendTextViewHeight + 10 );  
  427.             self.sendBackView.frame = CGRectMake(0, HEIGHT - _sendTextViewHeight  - 10, WIDTH, _sendTextViewHeight + 10);  
  428.         }  
  429.         else  
  430.         {  
  431.             self.tableView.frame = CGRectMake(064, WIDTH, HEIGHT - 64 - ChatHeight - 10 );  
  432.             self.sendBackView.frame = CGRectMake(0, HEIGHT - ChatHeight , WIDTH, ChatHeight);  
  433.         }  
  434.           
  435.           
  436.     }];  
  437. }  
  438. /*--------------------------------------------------------------------------------------------*/  
  439. - (void)insertTheTableToButtom  
  440. {  
  441.     // 哪一组 哪一段  
  442.     NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.datasource.count1 inSection:0];  
  443.     // 添加新的一行  
  444.     [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];  
  445.     // 滑动到底部  第二个参数是滑动到底部  
  446.     [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];  
  447. }  
  448.   
  449. #pragma mark tableView 代理  
  450. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  
  451.     return 1;  
  452. }  
  453.   
  454. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  
  455.     return self.datasource.count;  
  456. }  
  457.   
  458. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath  
  459. {  
  460.     ChatItem * chatItem = [self.datasource objectAtIndex:indexPath.row];  
  461.     if(chatItem.states == picStates)  
  462.     {  
  463.         NSLog(@"widht====%f,height======%f",chatItem.picImage.size.width,chatItem.picImage.size.height);  
  464.         return 50;  
  465.           
  466.           
  467.           
  468.     }  
  469.     else if(chatItem.states == textStates)  
  470.     {  
  471.         CGSize size = [chatItem.content boundingRectWithSize:CGSizeMake(2501000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading  attributes:@{NSFontAttributeName :[UIFont systemFontOfSize:14]} context:nil].size;  
  472.           
  473.         return size.height + 20 + 10// 与view的距离 + 与Cell的距离  
  474.     }  
  475.     else  
  476.     {  
  477.         return 50;  
  478.     }  
  479.       
  480.       
  481. }  
  482.   
  483. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
  484. {  
  485.       
  486.     static NSString * iden = @"iden";  
  487.     ChatCell * cell = [tableView dequeueReusableCellWithIdentifier:iden];  
  488.     if(cell == nil)  
  489.     {  
  490.         cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:iden];  
  491.         cell.selectionStyle = UITableViewCellSelectionStyleNone;  
  492.         // 让后面选中的没有阴影效果  
  493.           
  494.     }  
  495.       
  496.     // 模型  
  497.       
  498.     ChatItem * chatItem = [self.datasource objectAtIndex:indexPath.row];  
  499.      
  500.     CGSize size = [chatItem.content boundingRectWithSize:CGSizeMake(2501000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading  attributes:@{NSFontAttributeName :[UIFont systemFontOfSize:14]} context:nil].size;  
  501.       
  502.     //如果自己发的  
  503.     if(chatItem.isSelf)  
  504.     {  
  505.         cell.leftHeadImage.hidden = YES;  
  506.         cell.rightHeadImage.hidden = NO;  
  507.           
  508.         if(chatItem.states == picStates)  
  509.         {  
  510.             cell.lefeView.hidden = YES;  
  511.             cell.rightView.hidden = YES;  
  512.               
  513.             cell.rightPicImage.image = chatItem.picImage;  
  514.             cell.leftPicImage.hidden = YES;  
  515.             cell.rightPicImage.hidden = NO;  
  516.               
  517.             cell.leftVideoButton.hidden = YES;  
  518.             cell.rightVideoButton.hidden = YES;  
  519.               
  520.             NSLog(@"self send");  
  521.              
  522.               
  523.         }  
  524.         else if(chatItem.states == textStates)  
  525.         {  
  526.             cell.rightPicImage.hidden = YES;  
  527.             cell.leftPicImage.hidden = YES;  
  528.               
  529.             cell.lefeView.hidden = YES;  
  530.             cell.rightView.hidden = NO;  
  531.               
  532.             cell.leftVideoButton.hidden = YES;  
  533.             cell.rightVideoButton.hidden = YES;  
  534.             // 复用机制  
  535.             cell.rightLabel.frame = CGRectMake(105, size.width, size.height);  
  536.             cell.rightView.frame = CGRectMake(WIDTH - 40 -size.width-255, size.width + 25, size.height + 18);  
  537.             cell.rightLabel.text = chatItem.content;  
  538.         }  
  539.         else  
  540.         {  
  541.             cell.rightView.hidden = YES;  
  542.             cell.lefeView.hidden = YES;  
  543.             cell.rightView.hidden = YES;  
  544.             cell.lefeView.hidden = YES;  
  545.               
  546.             cell.leftVideoButton.hidden = YES;  
  547.             cell.rightVideoButton.hidden = NO;  
  548.               
  549.             cell.rightVideoButton.tag = 300 + indexPath.row;  
  550.             [cell.rightVideoButton addTarget:self action:@selector(cellSelectIndex:) forControlEvents:UIControlEventTouchUpInside];  
  551.             [cell.rightVideoButton setImage:[UIImage imageNamed:@"record.png"] forState:UIControlStateNormal];  
  552.               
  553.         }  
  554.           
  555.           
  556.           
  557.           
  558.           
  559.           
  560.           
  561.     }  
  562.     else  // 接受得到  
  563.     {  
  564.         cell.leftHeadImage.hidden = NO;  
  565.         cell.rightHeadImage.hidden = YES;  
  566.          
  567.           
  568.           
  569.         if(chatItem.states == picStates)  
  570.         {  
  571.             cell.rightView.hidden = YES;  
  572.             cell.lefeView.hidden = YES;  
  573.               
  574.             cell.leftVideoButton.hidden = YES;  
  575.             cell.rightVideoButton.hidden = YES;  
  576.               
  577.             cell.leftPicImage.image = chatItem.picImage;  
  578.             cell.rightPicImage.hidden = YES;  
  579.             cell.leftPicImage.hidden = NO;  
  580.               
  581.              
  582.               
  583.               
  584.         }  
  585.         else if(chatItem.states == textStates)  
  586.         {  
  587.             cell.rightPicImage.hidden = YES;  
  588.             cell.leftPicImage.hidden = YES;  
  589.               
  590.             cell.rightView.hidden = YES;  
  591.             cell.lefeView.hidden = NO;  
  592.               
  593.             cell.leftVideoButton.hidden = YES;  
  594.             cell.rightVideoButton.hidden = YES;  
  595.               
  596.             cell.leftLabel.frame = CGRectMake(155, size.width, size.height);  
  597.               
  598.             cell.lefeView.frame = CGRectMake(405, size.width +30, size.height + 25);  
  599.               
  600.             cell.leftLabel.text = chatItem.content;  
  601.         }  
  602.         else  
  603.         {  
  604.             cell.rightView.hidden = YES;  
  605.             cell.lefeView.hidden = YES;  
  606.             cell.rightView.hidden = YES;  
  607.             cell.lefeView.hidden = YES;  
  608.               
  609.             cell.leftVideoButton.hidden = NO;  
  610.             cell.rightVideoButton.hidden = YES;  
  611.               
  612.               
  613.             cell.leftVideoButton.tag = 300 + indexPath.row;  
  614.             [cell.leftVideoButton setImage:[UIImage imageNamed:@"record.png"] forState:UIControlStateNormal];  
  615.             [cell.leftVideoButton addTarget:self action:@selector(cellSelectIndex:) forControlEvents:UIControlEventTouchUpInside];  
  616.         }  
  617.           
  618.           
  619.           
  620.     }  
  621.   
  622.       
  623.     return cell;  
  624. }  
  625.   
  626. - (void)cellSelectIndex:(UIButton *)cellBtn  
  627. {  
  628.       
  629.     ChatItem *chatIden = [self.datasource objectAtIndex:cellBtn.tag - 300];  
  630.     if(chatIden.states == videoStates)  
  631.     {  
  632.         NSLog(@"realy play");  
  633. //        [self makeVideoPlayer:[self getVideoStremData]];  
  634.         [self makeVideoPlayer:chatIden.recordData];  
  635.     }  
  636. }  
  637.   
  638.   
  639. #pragma mark 下面是核心的连接MCSession 和  数据返回的地方  
  640.   
  641. /***************************-------**********************************************/  
  642. - (void)makeBlueData  
  643. {  
  644.       // 这是为了让 在block中弱引用  
  645.     __weak typeof (self) weakSelf = self;  
  646.     self.datasource = [NSMutableArray arrayWithCapacity:0];  
  647.       
  648.     // 初始化  会议室  
  649.     self.sessionManager = [[BlueSessionManager alloc]initWithDisplayName:[NSString stringWithFormat:@" %@",  [[UIDevice currentDevice] name]]];  
  650.       
  651.     //  
  652.     [self.sessionManager didReceiveInvitationFromPeer:^void(MCPeerID *peer, NSData *context) {  
  653.         __strong typeof (weakSelf) strongSelf = weakSelf;  
  654.         UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"是否连接?" message:[NSString stringWithFormat:@"同 %@%@", peer.displayName@" 连接?"] delegate:strongSelf cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil nil];  
  655.         [alertView show];  
  656.     }];  
  657.       
  658.     [self.sessionManager peerConnectionStatusOnMainQueue:YES block:^(MCPeerID *peer, MCSessionState state) {  
  659.         if(state == MCSessionStateConnected) {  
  660.             UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"已经连接" message:[NSString stringWithFormat:@"现在连接 %@了!", peer.displayName] delegate:nil cancelButtonTitle:nil otherButtonTitles:@"知道了", nil nil];  
  661.             [alertView show];  
  662.         }  
  663.     }];  
  664.       
  665.     // 发正常数据的返回  
  666.     [self.sessionManager receiveDataOnMainQueue:YES block:^(NSData *data, MCPeerID *peer) {  
  667.          
  668.         __strong typeof (weakSelf) strongSelf = weakSelf;  
  669.           
  670.         NSString *string = [NSKeyedUnarchiver unarchiveObjectWithData:data];  
  671.           
  672.           
  673.         ChatItem * chatItem = [[ChatItem alloc] init];  
  674.         chatItem.isSelf = NO;  
  675.         chatItem.states = textStates;  
  676.         chatItem.content = string;  
  677.         [strongSelf.datasource addObject:chatItem];  
  678.         // 加到数组里面  
  679.           
  680.         [strongSelf insertTheTableToButtom];  
  681.           
  682.           
  683.     }];  
  684.       
  685.     // 发图片之后的返回  
  686.     [self.sessionManager receiveFinalResourceOnMainQueue:YES complete:^(NSString *name, MCPeerID *peer, NSURL *url, NSError *error) {  
  687.           
  688.         __strong typeof (weakSelf) strongSelf = weakSelf;  
  689.         NSData *data = [NSData dataWithContentsOfURL:url];  
  690.           
  691.         ChatItem * chatItem = [[ChatItem alloc] init];  
  692.         chatItem.isSelf = NO;  
  693.         chatItem.states = picStates;  
  694.         chatItem.content = name;  
  695.         chatItem.picImage = [UIImage imageWithData:data];  
  696.         [strongSelf.datasource addObject:chatItem];  
  697.         [strongSelf insertTheTableToButtom];  
  698.           
  699.     }];  
  700.       
  701.       
  702.       
  703.     // 流  
  704.     [self.sessionManager didReceiveStreamFromPeer:^(NSInputStream *stream, MCPeerID *peer, NSString *streamName) {  
  705.         __strong typeof (weakSelf) strongSelf = weakSelf;  
  706.         strongSelf.inputStream = stream;  
  707.         strongSelf.inputStream.delegate = self;  
  708.         [strongSelf.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];  
  709.         [strongSelf.inputStream open];  
  710.           
  711.         NSLog(@"we need");  
  712.           
  713.     }];  
  714.       
  715. }  
  716. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex  
  717. {  
  718.     [self.sessionManager connectToPeer:buttonIndex == 1];  
  719. }  
  720.   
  721.   
  722.   
  723.   
  724.   
  725. #pragma mark 下面是流的传输  
  726.   
  727. /***********--------------------- 下面是流的传输 ------------------------***********************************/  
  728.   
  729. - (void)videoRecord  
  730. {  
  731.     // 播放录音  
  732.     [self SetTempRecordView];  
  733. }  
  734.   
  735.   
  736. - (void)sendAsStream  
  737. {  
  738.     if(!self.sessionManager.isConnected)  
  739.     {  
  740.         UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"蓝牙已经断开了,请重新连接!" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"知道了", nil nil];  
  741.         [alertView show];  
  742.         return;  
  743.     }  
  744.      
  745.     NSError *err;  
  746.     self.outputStream = [self.sessionManager streamWithName:@"super stream" toPeer:self.sessionManager.firstPeer error:&err];  
  747.     self.outputStream.delegate = self;  
  748.     [self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];  
  749.     if(err || !self.outputStream) {  
  750.         NSLog(@"%@", err);  
  751.     }  
  752.     else  
  753.     {  
  754.           
  755.         [self.outputStream open];  
  756.     }  
  757. }  
  758.   
  759. // 下面是一个代理  
  760. - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode  
  761. {  
  762.      
  763.     if(eventCode == NSStreamEventHasBytesAvailable)  
  764.     {  
  765.          // 有可读的字节,接收到了数据  
  766.         NSInputStream *input = (NSInputStream *)aStream;  
  767.         uint8_t buffer[1024];  
  768.         NSInteger length = [input read:buffer maxLength:1024];  
  769.         [self.streamData appendBytes:(const voidvoid *)buffer length:(NSUInteger)length];  
  770.        // 记住这边的数据陆陆续续的  
  771.     }  
  772.     else if(eventCode == NSStreamEventHasSpaceAvailable)  
  773.     {  
  774.         // 可以使用输出流的空间,此时可以发送数据给服务器  
  775.         // 发送数据的  
  776.         NSData *data = [self getVideoStremData];  
  777.         ChatItem * chatItem = [[ChatItem alloc] init];  
  778.         chatItem.isSelf = YES;  
  779.         chatItem.states = videoStates;  
  780.         chatItem.recordData = data;  
  781.           
  782.         [self.datasource addObject:chatItem];  
  783.         [self insertTheTableToButtom];  
  784.           
  785.         NSOutputStream *output = (NSOutputStream *)aStream;  
  786.         [output write:data.bytes maxLength:data.length];  
  787.         [output close];  
  788.     }  
  789.     if(eventCode == NSStreamEventEndEncountered)  
  790.     {  
  791.         // 流结束事件,在此事件中负责做销毁工作  
  792.         // 同时也是获得最终数据的好地方  
  793.           
  794.         ChatItem * chatItem = [[ChatItem alloc] init];  
  795.         chatItem.isSelf = NO;  
  796.         chatItem.states = videoStates;  
  797.         chatItem.recordData = self.streamData;  
  798.           
  799.         [self.datasource addObject:chatItem];  
  800.         [self insertTheTableToButtom];  
  801.           
  802.         [aStream close];  
  803.         [aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];  
  804.         if([aStream isKindOfClass:[NSInputStream class]])  
  805.         {  
  806.             self.streamData = nil;  
  807.         }  
  808.           
  809.     }  
  810.     if(eventCode == NSStreamEventErrorOccurred)  
  811.     {  
  812.         // 发生错误  
  813.         NSLog(@"error");  
  814.     }  
  815. }  
  816.   
  817. - (NSMutableData *)streamData  
  818. {  
  819.     if(!_streamData) {  
  820.         _streamData = [NSMutableData data];  
  821.     }  
  822.     return _streamData;  
  823. }  
  824.   
  825. /***********-----------------------  公用的数据 --------------------***********************************/  
  826.   
  827. - (NSData *)imageData  
  828. {  
  829.     return [NSData dataWithContentsOfURL:[self imageURL]];  
  830. }  
  831.   
  832. - (NSURL *)imageURL {  
  833.     NSString *path = [[NSBundle mainBundle]pathForResource:@"301-alien-ship@2x" ofType:@"png"];  
  834.     // 这儿有个技术点  
  835.     // 那个如何将 image转化成 路径  
  836.      
  837.     NSURL *url = [NSURL fileURLWithPath:path];  
  838.     return url;  
  839. }  
  840.   
  841. /***********----------------------------------------------***********************************/  
  842. #pragma mark 尝试空白处的连接  
  843.   
  844. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  845. {  
  846.     UITouch * touch = [[event allTouches] anyObject];  
  847.     if(touch.tapCount >= 1)  
  848.     {  
  849.         [self.sendTextView resignFirstResponder];  
  850.     }  
  851. }  
  852.   
  853.   
  854. /***********-------------------语音---------------------------***********************************/  
  855.   
  856. #pragma mark 尝试语音的录制和播出  
  857.   
  858. - (void)buildVideoForWe  
  859. {  
  860.     // 设置录音会话  
  861.     [self setAudioSession];  
  862. }  
  863.   
  864. - (void)SetTempRecordView  
  865. {  
  866.     _backRemindRecordView = [[UIView alloc] initWithFrame:CGRectMake(00, WIDTH, 150)];  
  867.     _backRemindRecordView.center = self.view.center;  
  868.     _backRemindRecordView.backgroundColor = [UIColor lightGrayColor];  
  869.     [self.view addSubview:_backRemindRecordView];  
  870.       
  871.       
  872.     UILabel * beginLabel = [[UILabel alloc] initWithFrame:CGRectMake(6050, WIDTH -12050)];  
  873.     beginLabel.backgroundColor = [UIColor greenColor];  
  874.     beginLabel.text = @"长按录音开始···";  
  875.     beginLabel.tag = 1001;  
  876.     beginLabel.textAlignment = NSTextAlignmentCenter;  
  877.     beginLabel.userInteractionEnabled = YES;  
  878.     [_backRemindRecordView addSubview:beginLabel];  
  879.       
  880.     UILongPressGestureRecognizer * longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressNextDo:)];  
  881.     [beginLabel addGestureRecognizer:longPress];  
  882.       
  883.   
  884.       
  885.       
  886.       
  887.       
  888. }  
  889.   
  890.   
  891.   
  892. - (void)longPressNextDo:(UILongPressGestureRecognizer * )longPress  
  893. {  
  894.     if(longPress.state == UIGestureRecognizerStateBegan)  
  895.     {  
  896.         NSLog(@"begin");  
  897.         UILabel * label = (UILabel *)[_backRemindRecordView viewWithTag:1001];  
  898.         label.text = @"录音正在进行中···";  
  899.         label.backgroundColor = [UIColor orangeColor];  
  900.         [self BeginRecordClick];  
  901.     }  
  902.     if(longPress.state == UIGestureRecognizerStateEnded)  
  903.     {  
  904.         [self OkStopClick];  
  905.         [_backRemindRecordView removeFromSuperview];  
  906.         [self  sendAsStream];  
  907.         NSLog(@"stop");  
  908.          
  909.     }  
  910. }  
  911.   
  912.   
  913. #pragma mark - 私有方法  
  914. /** 
  915.  *  设置音频会话 
  916.  */  
  917. -(void)setAudioSession  
  918. {  
  919.     AVAudioSession *audioSession=[AVAudioSession sharedInstance];  
  920.     //设置为播放和录音状态,以便可以在录制完之后播放录音  
  921.     [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];  
  922.     [audioSession setActive:YES error:nil];  
  923. }  
  924.   
  925. /** 
  926.  *  取得录音文件保存路径 
  927.  * 
  928.  *  @return 录音文件路径 
  929.  */  
  930. -(NSURL *)getSavePath  
  931. {  
  932.     NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];  
  933.     urlStr=[urlStr stringByAppendingPathComponent:kRecordAudioFile];  
  934.     NSLog(@"file path:%@",urlStr);  
  935.     NSURL *url=[NSURL fileURLWithPath:urlStr];  
  936.     return url;  
  937. }  
  938.   
  939. - (NSData *)getVideoStremData  
  940. {  
  941.     return [NSData dataWithContentsOfURL:[self getSavePath]];  
  942. }  
  943.   
  944.   
  945. /** 
  946.  *  取得录音文件设置 
  947.  * 
  948.  *  @return 录音设置 
  949.  */  
  950. -(NSDictionary *)getAudioSetting{  
  951.     NSMutableDictionary *dicM=[NSMutableDictionary dictionary];  
  952.     //设置录音格式  
  953.     [dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];  
  954.     //设置录音采样率,8000是电话采样率,对于一般录音已经够了  
  955.     [dicM setObject:@(8000) forKey:AVSampleRateKey];  
  956.     //设置通道,这里采用单声道  
  957.     [dicM setObject:@(1) forKey:AVNumberOfChannelsKey];  
  958.     //每个采样点位数,分为8、16、24、32  
  959.     [dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];  
  960.     //是否使用浮点数采样  
  961.     [dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];  
  962.     //....其他设置等  
  963.     return dicM;  
  964. }  
  965.   
  966. /** 
  967.  *  获得录音机对象 
  968.  * 
  969.  *  @return 录音机对象 
  970.  */  
  971. -(AVAudioRecorder *)audioRecorder  
  972. {  
  973.     if (!_audioRecorder) {  
  974.         //创建录音文件保存路径  
  975.         NSURL *url=[self getSavePath];  
  976.         //创建录音格式设置  
  977.         NSDictionary *setting=[self getAudioSetting];  
  978.         //创建录音机  
  979.         NSError *error=nil;  
  980.         _audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];  
  981.         _audioRecorder.delegate=self;  
  982.         _audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES  
  983.         if (error) {  
  984.             NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);  
  985.             return nil;  
  986.         }  
  987.     }  
  988.     return _audioRecorder;  
  989. }  
  990.   
  991. /** 
  992.  *  创建播放器 
  993.  * 
  994.  *  @return 播放器 
  995.  */  
  996.   
  997.   
  998. - (void)makeVideoPlayer:(NSData *)data  
  999. {  
  1000.     NSError *error=nil;  
  1001.     self.audioPlayer=[[AVAudioPlayer alloc]initWithData:data error:&error];  
  1002.     self.audioPlayer.delegate = self;  
  1003.     self.audioPlayer.numberOfLoops=0;  
  1004.     [self.audioPlayer prepareToPlay];  
  1005.     if (error)  
  1006.     {  
  1007.         NSLog(@"创建播放器过程中发生错误,错误信息:%@",error.localizedDescription);  
  1008.          
  1009.     }  
  1010.     else  
  1011.     {  
  1012.         if (![self.audioPlayer isPlaying]) {  
  1013.             NSLog(@"play");  
  1014.                 [self.audioPlayer play];  
  1015.         }  
  1016.           
  1017.     }  
  1018. }  
  1019.   
  1020.   
  1021.   
  1022.   
  1023.   
  1024. /** 
  1025.  *  录音声波监控定制器 
  1026.  * 
  1027.  *  @return 定时器 
  1028.  */  
  1029. -(NSTimer *)timer{  
  1030.     if (!_timer) {  
  1031.         _timer=[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(audioPowerChange) userInfo:nil repeats:YES];  
  1032.     }  
  1033.     return _timer;  
  1034. }  
  1035.   
  1036. /** 
  1037.  *  录音声波状态设置 
  1038.  */  
  1039. -(void)audioPowerChange{  
  1040.     [self.audioRecorder updateMeters];//更新测量值  
  1041.     float power= [self.audioRecorder averagePowerForChannel:0];//取得第一个通道的音频,注意音频强度范围时-160到0  
  1042.     CGFloat progress=(1.0/160.0)*(power+160.0);  
  1043.     [self.audioPower setProgress:progress];  
  1044. }  
  1045. #pragma mark - UI事件  
  1046. /** 
  1047.  *  点击录音按钮 
  1048.  * 
  1049.  *  @param sender 录音按钮 
  1050.  */  
  1051. - (void)BeginRecordClick  
  1052. {  
  1053.     if (![self.audioRecorder isRecording])  
  1054.     {  
  1055.         [self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风  
  1056.         self.timer.fireDate=[NSDate distantPast];  
  1057.     }  
  1058. }  
  1059.   
  1060. /** 
  1061.  *  点击暂定按钮 
  1062.  * 
  1063.  *  @param sender 暂停按钮 
  1064.  */  
  1065. - (void)StopPauseClick  
  1066. {  
  1067.     if ([self.audioRecorder isRecording]) {  
  1068.         [self.audioRecorder pause];  
  1069.         self.timer.fireDate=[NSDate distantFuture];  
  1070.     }  
  1071. }  
  1072.   
  1073.   
  1074. /** 
  1075.  *  点击停止按钮 
  1076.  * 
  1077.  *  @param sender 停止按钮 
  1078.  */  
  1079. - (void)OkStopClick  
  1080. {  
  1081.     [self.audioRecorder stop];  
  1082.     self.timer.fireDate=[NSDate distantFuture];  
  1083.     self.audioPower.progress=0.0;  
  1084. }  
  1085.   
  1086. #pragma mark - 录音机代理方法  
  1087. /** 
  1088.  *  录音完成,录音完成后播放录音 
  1089.  * 
  1090.  *  @param recorder 录音机对象 
  1091.  *  @param flag     是否成功 
  1092.  */  
  1093. -(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag  
  1094. {  
  1095. //    if (![self.audioPlayer isPlaying]) {  
  1096. //        [self.audioPlayer play];  
  1097. //    }  
  1098.     NSLog(@"录音完成!");  
  1099. }  
  1100.   
  1101. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag  
  1102. {  
  1103.       
  1104.     // 每次完成后都将这个对象释放  
  1105.     player =nil;  
  1106. }  

建一个model类:
[objc] view plain copy
  1. .h  
  2. #import <UIKit/UIKit.h>  
  3. //@protocol CellSelectIndex <NSObject>  
  4. //  
  5. //- (void)cellSelectIndex;  
  6. //  
  7. //@end  
  8.   
  9.   
  10. @interface ChatCell : UITableViewCell  
  11. @property(nonatomic,strong)UIImageView * lefeView;  
  12. @property(nonatomic,strong)UIImageView * rightView;  
  13. @property(nonatomic,strong)UILabel * leftLabel;  
  14. @property(nonatomic,strong)UILabel * rightLabel;  
  15.   
  16. @property(nonatomic,strong)UIImageView * leftHeadImage;  
  17. @property(nonatomic,strong)UIImageView * rightHeadImage;  
  18.   
  19. @property(nonatomic,strong)UIImageView * leftPicImage;  
  20. @property(nonatomic,strong)UIImageView * rightPicImage;  
  21.   
  22.   
  23. @property(nonatomic ,strong)UIButton * leftVideoButton;  
  24. @property(nonatomicstrong)UIButton * rightVideoButton;  
  25.   
  26. //@property(nonatomic,weak)id <CellSelectIndex> delegate;  
  27.   
  28. // 不能用名字相同的属性  
  29. //  记住自动的时候,讲一下 weak  and strong   
  30.   
  31. @end  
  32.   
  33.   
  34. .m  
  35. #import "ChatCell.h"  
  36.   
  37. @implementation ChatCell  
  38.   
  39. - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier  
  40. {  
  41.     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];  
  42.     if (self) {  
  43.         // Initialization code  
  44.         [self makeView];  
  45.     }  
  46.     return self;  
  47. }  
  48. -(void)makeView  
  49. {  
  50.     UIImage * leftImgae = [UIImage imageNamed:@"ReceiverTextNodeBkg.png"];  
  51.     UIImage * rightImage = [UIImage imageNamed:@"SenderTextNodeBkg.png"];  
  52.       
  53.     //这里设定一行一像素 当图片拉伸的时候,只放大两个像素  
  54.       
  55.     leftImgae = [leftImgae stretchableImageWithLeftCapWidth:30 topCapHeight:35];  
  56.     // 找一行一列的像素  
  57.     rightImage = [rightImage stretchableImageWithLeftCapWidth:30 topCapHeight:35];  
  58.     // 设定完了后生成了一个新的image;  
  59.       
  60. //----------------------------------------------------------------------------------------//  
  61.     // 左边头像  
  62.     self.leftHeadImage = [[UIImageView alloc] initWithFrame:CGRectMake(553030)];  
  63.     self.leftHeadImage.layer.masksToBounds = YES;  
  64.     self.leftHeadImage.layer.cornerRadius = 12;  
  65.     self.leftHeadImage.image = [UIImage imageNamed:@"f-pCert.png"];  
  66.     [self.contentView addSubview:self.leftHeadImage];  
  67.       
  68.     //左边气泡  
  69.     self.leftVideoButton = [UIButton buttonWithType:UIButtonTypeCustom];  
  70.     self.leftVideoButton.frame = CGRectMake(4053535);  
  71. //    [self.leftVideoButton addTarget:self action:@selector(recordTheVoice) forControlEvents:UIControlEventTouchUpInside];  
  72.     [self.contentView addSubview:self.leftVideoButton];  
  73.       
  74.     self.leftPicImage = [[UIImageView alloc] initWithFrame:CGRectMake(4056630)];  
  75.     [self.contentView addSubview:self.leftPicImage];  
  76.       
  77.     self.lefeView = [[UIImageView alloc] initWithFrame:CGRectMake(4056630)];  
  78.     self.lefeView.image = leftImgae;  
  79.     // 这里不是一个小像素的图片??  
  80.     [self.contentView addSubview:self.lefeView];  
  81.       
  82.       
  83.     self.leftLabel = [[UILabel alloc] initWithFrame:CGRectMake(15511)];  
  84.     self.leftLabel.font = [UIFont systemFontOfSize:14];  
  85.       
  86.     self.leftLabel.numberOfLines = 0// 换行  
  87.       
  88.     self.leftLabel.backgroundColor = [UIColor clearColor];// 设置透明的  
  89.       
  90.     [self.lefeView addSubview:self.leftLabel];  
  91.       
  92. //----------------------------------------------------------------------------------------//  
  93.       
  94.     self.rightHeadImage = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width - 3553030)];  
  95.     self.rightHeadImage.layer.masksToBounds = YES;  
  96.     self.rightHeadImage.layer.cornerRadius = 12;  
  97.     self.rightHeadImage.image = [UIImage imageNamed:@"f-plove.png"];  
  98.     [self.contentView addSubview:self.rightHeadImage];  
  99.       
  100.     self.rightVideoButton = [UIButton buttonWithType:UIButtonTypeCustom];  
  101.     self.rightVideoButton.frame = CGRectMake(self.frame.size.width - 45 - 4053535);  
  102. //    [self.rightVideoButton addTarget:self action:@selector(recordTheVoice) forControlEvents:UIControlEventTouchUpInside];  
  103.     [self.contentView addSubview:self.rightVideoButton];  
  104.       
  105.     self.rightPicImage = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width - 45 - 3053030)];  
  106.     [self.contentView addSubview:self.rightPicImage];  
  107.       
  108.     // 右边  
  109.     self.rightView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width - (66+40), 56630)];  
  110.     self.rightView.image = rightImage;  
  111.     [self.contentView addSubview:self.rightView];  
  112.   
  113.       
  114.     self.rightLabel = [[UILabel alloc] initWithFrame:CGRectMake(10511)];  
  115.     self.rightLabel.font = [UIFont systemFontOfSize:14];  
  116.     self.rightLabel.backgroundColor = [UIColor clearColor];  
  117.     self.rightLabel.numberOfLines = 0;  
  118.     [self.rightView addSubview:self.rightLabel];  
  119.    
  120. }  
  121.   
  122. //- (void)recordTheVoice  
  123. //{  
  124. //    [self.delegate cellSelectIndex];  
  125. //}  
每日更新关注:http://weibo.com/hanjunqiang  新浪微博

 基本知识必须了解的

 MCAdvertiserAssistant   //可以接收,并处理用户请求连接的响应。没有回调,会弹出默认的提示框,并处理连接。

 MCNearbyServiceAdvertiser //可以接收,并处理用户请求连接的响应。但是,这个类会有回调,告知有用户要与您的设备连接,然后可以自定义提示框,以及自定义连接处理。

 MCNearbyServiceBrowser  //用于搜索附近的用户,并可以对搜索到的用户发出邀请加入某个会话中。

 MCPeerID //这表明是一个用户

 MCSession //启用和管理Multipeer连接会话中的所有人之间的沟通。 通过Sesion,给别人发送数据。


建一个类用来写所有方法:

[objc] view plain copy
  1. .h  
  2. #import <Foundation/Foundation.h>  
  3.   
  4. @import MultipeerConnectivity;  
  5.   
  6. @interface BlueSessionManager : NSObject  
  7.   
  8. @property(strongnonatomicreadonlyNSArray *connectedPeers;  
  9.   
  10. @property(strongnonatomicreadonlyMCSession *session;  
  11.   
  12. @property(nonatomicreadonlygetter = isConnected) BOOL connected;  
  13.   
  14. @property(strongnonatomicNSDictionary *discoveryInfo; // 发现设备的特征  
  15.   
  16. @property(strongnonatomicreadonlyMCPeerID *firstPeer; // 第一个连接的 用户  
  17.   
  18. /** 
  19.  * The service type provided for browsing and advertising. 
  20.  * This should be a short text string that describes the 
  21.  * app's networking protocol. Should be something 
  22.  * in the form of `tjl_appname`. 
  23.  */  
  24. @property(strongnonatomicNSString *serviceType;  
  25.   
  26.   
  27. /* 
  28.  初始化一个 假设的用户名字 
  29.  */  
  30. - (instancetype)__attribute__((nonnull(1)))initWithDisplayName:(NSString *)displayName;  
  31.   
  32.   
  33. - (void)browseForProgrammaticDiscovery;  
  34.   
  35.   
  36. - (void)advertiseForBrowserViewController;  
  37.   
  38.   
  39. - (void)advertiseForProgrammaticDiscovery;  
  40.   
  41. - (void)didReceiveInvitationFromPeer:(void (^)(MCPeerID *peer, NSData *context))invite;  
  42.   
  43.   
  44. - (NSError *)sendDataToAllPeers:(NSData *)data;  
  45. - (NSError *)sendData:(NSData *)data toPeers:(NSArray *)peers;  
  46.   
  47.   
  48. - (NSError *)sendData:(NSData *)data toPeers:(NSArray *)peers withMode:(MCSessionSendDataMode)mode;  
  49.   
  50.   
  51. - (void)receiveDataOnMainQueue:(BOOL)mainQueue block:(void (^)(NSData *data, MCPeerID *peer))dataBlock;  
  52.   
  53.   
  54. - (NSProgress *)sendResourceWithName:(NSString *)name atURL:(NSURL *)url toPeer:(MCPeerID *)peer complete:(void (^)(NSError *error))compelete;  
  55.   
  56.   
  57. - (void)receiveFinalResourceOnMainQueue:(BOOL)mainQueue complete:(void (^)(NSString *name, MCPeerID *peer, NSURL *url, NSError *error))block;  
  58.   
  59.   
  60. - (void)startReceivingResourceOnMainQueue:(BOOL)mainQueue block:(void (^)(NSString *name, MCPeerID *peer, NSProgress *progress))block;  
  61.   
  62.   
  63. - (NSOutputStream *)streamWithName:(NSString *)name toPeer:(MCPeerID *)peerID error:(NSError * __autoreleasing *)error;  
  64.   
  65.   
  66. - (void)didReceiveStreamFromPeer:(void (^)(NSInputStream *inputStream, MCPeerID *peer, NSString *streamName))streamBlock;  
  67.   
  68. - (void)peerConnectionStatusOnMainQueue:(BOOL)mainQueue block:(void (^)(MCPeerID *peer, MCSessionState state))status;  
  69.   
  70.   
  71. - (void)browseWithControllerInViewController:(UIViewController *)controller connected:(void (^)(void))connected canceled:(void (^)(void))cancelled;  
  72.   
  73.   
  74. - (void)didFindPeerWithInfo:(void (^)(MCPeerID *peer, NSDictionary *info))found;  
  75. - (void)connectToPeer:(BOOL)connect;  
  76.   
  77. // 邀请其他设备连接  
  78. - (void)invitePeerToConnect:(MCPeerID *)peer connected:(void (^)(void))connected;  
  79. - (void)disconnectSession;  
  80. // 停止打开自己  
  81. - (void)stopAdvertising;  
  82.   
  83. // 停止扫描  
  84. - (void)stopBrowsing;  
  85.   
  86. @end  
  87.   
  88.   
  89.   
  90.   
  91. .m  
  92. #import "BlueSessionManager.h"  
  93.   
  94. #define ServiceType @"MyService"  
  95.   
  96. /* 
  97.  MCAdvertiserAssistant   //可以接收,并处理用户请求连接的响应。没有回调,会弹出默认的提示框,并处理连接。 
  98.  MCNearbyServiceAdvertiser //可以接收,并处理用户请求连接的响应。但是,这个类会有回调,告知有用户要与您的设备连接,然后可以自定义提示框,以及自定义连接处理。 
  99.  MCNearbyServiceBrowser  //用于搜索附近的用户,并可以对搜索到的用户发出邀请加入某个会话中。 
  100.  MCPeerID //这表明是一个用户 
  101.  MCSession //启用和管理Multipeer连接会话中的所有人之间的沟通。 通过Sesion,给别人发送数据。 
  102.  */  
  103. @interface BlueSessionManager ()<MCAdvertiserAssistantDelegate, MCNearbyServiceBrowserDelegate, MCSessionDelegate, MCBrowserViewControllerDelegate, MCNearbyServiceAdvertiserDelegate, UIAlertViewDelegate>  
  104. @property(strongnonatomicMCSession *currentSession; // 当前会议  
  105. @property(strongnonatomicMCAdvertiserAssistant *advertisingAssistant; // 宣传助手  
  106. @property(strongnonatomicMCNearbyServiceAdvertiser *advertiser; // 服务助手  
  107. @property(strongnonatomicMCNearbyServiceBrowser *browser; // 搜索蓝牙者  
  108. @property(strongnonatomicMCPeerID *peerID; // 用户  
  109.   
  110. //  以下都是用到的block  
  111. @property(nonatomiccopyvoid(^receiveDataBlock)(NSData *data, MCPeerID *peer);  
  112. @property(nonatomiccopyvoid(^receiveResourceBlock)(MCPeerID *peer, NSURL *url);  
  113. @property(nonatomiccopyvoid(^connectionStatus)(MCPeerID *peer, MCSessionState state);  
  114. @property(nonatomiccopyvoid(^browserConnected)(void);  
  115. @property(nonatomiccopyvoid(^browserCancelled)(void);  
  116. @property(nonatomiccopyvoid(^didFindPeer)(MCPeerID *peer, NSDictionary *info);  
  117. @property(nonatomiccopyvoid(^invitationHandler)(BOOL connect, MCSession *session);  
  118. @property(nonatomiccopyvoid(^inviteBlock)(MCPeerID *peer, NSData *context);  
  119. @property(nonatomiccopyvoid(^didStartReceivingResource)(NSString *name, MCPeerID *peer, NSProgress *progress);  
  120. @property(nonatomiccopyvoid(^finalResource)(NSString *name, MCPeerID *peer, NSURL *url, NSError *error);  
  121. @property(nonatomiccopyvoid(^streamBlock)(NSInputStream *inputStream, MCPeerID *peer, NSString *streamName);  
  122. // 各种判断  
  123. @property(nonatomic, assign) BOOL receiveOnMainQueue;  
  124. @property(nonatomic, assign) BOOL statusOnMainQueue;  
  125. @property(nonatomic, assign) BOOL resourceFinalOnMainQueue;  
  126. @property(nonatomic, assign) BOOL resourceStart;  
  127. @end  
  128. @implementation BlueSessionManager  
  129. #pragma mark 初始化自己  
  130. - (instancetype)initWithDisplayName:(NSString *)displayName  
  131. {  
  132.     return [self initWithDisplayName:displayName securityIdentity:nil encryptionPreferences:MCEncryptionNone serviceType:ServiceType];  
  133. }  
  134. // 为上面自定义 用户  
  135. - (instancetype)initWithDisplayName:(NSString *)displayName securityIdentity:(NSArray *)security encryptionPreferences:(MCEncryptionPreference)preference serviceType:(NSString *)type  
  136. {  
  137.     self = [super init];  
  138.     if(!self) {  
  139.         return nil;  
  140.     }  
  141.     self.peerID = [[MCPeerID alloc]initWithDisplayName:displayName];  
  142.     self.currentSession = [[MCSession alloc]initWithPeer:self.peerID securityIdentity:security encryptionPreference:preference];  
  143.     self.session.delegate = self;  
  144.     self.serviceType = type;  
  145.     return self;  
  146. }  
  147. #pragma mark 宣传自己  
  148. - (void)advertiseForBrowserViewController  
  149. {  
  150.     [self advertiseForBrowserViewControllerWithDiscoveryInfo:nil];  
  151. }  
  152.   
  153. - (void)advertiseForBrowserViewControllerWithDiscoveryInfo:(NSDictionary *)info  
  154. {  
  155.     //  
  156.     self.advertiser = [[MCNearbyServiceAdvertiser alloc]initWithPeer:self.peerID discoveryInfo:info serviceType:self.serviceType];  
  157.     self.advertiser.delegate = self;  
  158.     [self.advertiser startAdvertisingPeer];  
  159. }  
  160.   
  161. - (void)advertiseForProgrammaticDiscovery  
  162. {  
  163.     [self advertiseForProgrammaticDiscoveryWithDiscoveryInfo:nil];  
  164. }  
  165.   
  166. - (void)advertiseForProgrammaticDiscoveryWithDiscoveryInfo:(NSDictionary *)info  
  167. {  
  168.     //自定义自己,为了让其他设备搜索到自己  
  169.     self.advertisingAssistant = [[MCAdvertiserAssistant alloc]initWithServiceType:self.serviceType discoveryInfo:info session:self.session];  
  170.     self.advertisingAssistant.delegate = self;  
  171.     [self.advertisingAssistant start];  
  172. }  
  173.   
  174. - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOLMCSession *))invitationHandler {  
  175.     self.invitationHandler = [invitationHandler copy];  
  176.     if(self.inviteBlockself.inviteBlock(peerID, context);  
  177. }  
  178.   
  179. #pragma mark 下面是MCAdvertiserAssistant的两个代理  
  180. - (void)advertiserAssistantDidDismissInvitation:(MCAdvertiserAssistant *)advertiserAssistant  
  181. {  
  182.     //TODO implement  
  183. }  
  184.   
  185. - (void)advertiserAssitantWillPresentInvitation:(MCAdvertiserAssistant *)advertiserAssistant {  
  186.     //TODO implement  
  187. }  
  188.   
  189. #pragma mark  扫描其他的设备  
  190. - (void)browseForProgrammaticDiscovery  
  191. {  
  192.       
  193.     self.browser = [[MCNearbyServiceBrowser alloc]initWithPeer:self.peerID serviceType:self.serviceType];  
  194.     self.browser.delegate = self;  
  195.     [self.browser startBrowsingForPeers];  
  196.       
  197. }  
  198.   
  199. #pragma mark MCNearbyServiceBrowserDelegate   
  200. - (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID  
  201. {  
  202.     //TODO implement  
  203. }  
  204.   
  205. - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info  
  206. {  
  207.     if(self.didFindPeer)  
  208.     {  
  209.         self.didFindPeer(peerID, info);  
  210.     }  
  211. }  
  212.   
  213. - (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error  
  214. {  
  215.     //TODO implement  
  216. }  
  217.   
  218. #pragma mark 参加会议  也是会议的代理  
  219. //   也是  ----- MCSessionDelegate  
  220.   
  221. //  这是完成会议的结果···  
  222. - (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error  
  223. {  
  224.       if(self.resourceFinalOnMainQueue)  
  225.     {  
  226.         [[NSOperationQueue mainQueue]addOperationWithBlock:^{  
  227.             if(self.finalResource)  
  228.             {  
  229.                 self.finalResource(resourceName, peerID, localURL, error);  
  230.             }  
  231.         }];  
  232.     }  
  233.     else  
  234.     {  
  235.         if(self.finalResource)  
  236.         {  
  237.             self.finalResource(resourceName, peerID, localURL, error);  
  238.         }  
  239.     }  
  240. }  
  241. // 这是参加  普通数据的会议  
  242. - (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID  
  243. {  
  244.     if(self.receiveOnMainQueue)  
  245.     {  
  246.     [[NSOperationQueue mainQueue]addOperationWithBlock:^{  
  247.      if(self.receiveDataBlock){  
  248.         self.receiveDataBlock(data, peerID);  
  249.             }  
  250.         }];  
  251.     }  
  252.     else  
  253.     {  
  254.         if(self.receiveDataBlock)  
  255.         {  
  256.             self.receiveDataBlock(data, peerID);  
  257.         }  
  258.     }  
  259. }  
  260. // 这是参加普通流的会议  
  261. - (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID  
  262. {  
  263.      if(self.streamBlock)  
  264.     {  
  265.         self.streamBlock(stream, peerID, streamName);  
  266.     }  
  267. }  
  268. // 这是参加图片资源的会议  
  269. - (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress  
  270. {  
  271.     if(self.resourceStart)  
  272.     {  
  273.           
  274.         [[NSOperationQueue mainQueue]addOperationWithBlock:^{  
  275.             if(self.didStartReceivingResource)  
  276.             {  
  277.                 self.didStartReceivingResource(resourceName, peerID, progress);  
  278.             }  
  279.         }];  
  280.     }  
  281.     else  
  282.     {  
  283.         
  284.         if(self.didStartReceivingResource)  
  285.         {  
  286.             self.didStartReceivingResource(resourceName, peerID, progress);  
  287.         }  
  288.     }  
  289. }  
  290.   
  291.   
  292. // 这是不同数据,系那是不同会议时候的状态  
  293.   
  294. - (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state  
  295. {  
  296.     // 这个地方是当两个蓝牙设备一旦连接起来,就会形成的一个会议  
  297.     if(self.statusOnMainQueue)  
  298.     {  
  299.         [[NSOperationQueue mainQueue]addOperationWithBlock:^{  
  300.             if(self.connectionStatus)  
  301.             {  
  302.                 self.connectionStatus(peerID, state);  
  303.             }  
  304.         }];  
  305.     }  
  306.     else  
  307.     {  
  308.         if(self.connectionStatus)  
  309.         {  
  310.             self.connectionStatus(peerID, state);  
  311.         }  
  312.     }  
  313. }  
  314.   
  315.   
  316.   
  317. #pragma mark  send And receive  
  318. //--------------------------------------------------------------------------------------------//  
  319. // 发送消息  
  320. // 用户多个  
  321. - (NSError *)sendDataToAllPeers:(NSData *)data  
  322. {  
  323.     // 普通数据的发送  
  324.     return [self sendDataToAllPeers:data withMode:MCSessionSendDataReliable];  
  325. }  
  326.   
  327. - (NSError *)sendDataToAllPeers:(NSData *)data withMode:(MCSessionSendDataMode)mode  
  328. {  
  329.     // 确实进入会议  
  330.     NSError *error;  
  331.     [self.session sendData:data toPeers:self.session.connectedPeers withMode:mode error:&error];  
  332.     return error;  
  333. }  
  334.   
  335. // 用户确定一个  
  336. - (NSError *)sendData:(NSData *)data toPeers:(NSArray *)peers  
  337. {  
  338.     return [self sendData:data toPeers:peers withMode:MCSessionSendDataReliable];  
  339. }  
  340.   
  341. - (NSError *)sendData:(NSData *)data toPeers:(NSArray *)peers withMode:(MCSessionSendDataMode)mode  
  342. {  
  343.     NSError *error;  
  344.     [self.session sendData:data toPeers:peers withMode:mode error:&error];  
  345.     return error;  
  346. }  
  347.   
  348.   
  349. // 接收消息  
  350. - (void)receiveDataOnMainQueue:(BOOL)mainQueue block:(void (^)(NSData *data, MCPeerID *peer))dataBlock  
  351. {  
  352.       
  353.     self.receiveDataBlock = [dataBlock copy];  
  354.     self.receiveOnMainQueue = mainQueue;  
  355. }  
  356. //--------------------------------------------------------------------------------------------//