GKSession - what if I have Bluetooth and Wi-Fi turned off?
Asked Answered
T

6

11

I'm working on an iPhone app that will allow for peer-to-peer connections. From what I understand, I have the choice between using GKPeerPicker or the GKSession. I don't like the idea of using the PeerPicker because I want to show a custom interface, so I decided to go with GKSession, and hey, BONUS is that it also works over Wi-Fi, whereas the Peer Picker does not.

OK, so problem is... what if the user has both Bluetooth and Wi-Fi turned off? In the Peer Picker, there is a prompt to turn Bluetooth on w/o leaving the app. GKSession doesn't have it... but woah wait a second, it appears that I can't even check to see if Bluetooth is on or not programatically!

Carpe Cocoa claims no problem, just use the Delegate's session:didFailWithError: method. But, as it explains in the comments... that doesn't seem to work anymore! And in my experience, I concur.

Is there some other way to programmatically check if Bluetooth is on? Is this something that I should be leveraging Reachability for? Or is it just a bug that Apple has yet to fix?

To be more specific, I'm creating my session like this:

GKSession *aSession = [[GKSession alloc] initWithSessionID:nil
                                                  displayName:user.displayName 
                                                  sessionMode:GKSessionModePeer];

self.gkSession = aSession;
[aSession release];

self.gkSession.delegate = self;
self.gkSession.available = YES;

[self.gkSession setDataReceiveHandler:self withContext:NULL];

The class implements the GKSessionDelegate, and I know that it's working because when I have bluetooth turned on, the delegate methods are called no problem. I've implemented them as such:

#pragma mark -
#pragma mark GKSessionDelegate methods

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
     if (GKPeerStateAvailable == state) {
          [session connectToPeer:peerID withTimeout:10];
     } else if (GKPeerStateConnected == state) {
          // gets user

          NSError *error = nil;
          [session sendData:user.connectionData
                      toPeers:[NSArray arrayWithObjects:peerID,nil]
                withDataMode:GKSendDataReliable error:&error];
          if (error)
               NSLog(@"%@",error);
     }
}



- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID {
     NSError *error = nil;
     [session acceptConnectionFromPeer:peerID error:&error];
     if (error)
          NSLog(@"%@",error);
}

- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error {
     NSLog(@"%@",error);
}

- (void)session:(GKSession *)session didFailWithError:(NSError *)error {
     NSLog(@"%@",error);
}

None of the log statements are printed and I set breakpoints in each method, but none of them are hit when the user has both Bluetooth and Wi-Fi turned off. I was hoping that something would happen to trigger session:didFailWithError: so that I could prompt the user to turn on Bluetooth or connect to a Wi-Fi network.

Tieshatieup answered 20/2, 2010 at 23:36 Comment(1)
Sounds like a bug or possibly an enhancement request. You should file a radar.Phloem
T
2

Now in iOS 5, this can be achieved like so:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
NSMutableArray * discoveredPeripherals = [NSMutableArray new];
CBCentralManager * manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[manager scanForPeripheralsWithServices:discoveredPeripherals options:options];
[manager stopScan];

This requires that you import the CoreBluetooth framework in iOS 5. If bluetooth is off, the system will pop up an alert view which will offer the choice to turn bluetooth on. Otherwise, if it finds a peripheral it will call a corresponding delegate method, but if there is nothing in that implementation you don't need to worry about it.

Thun answered 10/8, 2012 at 19:16 Comment(0)
P
1

I agree with Martin Gordon, but a workaround might be to use Apple's reachability.

Preponderant answered 2/3, 2010 at 14:35 Comment(0)
S
1

Interesting point, have you tried testing it with Bluetooth OFF and the WiFi ON? I found out recently that although my program was calling this 'Bluetooth Unavailable' message, it wasn't in fact using Bluetooth AT ALL but was connecting over my WiFi network. I don't know of a way to force GKSession into a Bluetooth connection without using Apple's PeerPicker object, but the PeerPicker object does allow for people to make their own interfaces. What it doesn't seem to allow is connection types other than Peer, so if you want a Client/Server arrangement it's not going to be much help.

-Ash

Stylopodium answered 7/10, 2010 at 11:1 Comment(0)
A
0

You can switch on Blutooth programmatically, by using Apple's private API (i think BluetoothManger.h), but be careful , it will cause rejection in the Apple App Store push.

Ambit answered 10/8, 2011 at 7:16 Comment(0)
C
0

I second the notion of using Apple's reachability. As a bonus it's listed as one of the Apple App Store submission guidelines.

It's not that hard to implement either as much of the code needed is already written for you.

Slf provided a link to some source code using the Reachability class, additionally here's a link to Apple Dev's official reachability example.

However, make sure you are checking for connectability asynchronously.

I'm using it in my app and although it isn't the best solution at least it notifies the user that he/she needs to adjust the connection settings or that no networks exist.

Carven answered 21/9, 2011 at 18:44 Comment(0)
D
-1

You should use the same sessionID.

Devonian answered 18/8, 2011 at 12:3 Comment(1)
What do you mean by this? Why?Solicitor

© 2022 - 2024 — McMap. All rights reserved.