React-native-windows: Supporting Running Javascript Runtime in the background

Created on 5 Oct 2018  路  6Comments  路  Source: microsoft/react-native-windows

Environment

  1. react-native-cli: 2.0.1
    react-native: 0.55.4
  2. npm ls rnpm-plugin-windows: [email protected]
  3. npm ls react-native-windows: [email protected]
  4. node -v: v8.11.4
  5. npm -v: 5.6.0
  6. yarn --version: 1.3.2

Then, specify:

  • Target Platform: UWP
  • Target Platform Version(s):
    Target Version:17134
    Min Supported Version: 16299

  • Target Device(s):
    Desktop

  • Development Operating System:

  • Visual Studio Version:
    Window 10 17134
  • Build Configuration:
    Debug

Steps to Reproduce

(Write your steps here:)
I think this is more of a clarifying question:
We have a use case where we have an In-App AppService. We wish to be able to share logic between our foreground application and the background execution of the AppService. To accomplish this we are attempting to run the JavaScript runtime from the background so that we do not have to duplicate logic in both the C# layer as well as the JS layer.

in App.xaml.cs we have:
```c#
protected async override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
try
{
base.OnBackgroundActivated(args);
var deferral = args.TaskInstance.GetDeferral();

    if (!Host.HasInstance)
    {
        DispatcherHelpers.Initialize();
        ReactChoreographer.Initialize();
        await Host.ReactInstanceManager.GetOrCreateReactContextAsync(new CancellationToken());
    }
    IBackgroundTaskInstance taskInstance = args.TaskInstance;
    switch (taskInstance.TriggerDetails)
    {
        case AppServiceTriggerDetails appServiceDetails:
            //Do something with connection
            break;
        default:
            deferral.Complete();
            break;
    }

}

}
```
I got this from digging into how ReactNativeHost OnCreate Works, but I am unsure if this is supported, and if so whether I have done all the required steps in the correct order. I have noticed that if there is any error that occurs then the ReactNatvie attempts to run on the main thread some UI, which in turn crashes the process because we are in the background and there is no UI thread. Is there a way to prevent that? Any help would be greatly appreciated.

Thanks.

.NET needs-update-or-close

All 6 comments

@adam-bratin We do use app in background scenarios extensively, and I think all tweaks we made (ecept one...) are in public RNW. I may be wrong though, I'd like to know about any crashes you're hitting or so.

First of all a clarification: When launched in background OR in foreground from a secondary window (my people, or share charm), the "main UI thread" does exist. You have the MainView with dispatcher and such. In fact it's that thread that calls various lifecycle handlers including OnBackgroundActivated.
What is missing is the CoreWindow for this View.

Over the time this had some implications in RNW:

  • we had to replace the MainView.CoreWindow.Dispatcher constructs with MainView.Dispatcher (the middle man was not helping at all) and make any scenarios that were not depending on that window work.
  • one of these cases is the creation of the layout manager thread. It requires a secondary view, but you can't create it because main one has no CoreWindow... so we had to add a (still ugly) fallback.
  • some other cases really need a CoreWindow in the main view: for example the showing of an alert.. We made sure we don't crash in that case.
  • if your "minimum target" is < RS3 (yes, the min target, not target), you may hit a bad OS bug that leaves that main UI thread without a synchronization context (internally it's still due to the CoreWindow missing). As a result any "await x.DoSomething()" (like "await Host.ReactInstanceManager.GetOrCreateReactContextAsync(...)" in your excerpt) would run the continuation on a worker thread, triggering havoc.
    We have a workaround for that (basically writing our own synchronization context and pushing it aggressively to the dispatcher), but for some reason this didn't make it to public RNW (@rozele may remember why this didn't happen).

So in summary RNW supports these scenarios well, but one patch or two may have to be added to the public repo.

BTW, I'm assuming your scenario is based on the bundle to run something relevant (as part of creating that context). You won't have any root view.

@reseul Thanks for the quick response. To answer your question about the crash. This was being caused by not calling DispatcherHelpers.Initialize(); So I fixed that pretty easily, but that exposed a potential issue. When there is an uncaught exception in either the JS runtime or somewhere else in the RNW source code, then there is an attempt to open a Red Dialog box to display the error to the developer. The problem is that there is no Core Window it causes the application to crash. I am wondering if we need to added a check for the core window before showing the red dialog box?

Also,
The scenario we are working on is that our application may be closed, but we have an event from the system that will wake up an in-process background task. Now we have some logic that needs to run on that trigger. We already have that code written in the JS layer to be used when the application is activated in the foreground. Our desire to use the same code,when the application is also in the background to prevent having to rewrite that code in C# and maintain it in 2 places. So we are ok with not having any root view. We are attempting to maybe do some background processing, or potentially send a toast notification

@adam-bratin yes, there's a change needed for that CoreWindow thing. I'll send a PR of that + some other related, it's been waiting in our branches.
With regard to your second problem, you can avoid code duplication IF you're willing to initialize react context from the background activation. That will have as effect the execution of the bundle.
You'll have to make sure that JS code can be executed outside of the context of a root view since you won't have any.
@rozele should we push the synchronization context hack too? That may also be needed for a complete solution on public side.

@reseul We should consider publishing a version of ReactApplication that supports background initialization.

@adam-bratin can we close this issue for now? If there are specific actions for features that should be added (custom SynchronizationContext, helper class for background initialization, etc.) we should file those in separate issues.

FWIW, we hardened the red box path when there's no main CoreWindow. So we don't crash anymore.

@rozele I am ok with closing this for now. I have not had much time to look into this issue we decided to use Native UWP Background Tasks to handle the work for now. When we update to 0.57 of RNW I will revisit this. If I am still having problems I will reopen.

Was this page helpful?
0 / 5 - 0 ratings