Closed wanschi closed 4 years ago
If you're seeing a crash, don't filter the logcat with :S*. You're filtering out the exception stacktrace.
$ adb logcat
Does that mean anything to you?
07-23 16:27:44.440 17367 17392 E ReactNativeJS: Module AppRegistry is not a registered callable module (calling startHeadlessTask)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: FATAL EXCEPTION: mqt_native_modules
07-23 16:27:44.479 17367 17393 E AndroidRuntime: Process: com.brive_app, PID: 17367
07-23 16:27:44.479 17367 17393 E AndroidRuntime: com.facebook.react.common.JavascriptException: Module AppRegistry is not a registered callable module (calling startHeadlessTask), stack:
07-23 16:27:44.479 17367 17393 E AndroidRuntime: value@37:3170
07-23 16:27:44.479 17367 17393 E AndroidRuntime: <unknown>@37:822
07-23 16:27:44.479 17367 17393 E AndroidRuntime: value@37:2565
07-23 16:27:44.479 17367 17393 E AndroidRuntime: value@37:794
07-23 16:27:44.479 17367 17393 E AndroidRuntime: value@-1
07-23 16:27:44.479 17367 17393 E AndroidRuntime:
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.modules.core.ExceptionsManagerModule.showOrThrowError(ExceptionsManagerModule.java:54)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.modules.core.ExceptionsManagerModule.reportFatalException(ExceptionsManagerModule.java:38)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:158)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:751)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
07-23 16:27:44.479 17367 17393 E AndroidRuntime: at java.lang.Thread.run(Thread.java:762)
Does that mean anything to you?
Yes.
React Native version (react-native -v):
Sorry my bad. Version is: 0.59.8
Show me your root index.js
The plugin is failing to import {AppRegistry} from "react-native"
Causing this line to fail
I've added import {AppRegistry} from "react-native"
, but it's still not working.
/**
* @format
* @lint-ignore-every XPLATJSCOPYRIGHT1
*/
import { Navigation } from "react-native-navigation"
import { registerScreens } from "./src/navigation"
import AppStateHandler from "./src/AppStateHandler"
import { createStore } from "./src/redux"
import {Store} from 'redux'
import "moment/src/locale/de"
import localization from "moment/locale/de"
import moment from "moment"
import { persistStore as persistStoreRaw } from "redux-persist"
import {AppRegistry} from "react-native"
import {
dashboard,
deviceNotSuported,
driving,
loginScreen,
forceUpdate,
pendingTerms,
} from "./src/AppRootViews"
import Color from "@assets/color"
export const store: Store = createStore()
moment().locale("de", localization)
const persistStore = storeToPersist =>
new Promise(resolve => {
let persistor = persistStoreRaw(storeToPersist, undefined, () => {
resolve(persistor)
})
})
async function bootstrap() {
const persistor = await persistStore(store)
registerScreens(store, persistor)
Navigation.setDefaultOptions({
bottomTabs: { visible: true, drawBehind: false, animate: true },
topBar: {
buttonColor: Color.buttonColor,
drawBehind: false,
backButton: {
showTitle: false,
color: Color.buttonColor,
},
},
})
const stateHandler = new AppStateHandler({
store,
persistor,
onSignedOut: loginScreen,
onSignedIn: dashboard,
onDriving: driving,
onDeviceNotSupported: deviceNotSuported,
onForceUpdate: forceUpdate,
onPendingTerms: pendingTerms
})
}
Navigation.events().registerAppLaunchedListener(() => {
bootstrap()
})
I've added import {AppRegistry} from "react-native", but it's still not working.
Why? You're not referencing AppRegistry
in your index.js at all.
Why are you not executing BackgroundFetch.registerHeadlessTask
in your index.js?
import BackgroundFetch from "react-native-background-fetch";
let MyHeadlessTask = async () => {
console.log('[BackgroundFetch HeadlessTask] start');
// Perform an example HTTP request.
// Important: await asychronous tasks when using HeadlessJS.
let response = await fetch('https://facebook.github.io/react-native/movies.json');
let responseJson = await response.json();
console.log('[BackgroundFetch HeadlessTask response: ', responseJson);
// Required: Signal to native code that your task is complete.
// If you don't do this, your app could be terminated and/or assigned
// battery-blame for consuming too much time in background.
BackgroundFetch.finish();
}
// Register your BackgroundFetch HeadlessTask
BackgroundFetch.registerHeadlessTask(MyHeadlessTask);
Ok - so I need to register my headless tasks in the index.js
right?
I configure BackgroundFetch in the componentDidMount()
method in my component. Do I have to do both when I want to use headlessJS? In your example above you don't configure the task.
Do I have to do both
BackgroundFetch.configure
. You must always do that in componentDidMount
.BackgroundFetch.registerHeadessTask
always goes in index.js
Your react-native application does not mount in the headless context. None of your react components' componentDidMount
will execute in the headless context. Only index.js
runs in the headless context.
BackgroundFetch.registerHeadessTask
always goes inindex.js
@christocracy Can I import any function and register it on index.js
?
Something like this:
import { myFunction } from "./src/functions/index";
...
BackgroundFetch.registerHeadlessTask(myFunction);
Of course.
Hey @christocracy,
thanks for your support! Everything is working as expected now. Should I do a pull request to clarify some things in the documentation?
Sure
Your react-native application does not mount in the headless context. None of your react components' componentDidMount will execute in the headless context. Only index.js runs in the headless context.
Hey @christocracy, I was wondering if you know why this is true? My experience working with Headless JS in a RN application has shown me that it is true, but I would love to know why.
My best guess (and it is purely a guess) is that this limitation exists because headless JS spawns a different background thread to execute some work that's separate from the main application. Like normally RN has these three threads: (1) Native UI, (2) Layout, (3) Main JS/RN code:
And I'm guessing that the headless background process is separate from the main JS thread, so won't execute any of the React code that would normally interact with the other two threads.... Something like that....
Anyways, I would be appreciative if you have a more definitive answer. Thanks!
When you launch a typical Android app from the home-screen, it consists of an Application
+ Activity
. Your RN App
instance (the user interface) runs in the Activity
.
When an app is launched headless, there is only an Application
instance — no Activity
, thus no RN App
instance, thus no UI.
The Activity
is the "Head". The Application
is the "body". Another name for headless is activity-less or UI-less.
My best guess (and it is purely a guess) is that this limitation exists because
It's not a "limitation", it is simply the nature of Android application architecture.
Thanks @christocracy!
Your Environment
minimumFetchInterval: 15, stopOnTerminate: false, startOnBoot: true, enableHeadless: true,
Expected Behavior
Android app shouldn't crash whenever Headless JS Task is fired.
Actual Behavior
Android app is crashing in release build whenever Headless JS Task is fired.
Steps to Reproduce
adb shell cmd jobscheduler run -f com.xxx 999
Code
Debug logs