如何在Android后台服务中运行cordova插件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24584914/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to run cordova plugin in Android background service?
提问by mehsen
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.
我正在开发在cordova上开发的移动应用程序。我想实现一个后台服务,它做一些工作,比如打开套接字连接将本地数据库与远程数据库同步,并在新的远程推送等方面通知用户。关键是我在javascript中实现了这段代码,但我想在后台执行它。
I searched internet for a cordova background service plugin.
我在互联网上搜索了cordova 后台服务插件。
- katzer/cordova-plugin-background-mode
- jocull/phonegap-backgroundjs
The best one I think is red-folderbut 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.
- katzer/cordova-plugin-background-mode
- jocull/phonegap-backgroundjs
我认为最好的一个是红色文件夹,但它仅适用于 android,它不允许我编写要在后台执行的 javascript。但只是在java和javascript之间交换json。
I have read some topics about background service in android these are useful ones I found:
我已经阅读了一些关于 android 后台服务的主题,我发现这些主题很有用:
- create-a-service-on-android-with-phonegap-application
- simple-android-service-example-code-description-start-stop-service
- android-using-webview-outside-an-activity-context
- 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
gives null
.
所以我开始编写cordova插件(主要在android上)来在后台执行javascript代码。我从后台服务创建了一个 webview 来执行它的 javascript。当我执行普通的 javascript 时,这很好用,但是当涉及到cordova 插件 js 时,它会失败,例如设备device.uuid
给出null
.
This is the java service code:
这是java服务代码:
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);
}
UpdateThere is no error in the logcat. So I tried to write the device object on the screen and thats what I get :
更新logcat 中没有错误。所以我试图在屏幕上写设备对象,这就是我得到的:
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
with cordovaWebView
But the same result is given.
我试图取代标准webView
与cordovaWebView
但同样的结果给出。
//WebView wv = new WebView(this); Commented out
CordovaWebView wv = new CordovaWebView(this);
Any help about this problem ?
关于这个问题的任何帮助?
回答by Jan Misker
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.
您应该使用嵌入式 Cordova WebView,而不是标准 WebView。未设置标准 WebView 来处理 Cordova 插件,设备信息是一个插件。
See the Cordova docs on embedding webviews.
回答by CruorVult
To work with Cordova plugins in WebView as background service, i've created class that implements CordovaInterface. Here is an example
为了在 WebView 中使用 Cordova 插件作为后台服务,我创建了实现 CordovaInterface 的类。这是一个例子
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.
为了防止在cordova 初始化时出错,我覆盖了onJsAlert 方法。如果你有时间,你可能已经找到了更好的方法。
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);
回答by Richard
WebViews can not execute javascript from a background service.
WebViews 无法从后台服务执行 javascript。
I would recommend using native code instead. But if you must use javascript, i would try this library
我建议改用本机代码。但是如果你必须使用 javascript,我会试试这个库
https://code.google.com/p/jav8/
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.
首先将脚本的内容加载到字符串中,然后运行engine.eval()
方法。
Example (Run "test.js" from assets):
示例(从资产运行“test.js”):
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.
注意!该eval
函数期望一次只执行一个 javascript 函数并返回该函数的值。