Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scanning in background task. #529

Closed
3 tasks done
njdullea opened this issue Sep 3, 2019 · 17 comments
Closed
3 tasks done

Scanning in background task. #529

njdullea opened this issue Sep 3, 2019 · 17 comments
Labels
bug pending Issues that are planned to be worked on at some point in the future

Comments

@njdullea
Copy link

njdullea commented Sep 3, 2019

Prerequisites

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Expected Behavior

I am using react-native-background-fetch to execute a task when the app is in the background. In that task, I should be able to scan for devices.

Current Behavior

I am able to connect, speak with devices, and do anything except for scan for peripherals in the background task I configured. After searching through these issues, I found a related issue here. To confirm that I have all the correct advertised services, in the foreground process I do this:

const my_service  = 'c7fcee6f-e7e0-8c8a-b745-fde27c268efd';
manager.startDeviceScan([my_service], {allowDuplicates: true}, (error, device) => {
            if (error) {
                console.log("Error in device scan: ", JSON.stringify(error));
            }

            if (device) {
                 console.log("DEVICE UUIDS: ", device.serviceUUIDs);
            }
        });

In the console this log is printed:

'DEVICE UUIDS: ', [ '00001805-0000-1000-8000-00805f9b34fb',
  'c7fcee6f-e7e0-8c8a-b745-fde27c268efd' ]

Then in the background task, I perform the scanning process with those exact uuids, but without finding any devices this time.

NOTE: the service '00001805...' is the bluetooth current time service. The service id is really just '1805' or '0x1805' but i'm unsure whats the proper way to scan for a service with an assigned number by the bluetooth sig group.

manager.startDeviceScan(['00001805-0000-1000-8000-00805f9b34fb', 'c7fcee6f-e7e0-8c8a-b745-fde27c268efd'], {allowDuplicates: true}, (error, device) => {
        console.log("Anything?");
        if (error) {
            console.log("Error in background device scan: ", JSON.stringify(error));
        }

        if (device) {
            console.log("DEVICE UUIDS: ", device.serviceUUIDs);
            console.log("Found device in background scan: ", device.id);
        }
    });

I am setting log level to verbose. This is the only relevant log I have found:

'CentralManager(10766645056) scanForPeripherals(
withServices: Optional("[00001805-0000-1000-8000-00805F9B34FB, C7FCEE6F-E7E0-8C8A-B745-FDE27C268EFD]"),
options: Optional(["kCBScanOptionAllowDuplicates": true]))'

Library version: 1.0.3
Platform: IOS and Android

I have tried my best to do my due diligence before submitting a bug report. Please let me know what other relevant information I can provide, or what I am missing.

Thank you for your help and excellent library!


As a sidenote, I am pretty unclear on what happens when the app is registered for background modes, and a device or service is reconnected. For instance, in IOS it is recommended to just call connectToDevice(id) when a device disconnects if we want to reconnect. But, lets say, the app performs a data transfer when a component is mounted. If the app is in the background then that component is not mounted and that data transfer is not performed? Because of this confusion is why I am using react-native-background-fetch so I know exactly the code the runs in the background.

@njdullea njdullea added the bug label Sep 3, 2019
@njdullea njdullea changed the title Bug Report Scanning in background task. Sep 3, 2019
@jayrenteria
Copy link

Also having this problem on iOS, but on Android it is working well.

@Cierpliwy Cierpliwy added the pending Issues that are planned to be worked on at some point in the future label Sep 13, 2019
@njdullea
Copy link
Author

njdullea commented Feb 4, 2020

I am still interested in understanding more about how to properly use this library with background modes.

There are two relevant pieces of information in the documentation:

  1. It (the ble manager) should be initialized only once with the new keyword and method destroy() should be called on its instance when the user wants to deallocate all resources.
  2. In case you want to properly support Background Mode, you should provide restoreStateIdentifier and restoreStateFunction in BleManagerOptions.

A couple of questions I have regarding that:

  1. Is it correct I need to use a background modes library to use this library in the background?
  2. If I create a BLE manager in the app, and then a separate one when the background task runs, will that cause an issue if I do not call manager.destroy() on one of them?
  3. What do the restoreStateIdentifier and Function do, and how should I properly use them?

An example of the proper way to implement background tasks with BLE would probably be very useful for a lot of users, but of course that takes more time to do as all things do.

Thanks again for a great library!

@Cierpliwy
Copy link
Contributor

In upcoming days I will research this topic. The result will be a wiki page with all the details.

@AzRunRCE
Copy link

I have the same issue.I don't understand how can i use this library in background mode on Ios and Android.

@AzRunRCE
Copy link

I am still interested in understanding more about how to properly use this library with background modes.

There are two relevant pieces of information in the documentation:

  1. It (the ble manager) should be initialized only once with the new keyword and method destroy() should be called on its instance when the user wants to deallocate all resources.
  2. In case you want to properly support Background Mode, you should provide restoreStateIdentifier and restoreStateFunction in BleManagerOptions.

A couple of questions I have regarding that:

  1. Is it correct I need to use a background modes library to use this library in the background?
  2. If I create a BLE manager in the app, and then a separate one when the background task runs, will that cause an issue if I do not call manager.destroy() on one of them?
  3. What do the restoreStateIdentifier and Function do, and how should I properly use them?

An example of the proper way to implement background tasks with BLE would probably be very useful for a lot of users, but of course that takes more time to do as all things do.

Thanks again for a great library!

The restoreStateFunction is fired for you ? If yes, can you explain?

@njdullea
Copy link
Author

njdullea commented Feb 18, 2020

@AzRunRCE I have no idea what the restoreStateFunction does or how to use it.

I have had some luck with the restoreStateIdentifier. By using it, I have been able to use the methods manager.devices([id]) to see what devices are connected to the system but not the app, and the method manager.connectedDevices([uuid]).

The first has really only been useful when hot reloading causes stuff the break w/ the ble, but that happens frequently for use during development.

The second returned something one time, but I have never seen it do anything since then.

@Cierpliwy
Copy link
Contributor

Specifying both restoreStateIdentifier and restoreStateFunction tells iOS that you are interested in maintaining BLE state (connection as well) in the background. When in background mode, iOS may kill the app after unspecified time, but at the same time operating system will hold BLE connection (if one exists) for you. After this event, when user goes back to the application or it's woken up by a Bluetooth event, it is restored with maintained BLE state. Check argument of restoreStateFunction to get list of connected devices.

Additionally:

  • First application launch returns null state.
  • Application killed by a user (swipe), can't be restored.

@njdullea
Copy link
Author

njdullea commented Feb 18, 2020

Thank you @Cierpliwy, is this along the lines of how you would implement and use restore state identifier and function?

const restore_state_identifier = 'manager';
const restore_state_function = async (restored_state) => {
  console.log('Restored State: ', restored_state);
  const connected_devices = await restored_state.connectedDevices();
  console.log('Connected Devices: ', connected_devices);
  // do what you need with the devices_connected
}

const manager = new BleManager({restoreStateIdentifier: restore_state_identifier, restoreStateFunction: restore_state_function});

@Cierpliwy
Copy link
Contributor

Please check documentatation when in doubt: https://polidea.github.io/react-native-ble-plx/#blemanageroptionsrestorestatefunction. restored_state may be null and connectedDevices is not a function.

@Cierpliwy
Copy link
Contributor

Hello! I added a new entry in the Wiki with an example application to show you all available possibilities around background mode on iOS. Checkout page here: https://github.com/Polidea/react-native-ble-plx/wiki/Background-mode-(iOS).

@njdullea
Copy link
Author

@Cierpliwy This is incredibly thorough. Thank you for your help, it is much appreciated!

@ezranbayantemur
Copy link

Hello! I added a new entry in the Wiki with an example application to show you all available possibilities around background mode on iOS. Checkout page here: https://github.com/Polidea/react-native-ble-plx/wiki/Background-mode-(iOS).

Hi, thanks for your efforts!
Is background mode supported by Android too?

@robertobrogi
Copy link

Hi all, any news about Android?

thanks

@ezranbayantemur
Copy link

For anyone interested with Android side:
Looks like Android doesn't required any specific steps like iOS. You can create bluetooth operation on background with react-native-background-actions package. This packages allows you to create background service on Android even app killed/ terminated (swipe up)

But like iOS; you must provide a UUID for scanning function of manager. This means you can't scan everything on background mode.

Basically:

const task = async () => {
    await new Promise(async () => {
        manager.startDeviceScan(
            [UUID],  // UUID of your devices 
            {scanMode: ScanMode.LowPower}, // I haven't checked yet but LowLatency mode probably
                                           // drains so much battery, so maybe OS kill our background service. 
                                           // So better not to be so aggressive
             listener  // Do whatever you want when the device has found
         )
    });
};

await BackgroundService.start(task, options);

Speaking of it;
When you working on background with heavy tasks (such as like our topic, ble scans) your user should give some permission (I'm not talking about AndroidManifest "uses-permission" thing) to your application on device Settings menu.
You can look them on dontkillmyapp

You can check your task does scanning, made connections and did some operation with adb shell dumpsys bluetooth_manager command. If you saw Ongoing Scans label under your package name; then your background ble operations are working!

PLUS: You can check if your task running or not with adb shell dumpsys activity services <your-package-name>

Hope it helps!

@kindapath
Copy link

For anyone interested with Android side: Looks like Android doesn't required any specific steps like iOS. You can create bluetooth operation on background with react-native-background-actions package. This packages allows you to create background service on Android even app killed/ terminated (swipe up)

But like iOS; you must provide a UUID for scanning function of manager. This means you can't scan everything on background mode.

Basically:

const task = async () => {
    await new Promise(async () => {
        manager.startDeviceScan(
            [UUID],  // UUID of your devices 
            {scanMode: ScanMode.LowPower}, // I haven't checked yet but LowLatency mode probably
                                           // drains so much battery, so maybe OS kill our background service. 
                                           // So better not to be so aggressive
             listener  // Do whatever you want when the device has found
         )
    });
};

await BackgroundService.start(task, options);

Speaking of it; When you working on background with heavy tasks (such as like our topic, ble scans) your user should give some permission (I'm not talking about AndroidManifest "uses-permission" thing) to your application on device Settings menu. You can look them on dontkillmyapp

You can check your task does scanning, made connections and did some operation with adb shell dumpsys bluetooth_manager command. If you saw Ongoing Scans label under your package name; then your background ble operations are working!

PLUS: You can check if your task running or not with adb shell dumpsys activity services <your-package-name>

Hope it helps!

Thanks brother, it works!

@milobob
Copy link

milobob commented Nov 11, 2023

I am looking for a Bluetooth expert consultant (must be US based) to help with Android app background functionality. We have an iOS app that works fairly well, but Android having trouble scanning and reconnecting in the background. Anyone know someone that can help? Experience in React-Native and Bluetooth, especially the react-native-ble-plx library desired.

@lsantosmorecolab
Copy link

lsantosmorecolab commented Mar 4, 2024

For anyone interested with Android side: Looks like Android doesn't required any specific steps like iOS. You can create bluetooth operation on background with react-native-background-actions package. This packages allows you to create background service on Android even app killed/ terminated (swipe up)
But like iOS; you must provide a UUID for scanning function of manager. This means you can't scan everything on background mode.
Basically:

const task = async () => {
    await new Promise(async () => {
        manager.startDeviceScan(
            [UUID],  // UUID of your devices 
            {scanMode: ScanMode.LowPower}, // I haven't checked yet but LowLatency mode probably
                                           // drains so much battery, so maybe OS kill our background service. 
                                           // So better not to be so aggressive
             listener  // Do whatever you want when the device has found
         )
    });
};

await BackgroundService.start(task, options);

Speaking of it; When you working on background with heavy tasks (such as like our topic, ble scans) your user should give some permission (I'm not talking about AndroidManifest "uses-permission" thing) to your application on device Settings menu. You can look them on dontkillmyapp
You can check your task does scanning, made connections and did some operation with adb shell dumpsys bluetooth_manager command. If you saw Ongoing Scans label under your package name; then your background ble operations are working!
PLUS: You can check if your task running or not with adb shell dumpsys activity services <your-package-name>
Hope it helps!

Thanks brother, it works!

Why this doesnt work for me?
I have this on the same way you do - all permitions, AndroidManifest and Gradle changes to support that, but i really cant run the BleManager in Background mode. The scanner is mounted, but never running...?

When in foreground he can find devices, but in background he only "starts" the scanner ("entrei", but never really starts the scanner so I can find a new devices...

Really apreciate any help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug pending Issues that are planned to be worked on at some point in the future
Projects
None yet
Development

No branches or pull requests

9 participants