react-native-boundary icon indicating copy to clipboard operation
react-native-boundary copied to clipboard

Headless event listener not called when app is killed

Open mathiasmoeller opened this issue 4 years ago • 24 comments

Hey @eddieowens !

When the app is in foreground or background the boundary callbacks work perfectly! But I am struggling with the Headless part when the app is killed. In logcat I can see that the event is fired. I see the log message from boundary's index.js file:

ReactNativeJS: 'onExit', [ 'rated0' ]

which comes from this part of code here:

const HeadlessBoundaryEventTask = async ({event, ids}) => {
  console.log(event, ids);
  boundaryEventEmitter.emit(event, ids)
};

But my callback is never executed. I think the issue might be timing. When the app starts because of a Headless event I can see that boundary receives the event as said above. I added log messages for the Callback Registration and it seems to happen after the Headless event:

15:03:19.837 ReactNativeJS: 'onExit', [ 'rated0' ] // from boundary's index.js
15:03:19.863 ReactNativeJS: Registering Boundary Callbacks // my code

I moved the callback registration to the very first line of my index.js but the order still seems to be incorrect. Any idea how to solve this? Where should I call the Boundary.on callback registration in my code?

Setup:

  • "react-native": "0.59.5"
  • "react-native-activity-recognition": "woffu/react-native-boundary" // fix for newer android versions

Help is very much appreciated :)

mathiasmoeller avatar Mar 19 '20 14:03 mathiasmoeller

@mathiasmoeller I was having the same issue and fixed it by registering another headless task in index.js for the event. Then I just have it run the same code as it normally would. This method doesn't work for iOS, however, so it's not a great solution. I can't get iOS to do stuff when the app is killed and I don't know why.

NuclearKev avatar Apr 20 '20 20:04 NuclearKev

Hi @NuclearKev , can you share the code how you did that! That will be a big help!

aniksharif avatar Apr 21 '20 14:04 aniksharif

Sure! I use ClojureScript so it'll look kinda weird but you should be able to get the gist:

Somewhere in index.js you'll need to add the headless task register

(.registerHeadlessTask app-registry "OnBoundaryEvent" (fn [] async-boundary))

Make sure that you register the same event that react-native-boundary does, namely "OnBoundaryEvent".

registerHeadlessTask requires that the function you pass it be async. In CLJS I had to have a function that returns the async function but I don't think you need that in JS.

Then, somewhere else:

(defn async-boundary [d]
  (async
   (let [event (.-event ^js d)
         id (first (.-ids ^js d))]
     (when (= event "onEnter")
       ;; run some code in here!
      ))
   (js/Promise.resolve)))

and that's literally it!

EDIT: You may need to comment out the headless task in react-native-boundary to remove some warnings.

NuclearKev avatar Apr 21 '20 15:04 NuclearKev

@NuclearKev How would that look like in TypeScript? Do I just put

AppRegistry.registerHeadlessTask('OnBoundaryEvent', (event) => {
    if(event == "onEnter"){
        //my code here
     }
})

into the index.js? My main concern is: how would I get access to the id? Does it get passed along in the event ?

Your answer would be highly appreciated.

matyasdanko avatar Apr 21 '20 18:04 matyasdanko

@SufniDroid just like how react-native-boundary does it:

const HeadlessBoundaryEventTask = async ({event, ids}) => {
  console.log(event, ids);
  boundaryEventEmitter.emit(event, ids)
};

So in our case:

const HeadlessBoundaryEventTask = async ({event, ids}) => {
     if(event === "onEnter"){
        //my code here
     }
};

EDIT: or like this if you don't want to have a named function:

AppRegistry.registerHeadlessTask('OnBoundaryEvent', async ({event, ids}) => {
    if(event === "onEnter"){
        //my code here
     }
})

NuclearKev avatar Apr 21 '20 18:04 NuclearKev

I hope that works for you guys! I still have yet to figure out iOS....

NuclearKev avatar Apr 21 '20 18:04 NuclearKev

I know that the event gets triggered (if I put a breakpoint on the native code where the event gets triggered, it will stop there) but the code in the event listener doesn't get ran. No idea how to make it run. I was thinking it was maybe related to BGTaskScheduler but the more I look into it the less I think that's it.

NuclearKev avatar Apr 21 '20 18:04 NuclearKev

@NuclearKev I am working on a fix for iOS, should come very shortly.

cladjules avatar Apr 23 '20 16:04 cladjules

@cladjules please, keep us posted! :)

NuclearKev avatar Apr 23 '20 16:04 NuclearKev

Just tested this ability with react-native-background-geolocation and it worked. So it's definitely possible! Their library is far more complicated than react-native-boundary, so getting it to work would be excellent. Not to mention, the other one causes a lot of money to use on Android...

NuclearKev avatar Apr 23 '20 18:04 NuclearKev

Yes a fix for iOS would be awesome! I managed to get it run on Android (the way @NuclearKev suggested). Now iOS needs to work 😁 Thanks for your help!

mathiasmoeller avatar Apr 24 '20 07:04 mathiasmoeller

I have opened a PR here: https://github.com/eddieowens/react-native-boundary/pull/56

It looks ok on my side, if you could do some testing, that would be great.

Thanks

cladjules avatar Apr 26 '20 14:04 cladjules

Thanks, @cladjules

I'll be testing that out later today!

NuclearKev avatar Apr 27 '20 13:04 NuclearKev

@cladjules your fixes worked!

NuclearKev avatar Apr 27 '20 15:04 NuclearKev

@NuclearKev Great. Thanks for the help on Android as well. That should probably be documented?

cladjules avatar May 01 '20 09:05 cladjules

@cladjules where should it be documented?

NuclearKev avatar May 01 '20 14:05 NuclearKev

@NuclearKev How to add the Headless function, it's not obvious until you find that open issue. In the Readme, I guess.

cladjules avatar May 08 '20 14:05 cladjules

Does anyone know if there is a way to force iOS to check the location upon app startup? It looks like if the user has the location permission set to "while using," it won't fire the event if they are in the radius when they open the app.

EDIT: I tried adding in a function that runs [self.locationManager checkLocation] but it doesn't seem to work.

NuclearKev avatar May 12 '20 13:05 NuclearKev

The native APIs are designed to work only if the user sets the location permission to always.

m-ruhl avatar May 15 '20 09:05 m-ruhl

@SufniDroid just like how react-native-boundary does it:

const HeadlessBoundaryEventTask = async ({event, ids}) => {
  console.log(event, ids);
  boundaryEventEmitter.emit(event, ids)
};

So in our case:

const HeadlessBoundaryEventTask = async ({event, ids}) => {
     if(event === "onEnter"){
        //my code here
     }
};

EDIT: or like this if you don't want to have a named function:

AppRegistry.registerHeadlessTask('OnBoundaryEvent', async ({event, ids}) => {
    if(event === "onEnter"){
        //my code here
     }
})

@NuclearKev Where can I put this code? I put it in componentDidMount() but it is not working. There is an error: taskProvider() is not a function. (In 'taskProvider()(data)', 'taskProvider()' is an instance of Promise).

xoapit avatar Jun 07 '20 11:06 xoapit

It shoud be like this: AppRegistry.registerHeadlessTask('OnBoundaryEvent', () => async ({event, ids}) => { if(event === "onEnter"){ //my code here } })

xoapit avatar Jun 07 '20 11:06 xoapit

@xoapit I believe that in JavaScript you need to place it in the index.js file. (In ClojureScript it can be placed in the core.cljs)

NuclearKev avatar Jun 08 '20 14:06 NuclearKev

@xoapit @NuclearKev I doubt you need to add anything additional? It's already included in that lib's index.js: https://github.com/eddieowens/react-native-boundary/blob/master/index.js

Should work out of the box, as long as your listeners are not within a React lifecycle.

cladjules avatar Jun 08 '20 14:06 cladjules

on Event doesn't work in Android when the app is killed so I have to use addAppRegistry.registerHeadlessTask outside of React lifecycle as a trick to observe event changes.

xoapit avatar Jun 13 '20 10:06 xoapit