diff --git a/DIFFERENCE.md b/DIFFERENCE.md
new file mode 100644
index 00000000..c127189b
--- /dev/null
+++ b/DIFFERENCE.md
@@ -0,0 +1,13 @@
+# Difference from [original repository](https://github.com/katzer/cordova-plugin-background-mode)
+This repository is trying to solve issues with Windows compatibility of original plugin (mainly by finding workarounds for [issue #222](https://github.com/katzer/cordova-plugin-background-mode/issues/222)).
+## Changes
+1. Plugin hook to add windows capability `backgroundMediaPlayback` into windows `*.appxmanifest` files
+1. Usage of `Windows.ApplicationModel.ExtendedExecution` functionality to keep app running when minimized
+1. Starting audio playback automatically (to keep application running; quiet, but playing) - *might have performance & battery impact*
+## Upsides
+1. Plugin works for Windows applications (Desktop windows tested, haven't tested @mobile)
+1. You can pause application background tasks by clicking pause button under application hover-preview in taskbar (side effect of being "media-app")
+## Downsides
+1. Windows target is not buildable by `[ionic] cordova build|run windows` with package cordova-windows in version lower than 6.0
+1. When you're removing plugin, capability of `backgroundMediaPlayback` is kept in `*.appxmanifest` files, which means, that app is still not buildable by Cordova CLI (cordova-windows lower than 6.0; to fix it, remove/readd windows platform to project after plugin removal)
+1. Possible severe performance issues/battery drains, because of continuous unstopped playback
diff --git a/package.json b/package.json
index ebbedf34..6e9cecc7 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"platforms": [
"ios",
"android",
- "browser"
+ "browser",
+ "windows"
]
},
"repository": {
@@ -20,7 +21,8 @@
"ecosystem:cordova",
"cordova-ios",
"cordova-android",
- "cordova-browser"
+ "cordova-browser",
+ "cordova-windows"
],
"engines": [
{
diff --git a/plugin.xml b/plugin.xml
index 52bd90e9..736bf633 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -90,7 +90,7 @@
target-dir="src/de/appplant/cordova/plugin/background" />
-
@@ -98,10 +98,6 @@
-
-
-
-
@@ -114,7 +110,10 @@
- -->
+
+
+
+
diff --git a/scripts/hook-windows-background-capability.js b/scripts/hook-windows-background-capability.js
new file mode 100644
index 00000000..2fc9fcbc
--- /dev/null
+++ b/scripts/hook-windows-background-capability.js
@@ -0,0 +1,111 @@
+#!/usr/bin/env javascript
+
+/*
+ Copyright (c) Microsoft. All rights reserved.
+ Licensed under the MIT license. See LICENSE file in the project root for full license information.
+*/
+var fs = require("fs");
+var path = require("path");
+var Q;
+var glob;
+var xml2js = require('xml2js');
+
+var requiredCapabilities = [
+ {
+ name: "backgroundMediaPlayback",
+ present: false,
+ tag: "uap3:Capability",
+ namespace: { name: "uap3", uri: "http://schemas.microsoft.com/appx/manifest/uap/windows10/3" }
+ } /*, {
+ name: "extendedExecutionUnconstrained",
+ present: false,
+ tag: "rescap:Capability",
+ namespace: {name: "rescap", uri:"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"}
+ }*/
+];
+
+module.exports = function(context) {
+
+ console.log("Adding proper capability to windows manifests");
+
+ // Grab the Q, glob node modules from cordova
+ Q=context.requireCordovaModule("q");
+ glob=context.requireCordovaModule("glob");
+
+ // Need to return a promise since glob is async
+ var deferred = Q.defer();
+
+ // Find all custom framework files within plugin source code for the iOS platform
+ glob("platforms/windows/package.*.appxmanifest", function(err, manifests) {
+ if(err) {
+ deferred.reject(err);
+ } else {
+ // Folder symlinks like "Header" will appear as normal files without an extension if they came from
+ // npm or were sourced from windows. Inside these files is the relative path to the directory the
+ // symlink points to. So, start detecting them them by finding files < 1k without a file extension.
+ manifests.forEach(function(manifest) {
+ manifest = path.join(context.opts.projectRoot, manifest);
+
+ fs.readFile(manifest, 'utf8', function(err, data) {
+ console.log("Processing:", manifest);
+ if (err) {
+ return console.log(err);
+ }
+
+ xml2js.parseString(data, function(err, xml) {
+ if (err) {
+ return console.log(err);
+ }
+ var capabilities = xml['Package']['Capabilities'][0];
+ if (typeof capabilities === "undefined") {
+ capabilities = {};
+ }
+ // Check if capability is already present
+ requiredCapabilities.forEach(function (req) {
+ if (typeof capabilities[req.tag] !== "undefined") {
+ capabilities[req.tag].forEach(function(capability) {
+ if (capability["$"] && capability["$"]["Name"] == req.name) {
+ req.present = true;
+ }
+ });
+ }
+ });
+
+ requiredCapabilities.forEach(function (req) {
+ if (!req.present) {
+ console.log ("Adding", req.name)
+ if (typeof capabilities[req.tag] === "undefined") {
+ capabilities[req.tag] = [];
+ }
+ capabilities[req.tag].push({"$": { "Name" : req.name }})
+ if (req.namespace && !xml['Package']['$']['xmlns:' + req.namespace.name]) {
+ xml['Package']['$']['xmlns:' + req.namespace.name] = req.namespace.uri;
+ }
+ }
+ });
+ var namespaces = [];
+ for (ns in xml['Package']['$']) {
+ if (ns.match(/^xmlns:/)) {
+ namespaces.push(ns.split(":")[1]);
+ }
+ };
+ xml['Package']['$']['IgnorableNamespaces'] = namespaces.join(" ");
+
+ xml['Package']['Capabilities'] = capabilities;
+
+ // write modified appxmanifest
+ var builder = new xml2js.Builder();
+ fs.writeFile(manifest, builder.buildObject(xml), function(err) {
+ if(err) {
+ return console.log(err);
+ }
+ });
+ });
+ });
+ });
+ deferred.resolve();
+ }
+ });
+
+ return deferred.promise;
+}
diff --git a/src/windows/BackgroundModeProxy.js b/src/windows/BackgroundModeProxy.js
index 5542e3f7..5ac64b7d 100644
--- a/src/windows/BackgroundModeProxy.js
+++ b/src/windows/BackgroundModeProxy.js
@@ -27,7 +27,8 @@ var Uri = Windows.Foundation.Uri,
MediaPlaybackList = Windows.Media.Playback.MediaPlaybackList,
AudioCategory = Windows.Media.Playback.MediaPlayerAudioCategory,
MediaPlayer = Windows.Media.Playback.MediaPlayer,
- WebUIApplication = Windows.UI.WebUI.WebUIApplication;
+ WebUIApplication = Windows.UI.WebUI.WebUIApplication,
+ ExtendedExecution = Windows.ApplicationModel.ExtendedExecution;
/**
* Activates the background mode. When activated the application
@@ -40,6 +41,29 @@ var Uri = Windows.Foundation.Uri,
* @return [ Void ]
*/
exports.enable = function (success, error) {
+
+ var newSession = new ExtendedExecution.ExtendedExecutionSession();
+ newSession.reason = ExtendedExecution.ExtendedExecutionReason.unspecified;
+ newSession.onrevoked = function (args) {
+ console.log("Revoked!!", args);
+ exports.stopKeepingAwake();
+ }
+
+ newSession.requestExtensionAsync()
+ .then(function (result) {
+ switch (result) {
+ case ExtendedExecution.ExtendedExecutionResult.allowed:
+ exports.keepAwake();
+ break;
+ case ExtendedExecution.ExtendedExecutionResult.denied:
+ console.log("BG session failed :(");
+ break;
+ default:
+ break;
+ }
+ }, function (err) {
+ var abc = err.message;
+ });
success();
};
@@ -63,8 +87,9 @@ exports.disable = function (success, error) {
* @return [ Void ]
*/
exports.keepAwake = function () {
- if (!plugin.isEnabled() || plugin.isActive())
+ if (!plugin.isEnabled() || plugin.isActive()) {
return;
+ }
exports.configureAudioPlayer();
exports.audioPlayer.play();
@@ -110,14 +135,11 @@ exports.configureAudioPlayer = function () {
playList.autoRepeatEnabled = true;
audioPlayer.source = playList;
- audioPlayer.autoPlay = false;
+ audioPlayer.autoPlay = true;
audioPlayer.audioCategory = AudioCategory.soundEffects;
audioPlayer.volume = 0;
exports.audioPlayer = audioPlayer;
};
-WebUIApplication.addEventListener('enteredbackground', exports.keepAwake, false);
-WebUIApplication.addEventListener('leavingbackground', exports.stopKeepingAwake, false);
-
cordova.commandProxy.add('BackgroundMode', exports);