React Native receiving BLE notifications in background - android

I am currently working on a prototype trying to listen to bluetooth LE notification while in background mode.
I am using this library https://github.com/innoveit/react-native-ble-manager to interact with BLE devices. The idea is to be able to register to a BLE service on a peripheral and get notified on characteristic changes while in background.
const deviceId = '8A:B0:C3:BA:11:55';
const service = '0ce0';
const characteristic = '0ce2';
componentDidMount() {
BleManager.start({
showAlert: false
});
}
onButtonPress() {
BleManager.connect(deviceId).then(() => {
BleManager.retrieveServices(deviceId).then(() => {
BleManager.startNotification(deviceId, service, characteristic);
});
});
}
handleUpdateValueForCharacteristic(data) {
console.log('characteristic update', data);
}
this.handlerUpdate = bleManagerEmitter.addListener(
'BleManagerDidUpdateValueForCharacteristic',
this.handleUpdateValueForCharacteristic
);
From my understanding, with this code, every time the characteristic change on the BLE device, the app will get notified even in background mode and handleUpdateValueForCharacteristic will be triggered.
Is is possible to have multiple app listening to the same service and characteristic on the same BLE device?
Will all these work while background and sleep mode?

Related

I'm using mesibo android sdk to implement chat app but I have an issue with receiving voice call

when the app is totally closed, I don't receive calls, I don't know why
can any one help me ??
I'm using this code to setup mesibo :
Mesibo.getInstance().init(this)
Mesibo.addListener(this)
Mesibo.setRestartListener(this)
Mesibo.setSecureConnection(true)
Mesibo.setAccessToken(user?.mesiboToken)
val myProfile = UserProfile()
myProfile.name = user?.name
myProfile.address = user?.mesiboAddress
Mesibo.setDatabase("mydb", 0)
MesiboCall.getInstance().init(applicationContext)
Mesibo.setAppInForeground(this, 0, true)
Mesibo.start()
val profiles = Mesibo.getUserProfiles()
profiles.forEach { (key, profile) ->
val split = key.split("-")
if (!split.isNullOrEmpty()) {
val userProfile = UserProfile()
userProfile.name = split[0]
userProfile.address = key
Mesibo.setUserProfile(userProfile, false)
}
}
Mesibo.setPushToken(TokenManager.getInstance().getFCMToken())
also I have implement all Mesibo Call Listeners
Once the operating system suspends your app, it will not be able to
run and hence receive new messages or calls until it is activated
again. Hence, when your app has a new message or a new incoming call,
you need to wake up your app from the sleep state to deliver messages
and calls in real-time. This is where you need to send push
notifications. Push notification wakes up your app and moves it from
the sleep state to the active state. Once the app moves to the active
state, Mesibo will automatically connect and start receiving messages
and calls.
From https://mesibo.com/documentation/api/push-notifications/

Getting duplicate BLE notifications on Android

I'm developing a frame exchange sequence between an nRF52840 and an Android smartphone using the BLE protocol.
The first time I connect, everything works fine.
I activate the listening of BLE notifications by the Android smartphone with this method:
fun enableBleNotificationsOnCentral(currentBluetoothGatt: BluetoothGatt, serviceUUID: UUID, characteristicUUID: UUID) {
getMainDeviceService(currentBluetoothGatt, serviceUUID)?.let { service ->
val notificationConfiguration = service.getCharacteristic(characteristicUUID)
val result = currentBluetoothGatt.setCharacteristicNotification(notificationConfiguration, true)
println(result)
}
}
And I enable sending BLE notifications on the nRF52840 with this method:
fun enableBleNotificationsOnPeripheral(currentBluetoothGatt: BluetoothGatt, serviceUUID: UUID, characteristicUUID: UUID, descriptorUUID: UUID) {
getMainDeviceService(currentBluetoothGatt, serviceUUID)?.let { service ->
val descriptorConfiguration = service.getCharacteristic(characteristicUUID).getDescriptor(
descriptorUUID).apply {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
}
val result = currentBluetoothGatt.writeDescriptor(descriptorConfiguration)
println(result)
}
}
These methods are called each time my smartphone is connected to the nRF52840.
But if I disconnect and connect a second time, I receive each of the notifications in duplicate.
In addition, if I disconnect and connect a 3rd time, I receive each notification 3 times, and one more each time I reconnect.
I checked my code on the nRF52840 and it does not duplicate notifications.
Here is the method I call when I request a disconnection:
private fun disconnectFromCurrentDevice() {
currentBluetoothGatt?.disconnect()
BLECallbackManager.currentDevice = null
setUiMode(false)
}
I guess my problem is related to the fact that I don't disable the receipt of BLE notifications by my Android application when I disconnect but I'm not sure. And if that's where the problem comes from, when should I do it in the disconnect method? Can you help me?
I guess you're creating a new BluetoothGatt object for every new connection attempt, but you not destroy the previous one.
Try change disconnect() to close().

Xamarin background disconnected signalr

I am making an application in Xamarin Forms that uses the Signalr service to implement a chat. The chat works perfectly in the UWP version and in the Android emulator, so it does when I am debugging on my phone (Android), but when I disconnect the phone from the PC the chaos begins. The problem is that I think that when the application goes to the background, it disconnects from the Signalr server.
I have tried automatic reconnection and even changing the times of ServerTimeout and KeepAliveInterval. But I have not been successful. It should be noted that where I live additionally there are major connectivity problems, but still my theory is when the application goes to Background.
This is my code where I initialize my service (Im using a Singleton services).
hubConnection = new HubConnectionBuilder()
.WithUrl(URL, options =>
{
options.AccessTokenProvider = () => Task.FromResult(_myAccessToken);
})
.WithAutomaticReconnect()
//.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) })
//.WithAutomaticReconnect(new RandomRetryPolicy())
.Build();
This is my code to connect when the connection is closed
hubConnection.Closed += async (error) =>
{
OnConnectionClosed?.Invoke(this, new MessageEventArgs("Connection closed...",
string.Empty));
IsConnected = false;
await Task.Delay(new Random().Next(0, 5) * 1000);
try { await ReConnectAsync(); } catch (Exception ex) { Debug.WriteLine(ex); }
};
This is my code to connect
public async Task ReConnectAsync()
{
await ConnectAsync();
}
public async Task ConnectAsync()
{
if (IsConnected)
{
return;
}
Debug.WriteLine(hubConnection.State);
if (hubConnection.State== HubConnectionState.Disconnected)
{
await hubConnection.StartAsync();
//CancellationToken cancellationToken = new CancellationToken();
//await ConnectWithRetryAsync(hubConnection, cancellationToken);
}
IsConnected = true;
}
What else could I try to prevent it from disconnecting on Android or what will I be doing wrong in my code?
You won't be able to keep the SignalR connection alive on Android unless you have a Foreground Service running, which essentially keeps the App alive. This is how music apps etc. can keep functioning in the background.
A foreground service will also need to show a notification to the user that it is running.
Xamarin provides a nice little sample showing how to create a foreground service here https://github.com/xamarin/monodroid-samples/tree/master/ApplicationFundamentals/ServiceSamples/ForegroundServiceDemo
Essentially you create a Service:
[Service]
public class MyForegroundService : Service
{
}
Then you start it from your Activity with an Intent:
var intent = new Intent(this, typeof(MyForegroundService));
StartForegroundService(intent);
In your Service you will need to call StartForeground in a OnStartCommand override, otherwise the service will just get killed.
Question is though. Do you really need a foreground service and keep running SignalR in the background?
Have you thought about polling the back-end once in a while to fetch latest messages?
Have you thought about sending push notifications when the user receives a new message?
You will encounter a bigger limitation if you decide to target iOS as well. There it will be impossible for you to keep your SignalR connection alive.

Android BLE Device Button press Alert in android

I am working with BLE device.I perform the code using android GATT and it scan device and also I send immediate alert in BLE device from mobile using writeCharacteristic and BLE device is beep.But now I want to Alert in android Mobile when I press BLE device button. That exactly I don't know how to do.
Thank You.
For this you have to listen for characteristics change. When you will press the BLE button, a characteristics must be change inside its hardware (set any flag value depends on hardware's firmware coding). When characteristics changed, characteristics method will called. You can perform required functionality there.
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic)
{
Here we received ble button pressed event callback. Do stuff here.
}
For receiving characteristics change callback first you have to enable the notification like this.
BluetoothGattCharacteristic characteristic = gatt.getService(mServiceUuuid).getCharacteristic(mCharOneUuuid);
gatt.setCharacteristicNotification(characteristic, true);
List<BluetoothGattDescriptor> list = characteristic.getDescriptors();
for (int i = 0; i < list.size(); i++) {
BluetoothGattDescriptor desc = list.get(i);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
}

Making READ, WRITE and NOTIFY working on Android BLE (version 21 and above)

In my application, I got the READ and WRITE to work on specific BluetoothGattCharacteristic objects.
The BluetoothGattCallback onCharacteristicWrite and onCharacteristicRead are properly called.
I have then tried to setup the NOTIFY option so my Android app gets notified when a specific characteristic on the device changes.
I have set this up via the following code:
// Local notifications
mGatt.setCharacteristicNotification(statusTypeCharacteristic, notify);
// Remote notifications
BluetoothGattDescriptor desc = statusTypeCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
Log.d("Descriptor", desc.toString());
boolean test;
test = desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // return value = true
test = mGatt.writeDescriptor(desc); // return value = true
When the characteristic changes, the callback: onCharacteristicChanged is being called as expected
However, now all READ and WRITE operations do not work anymore.
When I comment the lines dealing with the descriptor, the READ and WRITE work again.
A part I am very unclear is around the UUID used to get the descriptor. Is it correct? Should I scan instead all descriptors from the characteristic and enable notification on one? How do I know which one to set as I have multiple ones coming back?
Ok, so I have figured out the issue.
At the beginning of my application, I am configuring (i.e. writing) to lots of descriptors.
2 issues with it:
1- A descriptor can only be written one at a time
2- No read/write operations can happen when a descriptor is being written to
The fix is to create a queue of write descriptor operations and perform the next descriptor write in the onDescriptorWrite callback.
private void writeGattDescriptor(BluetoothGattDescriptor d) {
//put the descriptor into the write queue
descriptorWriteQueue.add(d);
//if there is only 1 item in the queue, then write it. If more than 1, we handle asynchronously in the
// callback
if(descriptorWriteQueue.size() == 1) {
mGatt.writeDescriptor(d);
}
}
And then in the callback:
#Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
// Called when the descriptor is updated for notification
Log.d("onDescriptorWrite", descriptor.getUuid().toString());
// pop the item that we just finishing writing
descriptorWriteQueue.remove();
// if there is more to write, do it!
if(descriptorWriteQueue.size() > 0) {
mGatt.writeDescriptor(descriptorWriteQueue.element());
}
// Inform the framework that the scope has connected, configured and ready to process commands
if(descriptorWriteQueue.size() == 0) {
// Do something else, such as reads and writes
}
}

Categories

Resources