最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

iPhone 掌握蓝牙通信编程初体验

IT圈 admin 111浏览 0评论

2024年2月21日发(作者:暴芳蔼)

iPhone 掌握蓝牙通信编程初体验

/a2010/0114/837/

【IT168技术】iPhone OS 3.0的最佳功能是GameKit框架,这个框架包括了允许基于蓝牙网络进行通信的API,你可以更轻松地创建点到点的游戏和应用程序。与其它移动平台不一样,在iPhone中使用蓝牙作为一个通信信道比预期的要容易得多,因此,本文将向你展示如何构建一个简单的应用程序,实现iPhone和iPod之间的相互通信。

注意:如果要测试本文所介绍的内容,需要两部iPhone(3G或3GS),或使用iPhone OS 3.0或更高版本的iPod设备(二代或更新版本)。

创建一个项目

使用Xcode,创建一个新的基于视图的应用程序项目,取名为Bluetooth。访问蓝牙的各种API位于GameKit框架中,因此,你需要将这个框架添加到刚刚创建的项目中,在Xcode的框架组上点右键,选择“添加”*“现有框架”,选择GameKit框架,如图1所示。

图 1 添加GameKit框架

在BluetoothViewController.h文件中,声明下面的对象,outlet和行为:

1 #import

2

3 #import

4

5 @interface BluetoothViewController : UIViewController {

6

7 GKSession *currentSession;

8

9 IBOutlet UITextField *txtMessage;

10

11 IBOutlet UIButton *connect;

12

13 IBOutlet UIButton *disconnect;

14

15 }

16

17 @property (nonatomic, retain) GKSession *currentSession;

18

19 @property (nonatomic, retain) UITextField *txtMessage;

20

21 @property (nonatomic, retain) UIButton *connect;

22

23 @property (nonatomic, retain) UIButton *disconnect;

24

25 -(IBAction) btnSend:(id) sender;

26

27 -(IBAction) btnConnect:(id) sender;

28

29 -(IBAction) btnDisconnect:(id) sender;

30

31 @end

32

33

GKSession对象用于表现两个蓝牙设备之间连接的一个会话,你也可以使用它在两个设备之间发送和接收数据。

在BluetoothViewController.m文件中,添加下面的代码:

1 #import "BluetoothViewController.h"

2

3 #import

4

5 @implementation BluetoothViewController

6

7 @synthesize currentSession;

8

9 @synthesize txtMessage;

10

11 @synthesize connect;

12

13 @synthesize disconnect;

14

15

双击在Interface Builder中编辑它,在视图窗口中添加以下视图,如图2所示。

文本区域(Text Field)

圆形按钮(Round Rect Button)

图 2在视图窗口中填充文本区域和圆形按钮视图

执行以下行为:

按住CTRL键,在文件所有者项目上点击,将其拖放到文本区域视图上,选择txtMessage;

按住CTRL键,在文件所有者项目上点击,将其拖放到连接按钮上,选择connect;

按住CTRL键,在文件所有者项目上点击,将其拖放到断开连接按钮上,选择disconnect;

按住CTRL键,在发送按钮上点击,将其拖放到文件所有者项目上,选择btnSend;

按住CTRL键,在连接按钮上点击,将其拖放到文件所有者项目上,选择btnConnect;

按住CTRL键,在断开连接按钮上点击,将其拖放到文件所有者项目上,选择btnDisconnect;

在文件所有者项目上点击右键,验证所有连接是否正常,如图3所示。

图 3 验证所有连接是否正常

返回Xcode,在BluetoothViewController.m文件中,添加以下代码:

1 - (void)viewDidLoad {

2

3 [connect setHidden:NO];

4

5 [disconnect setHidden:YES];

6

7 [super viewDidLoad];

8

9 }

10

11 - (void)dealloc {

12

13 [txtMessage release];

14

15 [currentSession release];

16

17 [super dealloc];

18

19 }

20

21

搜索对等设备

现在所有准备工作已经就绪,接下来介绍一下访问其它蓝牙设备的API。

在BluetoothViewController.h文件中,声明一个GKPeerPickerController对象:

1 #import "BluetoothViewController.h"

2

3 #import

4

5 @implementation BluetoothViewController

6

7 @synthesize currentSession;

8

9 @synthesize txtMessage;

10

11 @synthesize connect;

12

13 @synthesize disconnect;

14

15 GKPeerPickerController *picker;

16

17

GKPeerPickerController类提供了一个标准的UI让你的应用程序发现并连接到其它蓝牙设备,连接方法并不难,首先实现一个btnConnect:类:

1 -(IBAction) btnConnect:(id) sender {

2

3 picker = [[GKPeerPickerController alloc] init];

4

5 te = self;

6

7 tionTypesMask = GKPeerPickerConnectionTypeNearby;

8

9 [connect setHidden:YES];

10

11 [disconnect setHidden:NO];

12

13 [picker show];

14

15 }

16

17

connectionTypesMask属性指出用户可以选择的连接类型,包括两种类型:GKPeerPickerConnectionTypeNearby和GKPeerPickerConnectionTypeOnline。对于蓝牙通信,使用GKPeerPickerConnectionTypeNearby常量,GKPeerPickerConnectionTypeOnline常量表示基于互联网的连接。

检测到远程蓝牙设备,用户选择并连接到其中一个蓝牙设备时,调用peerPickerController:didConnectPeer:toSession:方法,这个方法的实现如下:

1 - (void)peerPickerController:(GKPeerPickerController *)picker

2

3 didConnectPeer:(NSString *)peerID

4

5 toSession:(GKSession *) session {

6

7 tSession = session;

8

9 te = self;

10

11 [session setDataReceiveHandler:self withContext:nil];

12

13 te = nil;

14

15 [picker dismiss];

16

17 [picker autorelease];

18

19 }

20

21

当用户已经连接到对等蓝牙设备后,可以将GKSession对象保存到currentSession属性中,这样你可以使用GKSession对象与远程设备通信。

如果用户取消了蓝牙选择器,调用peerPickerControllerDidCancel:方法,其定义如下:

1 - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker

2

3 {

4

5 te = nil;

6

7 [picker autorelease];

8

9 [connect setHidden:NO];

10

11 [disconnect setHidden:YES];

12

13 }

14

15

如果要从一个设备断开连接,使用来自GKSession对象的disconnectFromAllPeers方法,btnDisconnect:方法的实现如下:

1 -(IBAction) btnDisconnect:(id) sender {

2

3 [tSession disconnectFromAllPeers];

4

5 [tSession release];

6

7 currentSession = nil;

8

9 [connect setHidden:NO];

10

11 [disconnect setHidden:YES];

12

13 }

14

15

连接设备或断开连接时,调用session:peer:didChangeState:方法,其实现如下:

1 - (void)session:(GKSession *)session

2

3 peer:(NSString *)peerID

4

5 didChangeState:(GKPeerConnectionState)state {

6

7 switch (state)

8

9 {

10

11 case GKPeerStateConnected:

12

13 NSLog(@"connected");

14

15 break;

16

17 case GKPeerStateDisconnected:

18

19 NSLog(@"disconnected");

20

21 [tSession release];

22

23 currentSession = nil;

24

25 [connect setHidden:NO];

26

27 [disconnect setHidden:YES];

28

29 break;

30

31 }

32

33 }

34

35

处理这个事件你将知道连接是什么时候建立的,或断开是什么时候发生的。例如,当建立一个连接时,你可能想要立即向对方发送数据。

发送数据

为了向连接的蓝牙设备发送数据,需要使用到GKSession对象的sendDataToAllPeers:方法,你发送的数据是通过NSData对象传输的,因此你可以自定义你的应用程序协议和发送的数据类型(如二进制数据),mySendDataToPeers:方法的定义如下:

1 - (void) mySendDataToPeers:(NSData *) data

2

3 {

4

5 if (currentSession)

6

7 [tSession sendDataToAllPeers:data

8

9 withDataMode:GKSendDataReliable

10

11 error:nil];

12

13 }

14

15 再定义btnSend:方法,以便用户输入的数据能够发送到远程设备:

16

17 -(IBAction) btnSend:(id) sender

18

19 {

20

21 //---convert an NSString object to NSData---

22

23 NSData* data;

24

25 NSString *str = [NSString stringWithString:];

26

27 data = [str dataUsingEncoding: NSASCIIStringEncoding];

28

29 [self mySendDataToPeers:data];

30

31 }

32

33

接收数据

当设备接收到数据时,调用receiveData:fromPeer:inSession:context:方法,其实现如下:

1 - (void) receiveData:(NSData *)data

2

3 fromPeer:(NSString *)peer

4

5 inSession:(GKSession *)session

6

7 context:(void *)context {

8

9 //---convert the NSData to NSString---

10

11 NSString* str;

12

13 str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

14

15 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data received"

16

17 message:str

18

19 delegate:self

20

21 cancelButtonTitle:@"OK"

22

23 otherButtonTitles:nil];

24

25 [alert show];

26

27 [alert release];

28

29 }

30

31

这里接收到的数据是NSData格式,为了使用UIAlertView类显示它,你需要将其转换为NSString对象。

测试应用程序

就是这么简单!现在可以开始测试了,在Xcode中按下Command-R,将程序部署到iPhone/iPod上,本文假设你有两部iPhone或两部iPod,为了运行刚刚创建的程序,这两台设备上都需要运行iPhone OS 3.0。

部署好程序后,在两台设备上启动好程序,在任一设备上点击连接按钮,GKPeerPickerController将会显示标准的UI发现其它设备,如图4所示。

图 4 GKPeerPickerController查找其它设备

等待一会儿后,两边的程序应该都能够发现对方,如图5所示,当你在发现的设备名称上轻轻点击,程序就会开始连接。

图 5 显示发现的设备名称

注意:如果你在iPhone模拟器上测试这个程序,应该会检测到两个设备,但却无法连接到任何设备。

当其它设备试图连接到你的设备时,你将会看到如图6所示的弹出提示,点击“接受”允许其连接,点击“拒绝”拒绝其连接。

图 6 其它设备试图连接到你时的提示

如果成功与你建立了连接,你就可以输入一些文本信息发给对方了,从其它设备接收到数据将会以一个警告视图显示,如图7所示。

图 7 接收到其它设备发来的数据

小结

通过本文的介绍,你会发现使用蓝牙连接两台iPhone/iPod是多么的简单,使用本文所介绍的内容,你可以轻松构建一个网络游戏或其它有趣的应用。在下一篇文章中,我将会介绍如何使用蓝牙连接传输语音数据,请密切关注。

iPhone蓝牙编程之实现语音聊天

/a2010/0129/845/

【IT168技术】在我之前的iPhone文章中,我们已经介绍过使用GameKit框架在两个设备之间通过蓝牙通信,在这篇文章中,我将为大家介绍GameKit框架另一个很酷的功能 — 语音聊天。

Gamekit中的语音聊天服务允许两台iPhone/iPod Touch之间建立语音聊天,语音聊天要么通过互联网,要么通过蓝牙实现,你将在本文中看到如何通过蓝牙通信信道实现语音聊天。

创建项目

首先使用Xcode创建一个新的基于视图的iPhone应用程序,取名为Bluetooth,在Xcode的框架组上点击右键,选择“增加”,从现有框架中选择一个增加到项目上,这里选择ork,同时再增加一个AVFoundation框架。

在BluetoothViewController.h文件中,增加下面的代码:

1 #import <UIKit/UIKit.h>

2 #import <GameKit/GameKit.h>

3 #import <AVFoundation/AVFoundation.h>

4 @interface BluetoothViewController : UIViewController

5    <GKVoiceChatClient> {

6

7    GKSession *currentSession;

8    

9    IBOutlet UIButton *connect;

10    IBOutlet UIButton *disconnect;

11 }

12 @property (nonatomic, retain) GKSession *currentSession;

13 @property (nonatomic, retain) UIButton *connect;

14 @property (nonatomic, retain) UIButton *disconnect;

15

16 -(IBAction) btnMute:(id) sender;

17 -(IBAction) btnUnmute:(id) sender;

18 -(IBAction) btnConnect:(id) sender;

19 -(IBAction) btnDisconnect:(id) sender;

20 @end

21

拖动一个wav文件(如无特殊说明,指)到Xcode的Resources文件夹上。

双击文件在Interface Builder编辑它,使用三个圆形按钮填充到视图窗口中,如图1所示。

图 1 使用三个圆形按钮填充视图窗口

在窗口中,执行以下连接:

按住CTRL键,点击文件所有者项目,将其拖放到Connect按钮上,选择连接;

按住CTRL键,点击文件所有者项目,将其拖放到Disconnect按钮上,选择断开连接;

按住CTRL键,点击Connect按钮,将其拖放到文件所有者项目上,选择btnConnect;

按住CTRL键,点击Disconnect按钮,将其拖放到文件所有者项目上,选择btnDisconnect;

在Mute按钮上点击右键,将Touch Down事件连接到文件所有者项目上,选择btnMute;

在Mute按钮上点击右键,将Touch Up Inside事件连接到文件所有者项目上,选择btnUnmute;

为了验证所有连接是否正确,在文件所有者项目上点击右键,查看其连接,如图2所示。

图 2 验证出口和行为的连接

在BluetoothViewController.m文件中,增加下面的代码:

1 #import "BluetoothViewController.h"

2 #import

3 #import

4

5 @implementation BluetoothViewController

6 @synthesize currentSession;

7 @synthesize connect;

8 @synthesize disconnect;

9

10 GKPeerPickerController *picker;

11 NSString *recorderFilePath;

12

13 AVAudioPlayer *audioPlayer;

14

15 - (void)viewDidLoad {

16

17 [connect setHidden:NO];

18 [disconnect setHidden:YES];

19

20 [super viewDidLoad];

21 }

22

23 - (IBAction) btnConnect:(id) sender {

24

25 //---选择一个附近的蓝牙设备---

26 picker = [[GKPeerPickerController alloc] init];

27 te = self;

28 tionTypesMask = GKPeerPickerConnectionTypeNearby;

29

30 [connect setHidden:YES];

31 [disconnect setHidden:NO];

32

33 [picker show];

34

35 }

36

37 -(IBAction) btnDisconnect:(id) sender {

38

39 //---从其它设备断开连接---

40 [tSession disconnectFromAllPeers];

41 [tSession release];

42 currentSession = nil;

43

44 [connect setHidden:NO];

45 [disconnect setHidden:YES];

46

47 }

48

49 - (void)peerPickerController:(GKPeerPickerController *)picker

50 didConnectPeer:(NSString *)peerID

51 toSession: (GKSession *) session {

52

53 tSession = session;

54 te = self;

55 [session setDataReceiveHandler: self withContext:nil];

56 te = nil;

57 [picker dismiss];

58 [picker autorelease];

59

60 }

61

62 - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker {

63

64 te = nil;

65 [picker autorelease];

66

67 [connect setHidden:NO];

68 [disconnect setHidden:YES];

69

70 }

71

72 -(IBAction) btnMute:(id) sender {

73

74 //---静音语音聊天---

75 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;

76

77 }

78

79 -(IBAction) btnUnmute:(id) sender {

80

81 //---取消静音---

82 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = NO;

83

84 }

85

86 //---返回一个表示本地用户的唯一ID ---

87 -(NSString *) participantID

88 {

89 return ;

90 }

91

92 -(void) voiceChatService:(GKVoiceChatService *) voiceChatService

93 sendData:(NSData *) data

94 toParticipantID:(NSString *)participantID {

95

96 [currentSession sendData:data toPeers:

97 [NSArray arrayWithObject:participantID]

98 withDataMode:GKSendDataReliable error:nil];

99

100 }

101

102 - (void)session:(GKSession *)session

103 peer:(NSString *)peerID

104 didChangeState:(GKPeerConnectionState)state {

105

106 switch (state)

107 {

108 case GKPeerStateConnected:

109 {

110 //---播放一个音频文件---

111 NSString *soundFilePath = [[NSBundle mainBundle]

112 pathForResource:@"beep" ofType:@"wav"];

113

114 NSURL *fileURL = [[NSURL alloc]

115 initFileURLWithPath: soundFilePath];

116

117 AVAudioPlayer *audioPlayer =

118 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL

119 error:nil];

120

121 [fileURL release];

122 [audioPlayer play];

123

124 NSError *error;

125 AVAudioSession *audioSession =

126 [AVAudioSession sharedInstance];

127

128 if (![audioSession

129 setCategory:AVAudioSessionCategoryPlayAndRecord

130 error:&error]) {

131 NSLog(@"Error setting the AVAudioSessionCategoryPlayAndRecord category: %@",

132 [error localizedDescription]);

133 }

134

135 if (![audioSession setActive: YES error: &error]) {

136 NSLog(@"Error activating audioSession: %@",

137 [error description]);

138 }

139

140 [GKVoiceChatService defaultVoiceChatService].client = self;

141

142 //---初始化语音聊天---

143 if (![[GKVoiceChatService defaultVoiceChatService]

144 startVoiceChatWithParticipantID:peerID error:&error]) {

145 NSLog(@"Error starting startVoiceChatWithParticipantID: %@",

146 [error userInfo]);

147 }

148 } break;

149

150 case GKPeerStateDisconnected:

151 {

152 [[GKVoiceChatService defaultVoiceChatService]

153 stopVoiceChatWithParticipantID:peerID];

154

155 [tSession release];

156 currentSession = nil;

157

158 [connect setHidden:NO];

159 [disconnect setHidden:YES];

160

161 } break;

162 }

163 }

164

165 - (void) receiveData:(NSData *)data

166 fromPeer:(NSString *)peer

167 inSession:(GKSession *)session

168 context:(void *)context {

169

170 //---初始化完成后开始语音聊天---

171 [[GKVoiceChatService defaultVoiceChatService]

172 receivedData:data fromParticipantID:peer];

173

174 }

175

176 - (void)dealloc {

177

178 if (currentSession) [currentSession release];

179 [connect release];

180 [disconnect release];

181

182 [super dealloc];

183 }

184 @end

185

理解语音聊天是如何工作的

当两个蓝牙设备连接时,首先播放文件发出嘟嘟声,然后启动语音会话(通过session:peer:didChangeState:方法实现)。

1 NSString *soundFilePath = [[NSBundle mainBundle]

2 pathForResource:@"beep" ofType:@"wav"];

3

4 NSURL *fileURL = [[NSURL alloc]

5 initFileURLWithPath: soundFilePath];

6

7 AVAudioPlayer *audioPlayer =

8 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL

9 error:nil];

10

11 [fileURL release];

12 [audioPlayer play];

13

14 NSError *error;

15 AVAudioSession *audioSession =

16 [AVAudioSession sharedInstance];

17

18 if (![audioSession

19 setCategory:AVAudioSessionCategoryPlayAndRecord

20 error:&error]) {

21 NSLog(@"Error setting the AVAudioSessionCategoryPlayAndRecord category: %@",

22 [error localizedDescription]);

23 }

24

25 if (![audioSession setActive: YES error: &error]) {

26 NSLog(@"Error activating audioSession: %@",

27 [error description]);

28 }

29

30 [GKVoiceChatService defaultVoiceChatService].client = self;

31

提示:有趣的是,如果你不启动音频播放器,语音聊天不能正常工作。

然后检索GKVoiceChatService类的单一实例,调用它的startVoiceChatWithParticipantID:error:方法启动语音聊天。

1 if (![[GKVoiceChatService defaultVoiceChatService]

2 startVoiceChatWithParticipantID:peerID error:&error]) {

3 NSLog(@"Error starting startVoiceChatWithParticipantID: %@",

4 [error userInfo]);

5 }

6

调用startVoiceChatWithParticipantID:error:方法将会请求voiceChatService:sendData:toParticipantID:方法,它将会使用当前的蓝牙会话发送配置数据到其它设备。

1 -(void) voiceChatService:(GKVoiceChatService *) voiceChatService

2 sendData:(NSData *) data

3 toParticipantID:(NSString *)participantID {

4

5 [currentSession sendData:data toPeers:

6 [NSArray arrayWithObject:participantID]

7 withDataMode:GKSendDataReliable error:nil];

8

9 }

10

其它连接的设备接收到发来的配置数据后,通过调用receivedData:fromParticipantID:方法启动语音聊天服务。

GKVoiceChatService使用两个设备之间交互的配置信息创建它自己的连接传输语音数据,还可以将microphoneMuted属性的值设为YES使麦克风静音。

1 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;

测试应用程序

在开始测试之前,先要把应用程序两台iPhone或iPod Touch上,对于iPod Touch,你需要使用一个外置麦克风,因为它默认是不带有麦克风的,一个好选择是Griffin iTalk Pro,如图3所示,它是iPod Touch麦克风及其零配件插入的基座,另外也支持苹果头戴式耳机及其配件。

图 3 Griffin iTalk Pro

应用程序部署到设备上后,启动应用程序,按下Connect按钮使用蓝牙相互连接,当两个设备连接好后,就可以开始聊天了,如果要临时静音,按下Mute按钮一直不放即可,放开Mute按钮后,声音就又恢复了。

在这篇文章中,你看到了如何使用Gamekit框架提供的GKVoiceChatService类在两个设备之间无缝地建立语音通信,关于两个设备之间的语音是如何传输的暂时没有必要知道,所有需要了解的就是要知道调用什么方法初始化语音聊天,另外你还要知道,语音聊天不仅可以通过蓝牙通信信道实现,在其它任何通信信道上都可以实现,实际上,如果使用TCP/IP连接两台设备,也可以实现语音聊天,在今后的文章中,我将会涉及。

2024年2月21日发(作者:暴芳蔼)

iPhone 掌握蓝牙通信编程初体验

/a2010/0114/837/

【IT168技术】iPhone OS 3.0的最佳功能是GameKit框架,这个框架包括了允许基于蓝牙网络进行通信的API,你可以更轻松地创建点到点的游戏和应用程序。与其它移动平台不一样,在iPhone中使用蓝牙作为一个通信信道比预期的要容易得多,因此,本文将向你展示如何构建一个简单的应用程序,实现iPhone和iPod之间的相互通信。

注意:如果要测试本文所介绍的内容,需要两部iPhone(3G或3GS),或使用iPhone OS 3.0或更高版本的iPod设备(二代或更新版本)。

创建一个项目

使用Xcode,创建一个新的基于视图的应用程序项目,取名为Bluetooth。访问蓝牙的各种API位于GameKit框架中,因此,你需要将这个框架添加到刚刚创建的项目中,在Xcode的框架组上点右键,选择“添加”*“现有框架”,选择GameKit框架,如图1所示。

图 1 添加GameKit框架

在BluetoothViewController.h文件中,声明下面的对象,outlet和行为:

1 #import

2

3 #import

4

5 @interface BluetoothViewController : UIViewController {

6

7 GKSession *currentSession;

8

9 IBOutlet UITextField *txtMessage;

10

11 IBOutlet UIButton *connect;

12

13 IBOutlet UIButton *disconnect;

14

15 }

16

17 @property (nonatomic, retain) GKSession *currentSession;

18

19 @property (nonatomic, retain) UITextField *txtMessage;

20

21 @property (nonatomic, retain) UIButton *connect;

22

23 @property (nonatomic, retain) UIButton *disconnect;

24

25 -(IBAction) btnSend:(id) sender;

26

27 -(IBAction) btnConnect:(id) sender;

28

29 -(IBAction) btnDisconnect:(id) sender;

30

31 @end

32

33

GKSession对象用于表现两个蓝牙设备之间连接的一个会话,你也可以使用它在两个设备之间发送和接收数据。

在BluetoothViewController.m文件中,添加下面的代码:

1 #import "BluetoothViewController.h"

2

3 #import

4

5 @implementation BluetoothViewController

6

7 @synthesize currentSession;

8

9 @synthesize txtMessage;

10

11 @synthesize connect;

12

13 @synthesize disconnect;

14

15

双击在Interface Builder中编辑它,在视图窗口中添加以下视图,如图2所示。

文本区域(Text Field)

圆形按钮(Round Rect Button)

图 2在视图窗口中填充文本区域和圆形按钮视图

执行以下行为:

按住CTRL键,在文件所有者项目上点击,将其拖放到文本区域视图上,选择txtMessage;

按住CTRL键,在文件所有者项目上点击,将其拖放到连接按钮上,选择connect;

按住CTRL键,在文件所有者项目上点击,将其拖放到断开连接按钮上,选择disconnect;

按住CTRL键,在发送按钮上点击,将其拖放到文件所有者项目上,选择btnSend;

按住CTRL键,在连接按钮上点击,将其拖放到文件所有者项目上,选择btnConnect;

按住CTRL键,在断开连接按钮上点击,将其拖放到文件所有者项目上,选择btnDisconnect;

在文件所有者项目上点击右键,验证所有连接是否正常,如图3所示。

图 3 验证所有连接是否正常

返回Xcode,在BluetoothViewController.m文件中,添加以下代码:

1 - (void)viewDidLoad {

2

3 [connect setHidden:NO];

4

5 [disconnect setHidden:YES];

6

7 [super viewDidLoad];

8

9 }

10

11 - (void)dealloc {

12

13 [txtMessage release];

14

15 [currentSession release];

16

17 [super dealloc];

18

19 }

20

21

搜索对等设备

现在所有准备工作已经就绪,接下来介绍一下访问其它蓝牙设备的API。

在BluetoothViewController.h文件中,声明一个GKPeerPickerController对象:

1 #import "BluetoothViewController.h"

2

3 #import

4

5 @implementation BluetoothViewController

6

7 @synthesize currentSession;

8

9 @synthesize txtMessage;

10

11 @synthesize connect;

12

13 @synthesize disconnect;

14

15 GKPeerPickerController *picker;

16

17

GKPeerPickerController类提供了一个标准的UI让你的应用程序发现并连接到其它蓝牙设备,连接方法并不难,首先实现一个btnConnect:类:

1 -(IBAction) btnConnect:(id) sender {

2

3 picker = [[GKPeerPickerController alloc] init];

4

5 te = self;

6

7 tionTypesMask = GKPeerPickerConnectionTypeNearby;

8

9 [connect setHidden:YES];

10

11 [disconnect setHidden:NO];

12

13 [picker show];

14

15 }

16

17

connectionTypesMask属性指出用户可以选择的连接类型,包括两种类型:GKPeerPickerConnectionTypeNearby和GKPeerPickerConnectionTypeOnline。对于蓝牙通信,使用GKPeerPickerConnectionTypeNearby常量,GKPeerPickerConnectionTypeOnline常量表示基于互联网的连接。

检测到远程蓝牙设备,用户选择并连接到其中一个蓝牙设备时,调用peerPickerController:didConnectPeer:toSession:方法,这个方法的实现如下:

1 - (void)peerPickerController:(GKPeerPickerController *)picker

2

3 didConnectPeer:(NSString *)peerID

4

5 toSession:(GKSession *) session {

6

7 tSession = session;

8

9 te = self;

10

11 [session setDataReceiveHandler:self withContext:nil];

12

13 te = nil;

14

15 [picker dismiss];

16

17 [picker autorelease];

18

19 }

20

21

当用户已经连接到对等蓝牙设备后,可以将GKSession对象保存到currentSession属性中,这样你可以使用GKSession对象与远程设备通信。

如果用户取消了蓝牙选择器,调用peerPickerControllerDidCancel:方法,其定义如下:

1 - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker

2

3 {

4

5 te = nil;

6

7 [picker autorelease];

8

9 [connect setHidden:NO];

10

11 [disconnect setHidden:YES];

12

13 }

14

15

如果要从一个设备断开连接,使用来自GKSession对象的disconnectFromAllPeers方法,btnDisconnect:方法的实现如下:

1 -(IBAction) btnDisconnect:(id) sender {

2

3 [tSession disconnectFromAllPeers];

4

5 [tSession release];

6

7 currentSession = nil;

8

9 [connect setHidden:NO];

10

11 [disconnect setHidden:YES];

12

13 }

14

15

连接设备或断开连接时,调用session:peer:didChangeState:方法,其实现如下:

1 - (void)session:(GKSession *)session

2

3 peer:(NSString *)peerID

4

5 didChangeState:(GKPeerConnectionState)state {

6

7 switch (state)

8

9 {

10

11 case GKPeerStateConnected:

12

13 NSLog(@"connected");

14

15 break;

16

17 case GKPeerStateDisconnected:

18

19 NSLog(@"disconnected");

20

21 [tSession release];

22

23 currentSession = nil;

24

25 [connect setHidden:NO];

26

27 [disconnect setHidden:YES];

28

29 break;

30

31 }

32

33 }

34

35

处理这个事件你将知道连接是什么时候建立的,或断开是什么时候发生的。例如,当建立一个连接时,你可能想要立即向对方发送数据。

发送数据

为了向连接的蓝牙设备发送数据,需要使用到GKSession对象的sendDataToAllPeers:方法,你发送的数据是通过NSData对象传输的,因此你可以自定义你的应用程序协议和发送的数据类型(如二进制数据),mySendDataToPeers:方法的定义如下:

1 - (void) mySendDataToPeers:(NSData *) data

2

3 {

4

5 if (currentSession)

6

7 [tSession sendDataToAllPeers:data

8

9 withDataMode:GKSendDataReliable

10

11 error:nil];

12

13 }

14

15 再定义btnSend:方法,以便用户输入的数据能够发送到远程设备:

16

17 -(IBAction) btnSend:(id) sender

18

19 {

20

21 //---convert an NSString object to NSData---

22

23 NSData* data;

24

25 NSString *str = [NSString stringWithString:];

26

27 data = [str dataUsingEncoding: NSASCIIStringEncoding];

28

29 [self mySendDataToPeers:data];

30

31 }

32

33

接收数据

当设备接收到数据时,调用receiveData:fromPeer:inSession:context:方法,其实现如下:

1 - (void) receiveData:(NSData *)data

2

3 fromPeer:(NSString *)peer

4

5 inSession:(GKSession *)session

6

7 context:(void *)context {

8

9 //---convert the NSData to NSString---

10

11 NSString* str;

12

13 str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

14

15 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data received"

16

17 message:str

18

19 delegate:self

20

21 cancelButtonTitle:@"OK"

22

23 otherButtonTitles:nil];

24

25 [alert show];

26

27 [alert release];

28

29 }

30

31

这里接收到的数据是NSData格式,为了使用UIAlertView类显示它,你需要将其转换为NSString对象。

测试应用程序

就是这么简单!现在可以开始测试了,在Xcode中按下Command-R,将程序部署到iPhone/iPod上,本文假设你有两部iPhone或两部iPod,为了运行刚刚创建的程序,这两台设备上都需要运行iPhone OS 3.0。

部署好程序后,在两台设备上启动好程序,在任一设备上点击连接按钮,GKPeerPickerController将会显示标准的UI发现其它设备,如图4所示。

图 4 GKPeerPickerController查找其它设备

等待一会儿后,两边的程序应该都能够发现对方,如图5所示,当你在发现的设备名称上轻轻点击,程序就会开始连接。

图 5 显示发现的设备名称

注意:如果你在iPhone模拟器上测试这个程序,应该会检测到两个设备,但却无法连接到任何设备。

当其它设备试图连接到你的设备时,你将会看到如图6所示的弹出提示,点击“接受”允许其连接,点击“拒绝”拒绝其连接。

图 6 其它设备试图连接到你时的提示

如果成功与你建立了连接,你就可以输入一些文本信息发给对方了,从其它设备接收到数据将会以一个警告视图显示,如图7所示。

图 7 接收到其它设备发来的数据

小结

通过本文的介绍,你会发现使用蓝牙连接两台iPhone/iPod是多么的简单,使用本文所介绍的内容,你可以轻松构建一个网络游戏或其它有趣的应用。在下一篇文章中,我将会介绍如何使用蓝牙连接传输语音数据,请密切关注。

iPhone蓝牙编程之实现语音聊天

/a2010/0129/845/

【IT168技术】在我之前的iPhone文章中,我们已经介绍过使用GameKit框架在两个设备之间通过蓝牙通信,在这篇文章中,我将为大家介绍GameKit框架另一个很酷的功能 — 语音聊天。

Gamekit中的语音聊天服务允许两台iPhone/iPod Touch之间建立语音聊天,语音聊天要么通过互联网,要么通过蓝牙实现,你将在本文中看到如何通过蓝牙通信信道实现语音聊天。

创建项目

首先使用Xcode创建一个新的基于视图的iPhone应用程序,取名为Bluetooth,在Xcode的框架组上点击右键,选择“增加”,从现有框架中选择一个增加到项目上,这里选择ork,同时再增加一个AVFoundation框架。

在BluetoothViewController.h文件中,增加下面的代码:

1 #import <UIKit/UIKit.h>

2 #import <GameKit/GameKit.h>

3 #import <AVFoundation/AVFoundation.h>

4 @interface BluetoothViewController : UIViewController

5    <GKVoiceChatClient> {

6

7    GKSession *currentSession;

8    

9    IBOutlet UIButton *connect;

10    IBOutlet UIButton *disconnect;

11 }

12 @property (nonatomic, retain) GKSession *currentSession;

13 @property (nonatomic, retain) UIButton *connect;

14 @property (nonatomic, retain) UIButton *disconnect;

15

16 -(IBAction) btnMute:(id) sender;

17 -(IBAction) btnUnmute:(id) sender;

18 -(IBAction) btnConnect:(id) sender;

19 -(IBAction) btnDisconnect:(id) sender;

20 @end

21

拖动一个wav文件(如无特殊说明,指)到Xcode的Resources文件夹上。

双击文件在Interface Builder编辑它,使用三个圆形按钮填充到视图窗口中,如图1所示。

图 1 使用三个圆形按钮填充视图窗口

在窗口中,执行以下连接:

按住CTRL键,点击文件所有者项目,将其拖放到Connect按钮上,选择连接;

按住CTRL键,点击文件所有者项目,将其拖放到Disconnect按钮上,选择断开连接;

按住CTRL键,点击Connect按钮,将其拖放到文件所有者项目上,选择btnConnect;

按住CTRL键,点击Disconnect按钮,将其拖放到文件所有者项目上,选择btnDisconnect;

在Mute按钮上点击右键,将Touch Down事件连接到文件所有者项目上,选择btnMute;

在Mute按钮上点击右键,将Touch Up Inside事件连接到文件所有者项目上,选择btnUnmute;

为了验证所有连接是否正确,在文件所有者项目上点击右键,查看其连接,如图2所示。

图 2 验证出口和行为的连接

在BluetoothViewController.m文件中,增加下面的代码:

1 #import "BluetoothViewController.h"

2 #import

3 #import

4

5 @implementation BluetoothViewController

6 @synthesize currentSession;

7 @synthesize connect;

8 @synthesize disconnect;

9

10 GKPeerPickerController *picker;

11 NSString *recorderFilePath;

12

13 AVAudioPlayer *audioPlayer;

14

15 - (void)viewDidLoad {

16

17 [connect setHidden:NO];

18 [disconnect setHidden:YES];

19

20 [super viewDidLoad];

21 }

22

23 - (IBAction) btnConnect:(id) sender {

24

25 //---选择一个附近的蓝牙设备---

26 picker = [[GKPeerPickerController alloc] init];

27 te = self;

28 tionTypesMask = GKPeerPickerConnectionTypeNearby;

29

30 [connect setHidden:YES];

31 [disconnect setHidden:NO];

32

33 [picker show];

34

35 }

36

37 -(IBAction) btnDisconnect:(id) sender {

38

39 //---从其它设备断开连接---

40 [tSession disconnectFromAllPeers];

41 [tSession release];

42 currentSession = nil;

43

44 [connect setHidden:NO];

45 [disconnect setHidden:YES];

46

47 }

48

49 - (void)peerPickerController:(GKPeerPickerController *)picker

50 didConnectPeer:(NSString *)peerID

51 toSession: (GKSession *) session {

52

53 tSession = session;

54 te = self;

55 [session setDataReceiveHandler: self withContext:nil];

56 te = nil;

57 [picker dismiss];

58 [picker autorelease];

59

60 }

61

62 - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker {

63

64 te = nil;

65 [picker autorelease];

66

67 [connect setHidden:NO];

68 [disconnect setHidden:YES];

69

70 }

71

72 -(IBAction) btnMute:(id) sender {

73

74 //---静音语音聊天---

75 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;

76

77 }

78

79 -(IBAction) btnUnmute:(id) sender {

80

81 //---取消静音---

82 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = NO;

83

84 }

85

86 //---返回一个表示本地用户的唯一ID ---

87 -(NSString *) participantID

88 {

89 return ;

90 }

91

92 -(void) voiceChatService:(GKVoiceChatService *) voiceChatService

93 sendData:(NSData *) data

94 toParticipantID:(NSString *)participantID {

95

96 [currentSession sendData:data toPeers:

97 [NSArray arrayWithObject:participantID]

98 withDataMode:GKSendDataReliable error:nil];

99

100 }

101

102 - (void)session:(GKSession *)session

103 peer:(NSString *)peerID

104 didChangeState:(GKPeerConnectionState)state {

105

106 switch (state)

107 {

108 case GKPeerStateConnected:

109 {

110 //---播放一个音频文件---

111 NSString *soundFilePath = [[NSBundle mainBundle]

112 pathForResource:@"beep" ofType:@"wav"];

113

114 NSURL *fileURL = [[NSURL alloc]

115 initFileURLWithPath: soundFilePath];

116

117 AVAudioPlayer *audioPlayer =

118 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL

119 error:nil];

120

121 [fileURL release];

122 [audioPlayer play];

123

124 NSError *error;

125 AVAudioSession *audioSession =

126 [AVAudioSession sharedInstance];

127

128 if (![audioSession

129 setCategory:AVAudioSessionCategoryPlayAndRecord

130 error:&error]) {

131 NSLog(@"Error setting the AVAudioSessionCategoryPlayAndRecord category: %@",

132 [error localizedDescription]);

133 }

134

135 if (![audioSession setActive: YES error: &error]) {

136 NSLog(@"Error activating audioSession: %@",

137 [error description]);

138 }

139

140 [GKVoiceChatService defaultVoiceChatService].client = self;

141

142 //---初始化语音聊天---

143 if (![[GKVoiceChatService defaultVoiceChatService]

144 startVoiceChatWithParticipantID:peerID error:&error]) {

145 NSLog(@"Error starting startVoiceChatWithParticipantID: %@",

146 [error userInfo]);

147 }

148 } break;

149

150 case GKPeerStateDisconnected:

151 {

152 [[GKVoiceChatService defaultVoiceChatService]

153 stopVoiceChatWithParticipantID:peerID];

154

155 [tSession release];

156 currentSession = nil;

157

158 [connect setHidden:NO];

159 [disconnect setHidden:YES];

160

161 } break;

162 }

163 }

164

165 - (void) receiveData:(NSData *)data

166 fromPeer:(NSString *)peer

167 inSession:(GKSession *)session

168 context:(void *)context {

169

170 //---初始化完成后开始语音聊天---

171 [[GKVoiceChatService defaultVoiceChatService]

172 receivedData:data fromParticipantID:peer];

173

174 }

175

176 - (void)dealloc {

177

178 if (currentSession) [currentSession release];

179 [connect release];

180 [disconnect release];

181

182 [super dealloc];

183 }

184 @end

185

理解语音聊天是如何工作的

当两个蓝牙设备连接时,首先播放文件发出嘟嘟声,然后启动语音会话(通过session:peer:didChangeState:方法实现)。

1 NSString *soundFilePath = [[NSBundle mainBundle]

2 pathForResource:@"beep" ofType:@"wav"];

3

4 NSURL *fileURL = [[NSURL alloc]

5 initFileURLWithPath: soundFilePath];

6

7 AVAudioPlayer *audioPlayer =

8 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL

9 error:nil];

10

11 [fileURL release];

12 [audioPlayer play];

13

14 NSError *error;

15 AVAudioSession *audioSession =

16 [AVAudioSession sharedInstance];

17

18 if (![audioSession

19 setCategory:AVAudioSessionCategoryPlayAndRecord

20 error:&error]) {

21 NSLog(@"Error setting the AVAudioSessionCategoryPlayAndRecord category: %@",

22 [error localizedDescription]);

23 }

24

25 if (![audioSession setActive: YES error: &error]) {

26 NSLog(@"Error activating audioSession: %@",

27 [error description]);

28 }

29

30 [GKVoiceChatService defaultVoiceChatService].client = self;

31

提示:有趣的是,如果你不启动音频播放器,语音聊天不能正常工作。

然后检索GKVoiceChatService类的单一实例,调用它的startVoiceChatWithParticipantID:error:方法启动语音聊天。

1 if (![[GKVoiceChatService defaultVoiceChatService]

2 startVoiceChatWithParticipantID:peerID error:&error]) {

3 NSLog(@"Error starting startVoiceChatWithParticipantID: %@",

4 [error userInfo]);

5 }

6

调用startVoiceChatWithParticipantID:error:方法将会请求voiceChatService:sendData:toParticipantID:方法,它将会使用当前的蓝牙会话发送配置数据到其它设备。

1 -(void) voiceChatService:(GKVoiceChatService *) voiceChatService

2 sendData:(NSData *) data

3 toParticipantID:(NSString *)participantID {

4

5 [currentSession sendData:data toPeers:

6 [NSArray arrayWithObject:participantID]

7 withDataMode:GKSendDataReliable error:nil];

8

9 }

10

其它连接的设备接收到发来的配置数据后,通过调用receivedData:fromParticipantID:方法启动语音聊天服务。

GKVoiceChatService使用两个设备之间交互的配置信息创建它自己的连接传输语音数据,还可以将microphoneMuted属性的值设为YES使麦克风静音。

1 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;

测试应用程序

在开始测试之前,先要把应用程序两台iPhone或iPod Touch上,对于iPod Touch,你需要使用一个外置麦克风,因为它默认是不带有麦克风的,一个好选择是Griffin iTalk Pro,如图3所示,它是iPod Touch麦克风及其零配件插入的基座,另外也支持苹果头戴式耳机及其配件。

图 3 Griffin iTalk Pro

应用程序部署到设备上后,启动应用程序,按下Connect按钮使用蓝牙相互连接,当两个设备连接好后,就可以开始聊天了,如果要临时静音,按下Mute按钮一直不放即可,放开Mute按钮后,声音就又恢复了。

在这篇文章中,你看到了如何使用Gamekit框架提供的GKVoiceChatService类在两个设备之间无缝地建立语音通信,关于两个设备之间的语音是如何传输的暂时没有必要知道,所有需要了解的就是要知道调用什么方法初始化语音聊天,另外你还要知道,语音聊天不仅可以通过蓝牙通信信道实现,在其它任何通信信道上都可以实现,实际上,如果使用TCP/IP连接两台设备,也可以实现语音聊天,在今后的文章中,我将会涉及。

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论