listen to click-event from connected button BLE peripheral, while app is in background <react-native ble manager iOS >

Viewed 363

As the title suggests, im trying to listen for click-event from my connected BLE peripheral device even after my react-native app is killed/background mode.

While connected i have a notification subscription on my BLE peripheral device and everytime i press button on device, my app gets notified. I want this subscription to last even if the user kills the application.

The app works fine in foreground and inactive, but when i kill the app on iOS it stops responding to button click. On android i found a library react-native-background-actions which helped solve this. Here is the background code that is currently working on android.

import BackgroundJob from "react-native-background-actions";


playing = BackgroundJob.isRunning();

const sleep = (time) =>
  new Promise((resolve) => setTimeout(() => resolve(), time));

BackgroundJob.on("expiration", () => {
  console.log("iOS: I am being closed!");
});

const taskRandom = async (taskData) => {
  if (Platform.OS === "ios") {
    console.warn(
      "This task will not keep your app alive in the background by itself, use other library like react-native-track-player that use audio,",
      "geolocalization, etc. to keep your app alive in the background while you excute the JS from this library."
    );
  }
  await new Promise(async (resolve) => {
    // For loop with a delay
    const { delay } = taskData;
    console.log(BackgroundJob.isRunning(), delay);
    for (let i = 0; BackgroundJob.isRunning(); i++) {
      console.log("Ran -> ", i);

    //   await BackgroundJob.updateNotification({
    //     taskDesc: "Emergency -> " + i,
    //   });
      await sleep(delay);
    }
  });
};

const options = {
  taskName: "Example",
  taskTitle: "ExampleTask title",
  taskDesc: "ExampleTask desc",
  taskIcon: {
    name: "ic_launcher",
    type: "mipmap",
  },
  color: "#ff00ff",
  linkingURI: "exampleScheme://chat/jane",
  parameters: {
    delay: 30000,
  },
};


/**
 * Toggles the background task
 */
export const toggleBackground = async () => {
playing = !playing;
  if (playing) {
    try {
      console.log("Trying to start background service");
      await BackgroundJob.start(taskRandom, options);
      console.log("Successful start!");
    } catch (e) {
      console.log("Error", e);
    }
  } else {
    console.log("Stop background service");
    await BackgroundJob.stop();
  }
};

I tried reading the core bluetooth background processing for iOS apps and added a restoration identifier on my start method like this:

BleManager.start({
  showAlert: true,
  restoreIdentifierKey: "IDENTIFIER",
  queueIdentifierKey: "IDENTIFIER",
}).then(() => {
  console.log("Module initialized");
});

Does anyone have a suggestion on how to keep the subscription while app is in background? react-native-background-actions suggests audio or geolocation libraries, but these are not relevant for my application.

Any help would be greatly appreciated.

1 Answers

You have two very different states you are talking about; Background and killed.

If your app is not onscreen but is still in memory then it is "suspended". It remains suspended until

  1. It is brought back into the foreground by the user
  2. A supported background event occurs and it executes briefly while before becoming suspended again.
  3. It is removed from memory because iOS needs resources
  4. It is removed from memory by the user "Swiping it away"

If an iOS app is suspended and you have added Bluetooth background mode to your app then it will just work; This is scenario 2.

You need to consider what you want to do if the peripheral goes out of range; Do you want to try and reconnect or do you want to give up.

If you want to try and reconnect then you simply call connect in response to a disconnection. If the peripheral comes into range then Core Bluetooth will provide a call-back to your app (even if it is suspended). This applies in both scenario 1 & 2.

An app can be in two different "killed" states; terminated by the system and terminated by the user. These are scenarios 3 & 4

If the app is terminated by the system, scenario 3, and you have set up Core Bluetooth state restoration when you initialised Core Bluetooth then iOS will relaunch your app. When relaunched you need to set up Core Bluetooth again and then the event will be delivered to your app as usual.

If the app is terminated by the user swiping up, scenario 4, then generally speaking your app is dead until the user relaunches it.

You haven't shown how you are using Core Bluetooth, so I can't offer any concrete suggestions but I can say the approach you have shown, trying to keep your app running in the background, is not the right approach and will definitely not work on iOS. There may even be a better approach on Android, but I am not familiar with that platform. Generally keeping an app around, in memory, performing useless work is just wasting memory and battery resources.

Related