Question

I am working with External Accessory framework. I am encountering problems reestablishing EASession after app goes into background and then returns to foreground. If I terminate my app and relaunch, then Bluetooth connection is reestablished as one would expect. I suspect that there is some part of the teardown that I am missing - or which is not exposed (??).

[EAAccessoryManager sharedAccessoryManager] connectedAccessories]] is returning my connected accessory, and I am able to query it to get name, modelNumber, etc. However, the following line sets _session to nil.

_session = [[EASession alloc] initWithAccessory:_accessory forProtocol:_protocolString];

Is there any way to diagnosis the reason for failed EASession initialization?

Is there some mantra for clearing out old EASession?

This question is related to this one - but I am not asking for advice on which path to follow. I am asking why this path has this large pitfall and how to navigate around it.

Was it helpful?

Solution

I've found (in the post iOS4.1 world) that leaving the app (Backgrounding or quitting) will cause a DidDisconnectNotification to fire off. In the case of just hitting the power button or having the device sleep; we don't see the connection go down.

Now if the BT device goes out of range or goes to sleep itself. Then the connection goes down.

As a result, we no longer depend on anything but the ConnectionNotifications. We don't even trust the [[EAAccessoryManager sharedAccessoryManager] connectedAccessories] list because we've found it can sometimes contain 'ghost accessories' that will say they are connected and have streams that you can connect to and get write available events from even after the entire bluetooth system has gone down (BT icon off)

ConnectionNotifications are cached when you are in the background, so you should get a fresh state when you re-enter the app.

Of course on first entry; you want to make sure that you've set up all your listeners (etc) properly.

OTHER TIPS

As far as I can tell, there is no clearing out of old EASession instances. I can hypothesize, but I don't really know why this is. I suspect that the established EASession does not release its association with its accessory - and that this prevent subsequent EASession instances from being successfully associated with the same accessory.

I opted to leave EASession in tact when app resigns active. This seems to be working. In testing, I have connected to Bluetooth accessory, launched my app, accessed accessory, sent my app into background, disconnected/reconnected BT accessory, brought app to foreground and been able to access accessory again. This is as much as I could hope for.

One caveat: with iOS 4.0 it is possible to have more than one accessory. For example, a video cable and a Bluetooth device are both accessories.

I had the same problem and solved it with a little trick. I logged the serial number of the accessory when I opened a session and logged when I closed a session.

That's how I saw some sessions were not closed. So when my app go to background mode, I close definitely all the opened sessions by device.

-(void) closeSessionForDevice:(EAAccessory*) device{
EASession *lclSession = (EASession*) [sessionDictionary valueForKey:[device serialNumber]];
[[lclSession inputStream] close];
[[lclSession inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[lclSession inputStream] setDelegate:nil];

[[lclSession outputStream] close];
[[lclSession outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[lclSession outputStream] setDelegate:nil];

lclSession = nil;

NSLog(@"Session Closed for : %@", [device serialNumber]);

[device setDelegate:nil];
}

Hope it helps someone else.

I had the same problem. I was developing an application would open an External Bluetooth Accessory on a timed interval, read some data, then close the streams. This had been working fine for a few days, then suddenly one day it stopped working with this exact problem. A message was also logged to the console.

2015-06-20 23:54:43.371 MyApp[2083:404019] ERROR - opening session failed
1 2015-06-20 23:54:43.371 MyApp[2083:404019] ERROR - /SourceCache/ExternalAccessory/ExternalAccessory-288.20.7/       EASession.m:-[EASession dealloc] - 141 unable to close session for _accessory=0x174018750 and sessionID=65536

The Apple documentation is clear, only one instance of each protocol is allowed to be open at a time and any previous instance is automatically deallocated. But why all of a sudden was iOS failing to dealloc the previous EASession when it had been working fine for days.

I was perplexed and I spent three days hitting my head against the wall. I searched Google and ended up here, I read Apple's guides on communicating with external accessories and the NSStream programming guide. The code was all correct.

Finally on the third day I heard a beep from the corner of my desk, my Android phone was running out of juice. A light bulb went off in my head. I turned the phone off and viola, the problem on the iOS device went away.

This is really an RF problem, not a programming problem, but I include my story here incase anyone else runs into this problem, Google will bring you here. Turn off all other Bluetooth radios in the vicinity because they are sources of noise and can lead to this problem.

I was heaving the same problem. In my case, the session object, just after creation, has retainCount = 3, so one call [session release] was not enough when receiving DidDisconnectNotification. Be sure you really released the session object after received DidDisconnectNotification notification.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top