0
votes

I've been banging my head against the monitor for the last few days. I'm developing an UWP app for the Windows Store (targeting 14393) and I'm using Prism/Unity frameworks for MVVM / IoC.

Since the data needed to update the Live Tile is stored in a class implementing the Repository pattern and everything is managed through Unity, I'm not creating a separate process for background execution, therefore even simplifying the whole BGTask registration process.

The actual BGTask registration code is as follows:

var servicingTaskAlreadyRegistered = false;
var tileUpdaterTaskAlreadyRegistered = false;

foreach (var t in BackgroundTaskRegistration.AllTasks)
{
    if (t.Value.Name == Constants.BgTileUpdaterTaskName)
        tileUpdaterTaskAlreadyRegistered = true;
    else if (t.Value.Name.Equals(Constants.BgServicingTaskName))
        servicingTaskAlreadyRegistered = true;
}

var reqAccess = await BackgroundExecutionManager.RequestAccessAsync();
if (reqAccess == BackgroundAccessStatus.Denied ||
    reqAccess == BackgroundAccessStatus.DeniedBySystemPolicy ||
    reqAccess == BackgroundAccessStatus.DeniedByUser ||
    reqAccess == BackgroundAccessStatus.Unspecified)
    return false;

if (!servicingTaskAlreadyRegistered)
{
    var servicingTaskBuilder = new BackgroundTaskBuilder();
    servicingTaskBuilder.Name = Constants.BgServicingTaskName;
    servicingTaskBuilder.SetTrigger(new SystemTrigger(SystemTriggerType.ServicingComplete, false));
    servicingTaskBuilder.Register();
}

if (tileUpdaterTaskAlreadyRegistered)
    return true;

var builder = new BackgroundTaskBuilder();
builder.Name = Constants.BgTileUpdaterTaskName;
builder.SetTrigger(new TimeTrigger(TileUpdateFrequencyMinutes, false));
//builder.SetTrigger(new MaintenanceTrigger(TileUpdateFrequencyMinutes, false));
builder.IsNetworkRequested = true;

builder.Register();

The registration successfully completes. Executing Get-AppBackgroundTask in PowerShell shows both tasks, as it should be. However, the TimeTrigger never fires. Swapping TimeTrigger with the MaintenanceTrigger fixes the problem, although the smartphone needs to be plugged to the charger which is not an acceptable workaround.

Forcing the task to run via VisualStudio or PowerShell (Start-AppBackgroundTask -TaskID ) correctly executes and the tile gets updated.

Do you have any other useful tip to share?

Edit 12/01/2017 I've created a Repro containing a Visual Studio Solution with two projects:

  • Live Tile Test Simple: as simple as it gets to have a live tile updating every 15 minutes using UWP. Everything works as expected.
  • Live Tile Test Prism: again, a simple conversion of the above project using Prism and Unity. Doesn't work because when the OS tries to launch the app to update the tile the Unity container is null (doesn't get initialized).

This explains why I'm having the problem: Unity doesn't get initialized, I'm unable to retrieve data via repositories, the app crashes and GG.

Now I just need to understand why Unity isn't available in the OnBackgroundActivated method. Almost there guys!!

Repro: https://github.com/eraser85/LiveTileTestRepro

2

2 Answers

0
votes

The code looks fine to me, the only things I'd try to change here are the use of the IsNetwokRequested property and the TimeTrigger frequency value, are you sure that constant/variable you're using is greater or equal to 15?

Here's a sample:

BackgroundTaskBuilder builder = new BackgroundTaskBuilder { Name = "YourBgTaskName" };
builder.SetTrigger(new TimeTrigger(15, false));
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.Register();
0
votes

Ok so after some more tests I've finally come up with a solution.

As mentioned, the problem stemmed from Prism: basically, when launched by the OS and entering via OnBackgroundActivated() the IoC container wasn't getting initialized.

The solution, even if seems hack-ish, is actually perfectly viable and correct (IMHO!). In your OnBackgroundActivated() just initialize everything as if starting from scratch (have a look at Prism's Source for implementation details): in my specific case, I just called CreateAndConfigureContainer() and re-registered everything I've put in OnInitializeAsync() (eg. repos, services..).

I've opened an issue with the devs. Maybe a solution is already on the way, but in the mean time this should do.