如何在Android后台服务中运行cordova插件?

我正在开发关于cordova的移动应用程序。 我想实现一个后台服务,做一些像远程打开套接字连接syncronise本地数据库的工作,并通知用户在新的远程推动等。 重点是我有这个代码在JavaScript中实现,但我想要执行它,我的背景。

我search了一个cordova后台服务插件的互联网。

  • katzer /cordova-插件背景模式
  • jocull / PhoneGap的-backgroundjs
  • 红色文件夹

    最好的一个,我认为是红色的文件夹,但它只是为Android,它不会让我写JavaScript来执行在后台。 但只是在java和javascript之间交换json。

我已经阅读了一些有关在Android的背景服务的主题这些是我发现的有用的:

  • 创build一种服务上,Android的使用,PhoneGap的应用
  • 简单的Android服务,例如代码,描述起停服务
  • 机器人-使用-网页视图的外一个活动上下文

所以我开始写cordova插件(主要在Android上)在后台执行JavaScript代码。 我从后台服务创build了一个webview来执行它的JavaScript。 这工作正常,当我执行正常的JavaScript,但是当涉及到cordova插件JS失败,例如设备device.uuidnull

这是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); } 

更新 logcat中没有错误。 所以我试图写在屏幕上的设备对象,这就是我得到的:

  document.write(JSON.stringify(window.device)) 

这就是结果:

  { available : false, plaform : null , version : null , uuid : null , cordova : null , model : null } 

我试图用cordovaWebViewreplace标准的webView但是给出了相同的结果。

  //WebView wv = new WebView(this); Commented out CordovaWebView wv = new CordovaWebView(this); 

有关这个问题的任何帮助?

Solutions Collecting From Web of "如何在Android后台服务中运行cordova插件?"

您应该使用embedded式Cordova WebView,而不是标准的WebView。 标准的WebView没有设置来处理Cordova插件,设备信息是一个插件。

查看关于embeddedwebviews的cordova文档 。

WebViews无法从后台服务执行JavaScript。

我会build议使用本机代码。 但是,如果你必须使用JavaScript,我会试试这个库

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(); } 

首先将脚本的内容加载到一个string中,然后运行engine.eval()方法。

示例(从资产运行“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(); } 

注意! eval函数只需要一次执行一个javascript函数并返回这个函数的值。

为了在WebView中使用Cordova插件作为后台服务,我创build了实现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(); } } 

为了防止cordova初始化时出现错误,我重写了onJsAlert方法。 如果你有时间,你可能会find更好的办法。

  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; } } 

如何使用:

 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);