Not able to discover CBServices I am advertising - ios

I am creating a custom CBService and adding them to the CBPeripheralManager. I am advertising the service along with the Advertisement data. But I am not able to see the service I created in the Light Blue app. The Light Blue app shows two services which I don't know what they are and I didn't add those. The advertisement data is shown but not the service. Below is my implementation of creating a service and advertising it in Xamarin:
void AdvertiseData()
{
var uui = new CBUUID[] { CBUUID.FromString("E20A39F4-73F5-4BC4-A12F-17D1AD07A961") };
var nsArray = NSArray.FromObjects(uui);
var nsObject = NSObject.FromObject(nsArray);
var manufacturerDataBytes = new byte[6] { 5, 255, 76, 0, 25, 35 };
var advertisementData = new NSDictionary(
CBAdvertisement.DataLocalNameKey, "id1",
CBAdvertisement.DataServiceUUIDsKey, nsObject,
CBAdvertisement.DataManufacturerDataKey, NSData.FromArray(manufacturerDataBytes));
try
{
var newService = new CBMutableService(CBUUID.FromString("1F3A8B1E-4BAA-45DA-B3A4-7A19DDC86305"), false);//1F3A8B1E-4BAA-45DA-B3A4-7A19DDC86305
newService.Characteristics = new CBCharacteristic[]
{
new CBMutableCharacteristic(CBUUID.FromString("906377DD-F782-448C-9A65-796B48E10894"),//906377DD-F782-448C-9A65-796B48E10894
CBCharacteristicProperties.Read, "FooChar",
CBAttributePermissions.Readable),
new CBMutableCharacteristic(CBUUID.FromString("2B77EC99-BE87-45D3-863C-599D5202E4C0"),//2B77EC99-BE87-45D3-863C-599D5202E4C0
CBCharacteristicProperties.Write, null,
CBAttributePermissions.Writeable)
};
cbPeriphMang.AddService(newService);
//cbPeriphMang.RemoveAllServices();
}
catch(Exception ex)
{
}
if (cbPeriphMang.Advertising) cbPeriphMang.StopAdvertising();
cbPeriphMang.StartAdvertising(new StartAdvertisingOptions(){LocalName="alpha", ServicesUUID = new CBUUID[] { CBUUID.FromString("1F3A8B1E-4BAA-45DA-B3A4-7A19DDC86305")} } );
}

I assume you are running the LightBlue app on another iOS device. In my experience iOS caches a lot of BLE data including services and characteristics. If the peripheral changes any service or characters (or adds or deletes) then iOS will not see those changes until you restart bluetooth on the iOS device where LightBlue is running. In some cases all I need to do is turn bluetooth off/on but in other cases I had to restart the device completely. If you scan the Apple developer forums you will find other people reporting the same problem and same workaround.

Related

IOS 13 doesn't play a notification sound using FirebasePushNotificationPlugin

I use Firebase to push notifications to the users at a certain time. They receive the notification but no alert sound is played. In the settings, the allow sound/notifications are turned on and other IOS13 and other apps play sound.
Version Number of FirebasePushNotificationPlugin Plugin: 3.3.10
Device Tested On: iphone X, OS: 13.4.1
Simulator Tested On: N/A (simulators don't receive notifications)
Version of VS: VS for Mac Community, 8.6.6 (build 11)
Version of Xamarin: Xamarin.IOS 13.18.2.1, Xamarin.Forms v4.6.0.847
AppDelegate.cs:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
bool fbaseStarted = false;
try
{
// This method does all the UNUserNotificationCenter.Current.RequestAuthorization() code so we don't have to.
FirebasePushNotificationManager.Initialize(options, true);
fbaseStarted = true;
}
catch
{ }
LoadApplication(new App());
if (!fbaseStarted)
{
try
{
FirebasePushNotificationManager.Initialize(options, true);
}
catch { }
}
FirebasePushNotificationManager.CurrentNotificationPresentationOption = UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound;
}
Within one of the pages of my code, I subscribe a list of tags (please note that I unsubscribe because the first time the code runs it fails silently if the notifications aren't approved - resulting in the model thinking the notifications was subscribed when it wasn't):
CrossFirebasePushNotification.Current.UnsubscribeAll();
CrossFirebasePushNotification.Current.Subscribe(Constants.NotificationTagsArray);
I keep coming across payload json solutions but unless I am wrong, I don't think that applies to me as I am using Xamarin and the FirebasePushNotificationPlugin. Is there any additional permissions that were added in ios 13 for playing notifications with sound that I have missed?
I have also posted here: https://github.com/CrossGeeks/FirebasePushNotificationPlugin/issues/348 but nobody has been able to assist me yet.
Thanks
The issue actually lies with the sending of the notifications nothing to do with the Xamarin App. The issue resided in the services that sends the notifications to firebase (to then be sent out to the phones).
In the service we were sending a FirebaseNet.Messaging.Message() to the phones:
Message FireBasemessage = new Message()
{
To = "/topics/" + PushNote.Tag,
TimeToLive = 86400,
Priority = MessagePriority.high,
ContentAvailable = true,
Notification = new AndroidNotification()
{
Tag = "/topics/" + PushNote.Tag,
Body = enhancedMessage,
Title = xtitle,
}
,
Data = new Dictionary<string, string>
{
{ "param", PushNote.Tag },
{ "text", enhancedMessage}
}
};
In the AndroidNotification() object required Sound = "default" to be added for it to work. Please note that this works for both Android and IOS notifications despite the fact it is an AndroidNotification object.

BLE WroteCharacteristicValue never calls

I am writing an iOS application with Xamarin.iOS, but an answer in native iOS would be appreciated as well. My application uses a BLE write characteristic to send messages between devices. My code to create and add the service to the CBPeripheralManager:
_cbPeripheralManager.WriteRequestsReceived += WriteRequestReceived; // WriteRequestReceived is never called
// my read characteristic actually works fine
_readCharacteristic = new CBMutableCharacteristic(CBUUID.FromString(MyReadCharacteristicUuid), CBCharacteristicProperties.Read | CBCharacteristicProperties.Notify, null, CBAttributePermissions.Readable);
// but my write characteristic doesn't work when i try to write to it
_writeCharacteristic = new CBMutableCharacteristic(CBUUID.FromString(MyWriteCharacteristicUuid), CBCharacteristicProperties.Write | CBCharacteristicProperties.Notify, null, CBAttributePermissions.Writeable);
_service = new CBMutableService(CBUUID.FromString(MyServiceUuid), true);
_service.Characteristics = new CBCharacteristic[2] { _readCharacteristic, _writeCharacteristic };
_cbPeripheralManager.AddService(_service);
And my code to write to the characteristic of the peripheral (not showing the code for device and service/characteristic discovery for simplicity)
peripheral.WroteCharacteristicValue += handler; // handler is never called
peripheral.WriteValue(NSData.FromString("hello"), characteristic, CBCharacteristicWriteType.WithoutResponse);
Any idea what the problem could be?

Beacons array is empty in didRangeBeaconsInRegion event in ionic ios app

im using ionic native ibeacon library to detect beacons.I can detect beacons with android but when I try in ios ,i always see an empty beacon array.
I tried these things ,but still cant see the beacons in ios (device is iphone 6s plus 11.4.1) (bluetooth service is enabled on device)
I tried both requestWhenInUseAuthorization and also
requestAlwaysAuthorization.
I add NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription key in info.plist
my code is like this, its working on android device
import { Injectable } from '#angular/core';
import { Platform, Events } from 'ionic-angular';
import { IBeacon } from "#ionic-native/ibeacon";
#Injectable()
export class BeaconProvider {
delegate: any;
region: any;
constructor(
public platform: Platform,
public events: Events,
private iBeacon: IBeacon
) {
this.initialise();
}
initialise(): any {
let promise = new Promise((resolve, reject) => {
if (this.platform.is("cordova")) {
this.iBeacon.requestAlwaysAuthorization();
// ALSO try this one too this.iBeacon.requestWhenInUseAuthorization();
this.delegate = this.iBeacon.Delegate();
this.delegate.didRangeBeaconsInRegion().subscribe(
data => {
this.events.publish("didRangeBeaconsInRegion", data);
//console.log("didRangebeacons__" + JSON.stringify(data)); // empty beacons array
},
error => console.error()
);
this.region = this.iBeacon.BeaconRegion("deskBeacon", "e2c56db5-dffb-48d2-b060-d0f5a71096e0");
this.iBeacon
.startRangingBeaconsInRegion(this.region)
.then(
() => {
resolve(true);
},
error => {
console.error("Failed to begin monitoring: ", error);
resolve(false);
}
);
} else {
resolve(false);
}
});
return promise;
}
}
EDIT
My location services are on ,and I'm using same uuid in ios or android (ionic,same code).By the way I tried to make a iphone as beacon transmitter by an app in market,other iphone can see it as beacon.
And here is the screenshot of beacon scope app
A few things to check on iOS:
Go to settings, location, and check if your app has been granted location permission.
Make sure Bluetooth is turned on
Try a 3rd party beacon scanner like Locate Beacon, configure it with your UUID and make sure it can detect your beacon with the same device.
EDIT: A few more steps
Make sure iOS has Location turned on in Settings (the overall setting, not just for your app) Settings -> Privacy -> Location Services
Since you can detect on Android but not iOS, double check the UUID that you see on Android and make sure it matches exactly what you enter on iOS.
If the UUID in the config matches, but it still won't detect, verify that the beacon is actually sending out an iBeacon frame and not AltBeacon or some format iPhone won't see by default. If you use the Beacon Scope app for Android, it will tell you the frame type.

Use Bloothtooth LE while app is in background

I am building an iOS app with Xamarin, with this BLE plugin:
https://github.com/aritchie/bluetoothle
I'm just broadcasting a UUID via BLE, and it works. Here is my code:
var data = new Plugin.BluetoothLE.Server.AdvertisementData
{
LocalName = "MyServer",
};
data.ServiceUuids.Add(new Guid("MY_UUID_HERE"));
await this.server.Start(data);
The only problem is that it stops broadcasting once I put the app in the background. And resumes again when I open the app again.
How can I let it continue to broadcast once it's in the background? I read the documentation here:
https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
And it says that I have to use the CBCentralManager class to obtain the preservation and restoration feature (so I can keep broadcasting the UUID at all times), but I'm having a hard time translating this to Xamarin/C#.
EDIT
After researching some more, I read that I need to create an instance of CBCentralManager and implement WillRestoreState in the delegate. I did this in the AppDelegate:
[Register("AppDelegate")]
public class AppDelegate : MvxApplicationDelegate, ICBCentralManagerDelegate
{
private IGattServer server = CrossBleAdapter.Current.CreateGattServer();
private CBCentralManager cbCentralManager;
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// irrelevant code...
this.Ble();
return true;
}
private async Task Ble()
{
try
{
await Task.Delay(5000); // wait for it to finish initializing so I can access BLE (it crashes otherwise)
var options = new CBCentralInitOptions();
options.RestoreIdentifier = "myRestoreIndentifier";
this.cbCentralManager = new CBCentralManager(this,null,options);
var data = new Plugin.BluetoothLE.Server.AdvertisementData
{
LocalName = "MyServer",
};
data.ServiceUuids.Add(new Guid("MY_UUID_HERE"));
await this.server.Start(data);
}
catch (Exception e)
{
}
}
public void UpdatedState(CBCentralManager central)
{
//throw new NotImplementedException();
}
[Export("centralManager:willRestoreState:")]
public void WillRestoreState(CBCentralManager central, NSDictionary dict)
{
//never gets called
}
But it didn't make a difference for me. And the WillRestoreState method never gets called... I don't mind using a different plugin/library if I have to at this point...
EDIT 2
I just realized that the app is still broadcasting while it is in the background, I just don't see the service UUID anymore (in the web portal of the beacon that I'm testing with), I only see the phone's identifier.
After doing tons of research, I found that it is simply an iOS restriction - you can not broadcast the UUID of a BLE service while your app is in the background. Background work is very restrictive in iOS.
EDIT to include Paulw11 comment (which is true):
You can advertise a service, but it is advertised in a way that only another iOS device that is specifically scanning for that service UUID can see.
Although you can not broadcast the UUID of a BLE service while your iOS app is in the background, for anyone trying to do something similar, you should look into iBeacon. It's Apple's protocol for letting iOS apps do bluetooth stuff while it's in the background.

Xamarin.iOS CoreBluetooth/External Accesory issue

I've looking here on Forums, on the monotouch samples GIT hub, and never found a really functional sample to use CoreBluetooth in order to achieve the following:
1.Check if is there a device that match a criteria(by name or some identifier of the device) paired and connected
2.If paired but not connected, try connect to it
3.If connection fails, then show a list of the bluetooth devices that matches the criterias on topic 1 so the user can select and connect to it
Note: The device I'm trying to connect uses SPP but is Apple MFi certified. It is a credit card reader over bluetooth and some of then even implement ExternalAccessory protocols
The CoreBluetooth samples page is empty http://developer.xamarin.com/samples/ios/CoreBluetooth/
I've trying this pretty simple sample that never get the events called after the scan:
public static class BTHelper
{
private static CBCentralManager manager;
private static CBUUID UUID;
static BTHelper()
{
manager =
manager.DiscoveredPeripheral += OnDiscovery;
manager.ConnectedPeripheral += OnConnected;
manager.DisconnectedPeripheral += OnDisconnected;
UUID = CBUUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
}
public static void CheckBluetooth()
{
manager.ScanForPeripherals(new[] { UUID });
}
static void OnDisconnected(object sender, CBPeripheralErrorEventArgs e)
{
Console.WriteLine("Disconnected - " + e.Peripheral.Name);
}
static void OnConnected(object sender, CBPeripheralEventArgs e)
{
Console.WriteLine("Connected - " + e.Peripheral.Name);
}
static void OnDiscovery(object sender, CBDiscoveredPeripheralEventArgs e)
{
Console.WriteLine("Found - " + e.Peripheral.Name);
}
}
Can anyone help? I've being really tired of googling and looking of many questions on SO with no real answer.
#XamarinTeam, you guys should provide a sample on how to use it... We are lost without reference...
Thank, really appreciate any help...
Gutemberg
It seems like you are looking at wrong documents.Core Bluetooth only allows you to communicate with Bluetooth Low Energy (BLE) devices using the GATT profile. you can not scan SPP device with corebluetooth.
For your MFI device, you need to check External Accessory framework , It allows communication with 'legacy' Bluetooth devices using profiles such as the Serial Port Protocol (SPP).
To answer your question:
: 1.Check if is there a device that match a criteria(by name or some identifier of the device) paired and connected
You can use showBluetoothAccessoryPicker function of EAAccessoryManager to get list of Available devices, read more here
2.If paired but not connected, try connect to it
There is not any documented way to check for this. You can not initiate connect from app without showBluetoothAccessoryPicker . You can monitor for
EAAccessoryDidConnect notification. if this method is not called, and showbluetoothaccessorypicker 's complition get called, your device is not connected.
3.If connection fails, then show a list of the bluetooth devices that matches the criterias on topic 1 so the user can select and connect to it
1)
After completion of showbluetoothaccessorypicker You can check in ConnectedAccessories . If its not avaiable, call showbluetoothaccessorypicker to display list of accessories.
Sample code for using External Accessory framework in your code
EAAccessoryManager manager= EAAccessoryManager.SharedAccessoryManager;
var allaccessorries= manager.ConnectedAccessories;
foreach(var accessory in allaccessorries)
{
yourlable.Text = "find accessory";
Console.WriteLine(accessory.ToString());
Console.WriteLine(accessory.Name);
var protocol = "com.Yourprotocol.name";
if(accessory.ProtocolStrings.Where(s => s == protocol).Any())
{
yourlable.Text = "Accessory found";
//start session
var session = new EASession(accessory, protocol);
var outputStream = session.OutputStream;
outputStream.Delegate = new MyOutputStreamDelegate(yourlable);
outputStream.Schedule(NSRunLoop.Current, "kCFRunLoopDefaultMode");
outputStream.Open();
}
}
and
public class MyOutputStreamDelegate : NSStreamDelegate
{
UILabel label;
bool hasWritten = false;
public MyOutputStreamDelegate(UILabel label)
{
this.label = label;
}
public override void HandleEvent(NSStream theStream, NSStreamEvent streamEvent)
{
//write code to handle stream.
}
}
There is not any perticular demo for using Exeternal Accessory framework,
but You can check this sample code for understanding how it works.:
Whole Project
AccessoryBrowser class

Resources