Search code examples
ios8bluetoothxamarinxamarin.iosios9

NSInputStream never HasBytesAvailable on iOS9 (classic Bluetooth)


I have a cross platform (Xamrin) app that does some classic Bluetooth communication and is working absolutely fine on iOS8. However, after re-building and running it on iOS9 I can't get the NSInputStream to ever have "HasBytesAvailable"= true. Note: I followed all the instructions from Xamarin's website.

I tried both assigning a delegate to the InputStream and waiting on the NSRunLoop but the stream never seems to have bytes available. The event only fires (on iOS9) when the Input stream is opened (on iOS8 it fires as expected).

Here is a snippet of the code that does the reading successfully on iOS8 (delegate method):

EAsession.InputStream.Delegate = new Foo();    
EAsession.InputStream.Schedule(NSRunLoop.Current,NSRunLoop.NSDefaultRunLoopMode);
    EAsession.InputStream.Open();           
    (NSRunLoop.Current).RunUntil(NSDate.FromTimeIntervalSinceNow(2));

Where Foo is a class that implements: NSObject, INSStreamDelegate

    public class Foo :NSObject, INSStreamDelegate
{
    [Export("stream:handleEvent:")]
    public void HandleEvent(Foundation.NSStream theStream, Foundation.NSStreamEvent streamEvent)
    {
      //Code to read bytes here
    }

To make sure there really are bytes sent to the iPhone5 I modified the external Bluetooth device to just echo any bytes received.

Using either method (delegate or waiting on NSRunLoop) on iOS8, the echo arrives immediately. However when I change the target device to the iOS9 I can wait forever and HasBytesAvailable would always be false.

I even tried reading regardless of HasBytesAvailable being false, but nothing is being read (no big surprise there I guess).

Moreover, I tried building using both Xcode6.4 and Xcode 7 with same result.

At the moment I am out of ideas so any help would be greatly appreciated!

Thanks in advance!

EDIT:

I contacted Xamarin and I am writing a test app for them to test whether it is an Apple issue or Xamarin issue.

Also, see the comment in this link about Bluetooth... perhaps related?


Solution

  • So I finally solved it,

    I am not entirely sure what was the problem eventually as I did a few things:

    1. Update to Xamarin beta stream ( 5.9.7 build 12).
    2. Update to the latest iOS (9.0.2)
    3. Use Xcode 7.0
    4. And change where I called the delegate, open stream and schedule.

    The change to the code was that instead of handling the opening, scheduling and delegate assignment in the receiving and sending methods separately, I did it at the same place. Namely, when creating the EASession I assigned all of the above like so:

            s = new EASession(device, protocol);
            output_stream = s.OutputStream;
            input_stream = s.InputStream;
    
            output_stream.Delegate=this;
            output_stream.Schedule(NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);
            output_stream.Open();
    
            input_stream.Delegate = this;
            input_stream.Schedule(NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);
            input_stream.Open();
    

    At the moment I am not unscheduling the input and output streams and I am not sure it this is the right thing to do. I'll try and keep this updated as I move from working to a nice looking code that works...

    Unlike what Bluecode describes I definitely needed to use my input stream and I was always opening it; so I am not sure if it was the same problem. I am still unsure what was the solution to the problem as it can be either one or a combination of the above. I might experiment a bit more into this later on when I have more time to see which one was the single solution? If any.

    Hope this helps any. Cheers