locked
UWP (Xamarin): Bluetooth RFComm Connection without Pairing - Possible? How? RRS feed

  • Question

  • Hello,

    I have the need to connect to a simple proprietary Bluetooth device that only supports simple RFComm serial interface (with no security). I want to be able to simply connect and start communicating with the device as soon as I see it (through enumeration) without needing to Pair to it. Everytime I try to get the Socket Reader/Writer though, Windows/UWP automagically pops-up a notification on the task bar that requires the user to go to the "Devices" settings screen and "Allow" the device, which then pairs it. Is there anyway to avoid this? Here is my code that I am trying:

    namespace EStopDeviceManagerXamarin.UI.UWP.Bluetooth
    {
        public class BluetoothConnection_UWP : BluetoothConnectionBase
        {
            private readonly string id;
    
            private BluetoothDevice bluetoothDevice;
            private DeviceAccessStatus accessStatus;
            private RfcommDeviceService serialService;
            private StreamSocket readerWriterSocket;
            private DataReader reader;
            private DataWriter writer;
    
            public BluetoothConnection_UWP(string id)
            {
                this.id = id;
            }
    
            public override async Task<bool> Connect()
            {
                if (!await VerifyAccess()) return false;
                if (!await ObtainDevice()) return false;
                if (!await ObtainSerialPortService()) return false;
                if (!await ObtainReaderWriter()) return false;
                return true;
            }
    
            private async Task<bool> VerifyAccess()
            {
                accessStatus = DeviceAccessInformation.CreateFromId(id)?.CurrentStatus ?? DeviceAccessStatus.Unspecified;
                for ( var i=0; i<120 && accessStatus != DeviceAccessStatus.Allowed; i++ )
                {
                    await Task.Delay(250);
                    accessStatus = DeviceAccessInformation.CreateFromId(id)?.CurrentStatus ?? DeviceAccessStatus.Unspecified;
                }
    
                if (accessStatus == DeviceAccessStatus.DeniedByUser)
                {
                    Error = "Unable access to connect to the remote device (grant access in Settings > Privacy > Other Devices)";
                    Connected = false;
                    return false;
                }
                else if (accessStatus != DeviceAccessStatus.Allowed)
                {
                    Error = "Device not present or access denied by the system";
                    Connected = false;
                    return false;
                }
    
                return true;
            }
    
            private async Task<bool> ObtainDevice()
            {
                try
                {
                    bluetoothDevice = await BluetoothDevice.FromIdAsync(id);
                    if (bluetoothDevice == null)
                    {
                        Error = $"Bluetooth Device returned null. Access Status = {accessStatus}";
                        Connected = false;
                        return false;
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    Error = $"Unable to acquire bluetooth device: {ex.Message}";
                    Connected = false;
                    return false;
                }
            }
    
            private async Task<bool> ObtainSerialPortService()
            {
                try
                {
                    var services = await bluetoothDevice.GetRfcommServicesForIdAsync(RfcommServiceId.SerialPort, BluetoothCacheMode.Uncached);
                    if (services.Services.Count > 0)
                    {
                        serialService = services.Services[0];
                        return true;
                    }
                    Error = "Could not discover the serial communication service on the remote device";
                }
                catch (Exception ex)
                {
                    Error = $"Could not discover the serial communication service on the remote device: {ex.Message}";
                }
    
                Connected = false;
                return false;
            }
    
            private async Task<bool> ObtainReaderWriter()
            {
                readerWriterSocket = new StreamSocket();
    
                try
                {
                    await readerWriterSocket.ConnectAsync(serialService.ConnectionHostName, serialService.ConnectionServiceName);
                    writer = new DataWriter(readerWriterSocket.OutputStream);
                    reader = new DataReader(readerWriterSocket.InputStream);
                    Connected = true;
                    return true;
                }
                catch (Exception ex) when ((uint)ex.HResult == 0x80070490) // ERROR_ELEMENT_NOT_FOUND
                {
                    Error = "Please verify that you are running the Device chosen is a Laird PSD or MSD.";
                }
                catch (Exception ex) when ((uint)ex.HResult == 0x80072740) // WSAEADDRINUSE
                {
                    Error = "Please verify that there is no other RFCOMM connection to the same device.";
                }
                catch (Exception ex)
                {
                    Error = $"Unable to open device for reading/writing: {ex.Message}";
                }
    
                Connected = false;
                return false;
            }
    
        }
    }
    

    And here is a unit test exercising it:

            [TestMethod]
            public void Connect_Test()
            {
                // Arrange
                IBluetoothConnection btc = new BluetoothConnection_UWP(TEST_PSD_ID);
    
                // Act
                var actualConnectedTask = btc.Connect();
                actualConnectedTask.Wait();
                var actualConnected = actualConnectedTask.Result;
    
                // Assert
                Assert.IsTrue(actualConnected, $"Connection Failed: Error - {btc.Error}");
            }

    What happens is that UWP/Windows pops-up the notification at this line:

     var services = await bluetoothDevice.GetRfcommServicesForIdAsync(RfcommServiceId.SerialPort, BluetoothCacheMode.Uncached);
    

    Is there any way to get this kind of connection without having UWP/Windows force "Pairing"? I keep reading multiple references to it being possible, but, I can't seem to find how to do it in the documentation.

    Any assistance or guidance would be greatly appreciated. Thanks in advance!

    Tuesday, July 31, 2018 4:44 PM

All replies

  • Hi,

    For questions about Xamarin, it is out of scope of this forum. I suggest that you might need to ask about this in the official forum of Xamarin.

    Sorry for any inconvenience。

    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 1, 2018 2:02 AM
  • This was actually a UWP question. Xamarin is only tangentially related. This was posted to the UWP topic of this forum, no?
    Thursday, August 2, 2018 6:15 PM
  • I do not understand why you are calling a question about UWP development on the UWP forum, "Off-Topic". Did you even read the post or did you just blindly see that I mentioned (Xamarin) in parenthesis? Xamarin actually has nothing to do with the code in question. It's all about UWP.
    Thursday, August 2, 2018 6:20 PM