Scan for Ble Devices and Present Them in an UItableview

Scan for BLE devices and present them in an UITableView

Like @paulw11 said, I had to creat a delegate protocol:

protocol BluetoothDelegate: class {

func ReloadView()
}

This 'ReloadView' method is declared in my ScanTableView class:

func ReloadView() {
scanTableView.reloadData()
}

Now, I had to do some additional:

  1. Add the BluetoothDelegate to ScanTableView class
  2. Declare a variable 'weak var delegate: BluetoothDelegate?' in BluetoothManager class
  3. call the delegate method with 'delegate?.ReloadView()' at the wished point in BluetoothManager class
  4. Activate the delegate in ScanTableView by using 'bluetoothManager?.delegate = self'

That's it!

How to show found device list on tableview using Bluetooth LE iOS

For now it shown found list on uitableview but I can not select device to connect. Can you show me? thanks

You should implement one more central manager delegate's method:

centralManager:didConnectPeripheral:error

Inside it you should pass self to peripheral's delegate

peripheral.delegate = self;

At this moment you didn't discovered peripheral service nor characteristics. You should explicitly tell that you want to retrieve all services that peripheral has :

[peripheral discoverServices:nil];

After that CoreBluetooth invokes CBPeripheral delegate method :

peripheral:didDiscoverServices:

At that moment you have all services on peripheral that can be accessed via services property:

peripheral.services

Next step - discover services characteristics:

for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil
forService:service];
}

Again you need to implement CBPeripheral method from protocol:

peripheral:didDiscoverCharacteristicsForService:error:

That can be accessed via

service.characteristics

Now you can read/write/setNotify on them.
But for reading/writing/notifying you should implement corresponding CBPeripheralManager protocol methods:

peripheralManager:didReceiveReadRequest:
peripheralManager:didReceiveWriteRequests:
peripheralManager:central:didSubscribeToCharacteristic:

All of that described in documentation:
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/AboutCoreBluetooth/Introduction.html

IOS Bluetooth LE Scanning Devices not adding to the uitableview

There is a lot of code here, but generally it looks OK. Two things do stand out however. Your numberOfSectionsInTableView is returning 0 - so there will be no content in your table. You should have -

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}

I suggest that you just store the CBPeripheral in your data array.

Also, once you discover a peripheral and add it to your array you should inform the table view that the data source has been updated (This code assumes you have property tableView that holds a reference to your tableview ) -

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {

NSLog(@"Discovered %@ at %@", peripheral.name, RSSI);

if (![_foundPeripherals containsObject:peripheral]) {
[_foundPeripherals addObject:myDevice ] ;

[self.tableView reloadData]; // Tell the tableview that the data source has changed
}

}

Then your cellForRowAtIndexPath becomes -

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath];

if (cell == nil) {
        cell =  [ [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"reuseIdentifier"] ;

        cell.selectionStyle = UITableViewCellSelectionStyleGray;
    }

CBPeripheral *peripheral=[_foundPeripherals objectAtIndex:indexPath.row];

    cell.textLabel.text = peripheral.name;
    // Configure the cell...

    return cell;
}

To connect to the peripheral when the table row is selected -

- (void)tableView: (UITableView *)tableView
didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{

[self performSegueWithIdentifier:@"connectSegue" sender:[_foundPeripherals objectAtIndex:indexPath.row]]; // This is a segue to your BTSentCommandViewController
}

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
BTSentCommandViewController* sliderVC=( BTSentCommandViewController *)segue.destinationViewController;
sliderVC.centralManager=_centralManager;
sliderVC.periperhal=_sender;

}

In your BTSentCommandViewController you can connect to the peripheral. You should also set the BTSentCommandViewController instance as the peripherals delegate and implement all of the CBPeripheralDelegate methods there

Bluetooth Scan throwing ArgumentOutOfRangeException in Xamarin.iOS

So it turns out that the BLE scan, which runs continuously, was producing a race condition where an item was being removed at the same time that the list was being updated with removed devices.

Invoking on main thread and adding a lock to the property seems to keep that exception from throwing:

        private object _deviceListLock = new object();
public ObservableRangeCollection<DeviceListItemViewModel> Devices { get; set; } = new ObservableRangeCollection<DeviceListItemViewModel>();

private void OnDeviceAdded(BleDevice device)
{
InvokeOnMainThread(() =>
{
lock (_deviceListLock)
{
Devices.Add(new DeviceListItemViewModel(device));
}
});
}

private void OnDeviceUpdated(BleDevice device)
{
InvokeOnMainThread(() =>
{
lock (_deviceListLock)
{
Devices.ReplaceRange(Devices.OrderByDescending(x => x.Rssi).ToList());
}
});
}

private void OnDeviceExpired(BleDevice device)
{
InvokeOnMainThread(() =>
{
lock (_deviceListLock)
{
var vm = Devices.FirstOrDefault(d => d.Id == device.Id);
Devices.Remove(vm);
}
});
}

Why this is necessary on iOS, but not on Android, I'm not entirely sure.



Related Topics



Leave a reply



Submit