如何在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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:26:54  来源:igfitidea点击:

How to run cordova plugin in Android background service?

javascriptandroidcordovamobilewebview

提问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 后台服务插件。

I have read some topics about background service in android these are useful ones I found:

我已经阅读了一些关于 android 后台服务的主题,我发现这些主题很有用:

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.uuidgives 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 webViewwith cordovaWebViewBut the same result is given.

我试图取代标准webViewcordovaWebView但同样的结果给出。

       //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.

请参阅有关嵌入 webviewsCordova 文档

回答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 evalfunction expects only a javascript function to be executed at a time and returns the value of this function.

注意!eval函数期望一次只执行一个 javascript 函数并返回该函数的值。