How to run cordova plugin in Android background service?
Solution 1
You should use an embedded Cordova WebView, not a standard WebView. A standard WebView is not set up to handle Cordova plugins, and the device info is a plugin.
See the Cordova docs on embedding webviews.
Solution 2
WebViews can not execute javascript from a background service.
I would recommend using native code instead. But if you must use javascript, i would try this library
https://code.google.com/p/jav8/
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("jav8");
try {
engine.eval("print('Hello, world!')");
} catch (ScriptException ex) {
ex.printStackTrace();
}
First load the contens of your script into a string and then run engine.eval()
method.
Example (Run "test.js" from assets):
AssetManager am = context.getAssets();
InputStream is = am.open("test.js");
BufferedReader r = new BufferedReader(new InputStreamReader(is));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("jav8");
try {
engine.eval(total.toString());
} catch (ScriptException ex) {
ex.printStackTrace();
}
Notice!
The eval
function expects only a javascript function to be executed at a time and returns the value of this function.
Solution 3
To work with Cordova plugins in WebView as background service, i've created class that implements CordovaInterface. Here is an example
private class CordovaBackground extends Activity implements CordovaInterface {
private ArrayList pluginEntries = new ArrayList();
private CordovaPreferences preferences;
private Context context;
private Whitelist internalWhitelist;
private Whitelist externalWhitelist;
private CordovaWebViewBackground webView;
protected LinearLayout root;
private WindowManager serviceWindowManager;
private final ExecutorService threadPool = Executors.newCachedThreadPool();
public CordovaBackground(Context context, WindowManager windowManager) {
attachBaseContext(context);
this.context = context;
this.serviceWindowManager = windowManager;
}
private void loadConfig() {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(this);
preferences = parser.getPreferences();
internalWhitelist = parser.getInternalWhitelist();
externalWhitelist = parser.getExternalWhitelist();;
ArrayList<PluginEntry> allPluginEntries = parser.getPluginEntries();
String[] backgroundPluginNames = {"File"};//not all plugins you need in service, here is the list of them
ArrayList<String> backgroundPlugins = new ArrayList<String>(
Arrays.asList(backgroundPluginNames));
for (PluginEntry pluginEntry : allPluginEntries) {
if (backgroundPlugins.contains(pluginEntry.service)) {
pluginEntries.add(pluginEntry);
}
}
}
public void loadUrl(String url) {
init();
webView.loadUrl(url);
}
public void init() {
loadConfig();
webView = new CordovaWebViewBackground(context);
if (webView.pluginManager == null) {
CordovaWebViewClient webClient = webView.makeWebViewClient(this);
CordovaChromeClientBackground webChromeClient = webView.makeWebChromeClient(this);
webView.init(this, webClient, webChromeClient,
pluginEntries, internalWhitelist, externalWhitelist, preferences);
}
}
public WindowManager getWindowManager() {
return serviceWindowManager;
}
@Override
public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
}
@Override
public void setActivityResultCallback(CordovaPlugin plugin) {
}
@Override
public Activity getActivity() {
return this;
}
@Override
public Object onMessage(String id, Object data) {
return null;
}
@Override
public ExecutorService getThreadPool() {
return threadPool;
}
@Override
public Intent registerReceiver(android.content.BroadcastReceiver receiver, android.content.IntentFilter filter) {
return getIntent();
}
@Override
public String getPackageName() {
return context.getPackageName();
}
}
To prevent errors while cordova initializing, i've overrode onJsAlert method. If you have a time, you may have found better way.
private class CordovaWebViewBackground extends CordovaWebView {
public CordovaWebViewBackground(Context context) {
super(context);
}
public CordovaChromeClientBackground makeWebChromeClient(CordovaInterface cordova) {
return new CordovaChromeClientBackground(cordova, this);
}
}
private class CordovaChromeClientBackground extends CordovaChromeClient {
public CordovaChromeClientBackground(CordovaInterface ctx, CordovaWebView app) {
super(ctx, app);
}
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
//super.onJsAlert(view, url, message, result);
return true;
}
}
How to use:
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
CordovaBackground cordovaBackground = new CordovaBackground(this, wm);
cordovaBackground.setIntent(intent);
String url = "file:///android_asset/www/test.html";
cordovaBackground.loadUrl(url);
mehsen
Updated on October 14, 2020Comments
-
mehsen over 3 years
I am working on mobile application developed on cordova . I want to implement a background service that do some work like open socket connection syncronise local database with remote one and notify the users on new remote pushes etc . The point is I have this code implemented in javascript but I want execute it i background.
I searched internet for a cordova background service plugin.
-
The best one I think is red-folder but it is just for android and it does not let me to write javascript to be executed in background. but just exchange json between java and javascript.
I have read some topics about background service in android these are useful ones I found:
- create-a-service-on-android-with-phonegap-application
- simple-android-service-example-code-description-start-stop-service
- android-using-webview-outside-an-activity-context
So I started writing cordova plugin (primarily on android) to execute the javascript code in background. I created a webview from the background service to execute the javascript from it. This works fine when I execute normal javascript but when it comes to cordova plugins js it fails for example the device
device.uuid
givesnull
.This is the java service code:
public void onStart(Intent intent, int startId) { Toast.makeText(this, "My Happy Service Started", Toast.LENGTH_LONG).show(); createBackGroundView(); super.onStart(intent,startId); } public void createBackGroundView(){ WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutParams params = new WindowManager.LayoutParams( android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT ); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 0; params.width = 200; params.height = 200; LinearLayout view = new LinearLayout(this); view.setLayoutParams(new RelativeLayout.LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT )); WebView wv = new WebView(this); wv.setLayoutParams(new LinearLayout.LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT )); view.addView(wv); wv.getSettings().setJavaScriptEnabled(true); wv.setWebChromeClient(new WebChromeClient()); wv.loadUrl("file:///android_asset/www/background.html"); wv.setWebViewClient(new WebViewClient() { @Override public void onReceivedError(final WebView view, int errorCode, String description, final String failingUrl) { Log.d("Error","loading web view"); super.onReceivedError(view, errorCode, description, failingUrl); } }); windowManager.addView(view, params); }
Update There is no error in the logcat. So I tried to write the device object on the screen and thats what I get :
document.write(JSON.stringify(window.device))
And this is the result :
{ available : false, plaform : null , version : null , uuid : null , cordova : null , model : null }
I tried to replace the standard
webView
withcordovaWebView
But the same result is given.//WebView wv = new WebView(this); Commented out CordovaWebView wv = new CordovaWebView(this);
Any help about this problem ?