如何在Android后台服务中运行cordova插件?
Posted
技术标签:
【中文标题】如何在Android后台服务中运行cordova插件?【英文标题】:How to run cordova plugin in Android background service? 【发布时间】:2014-07-05 09:23:00 【问题描述】:我正在开发在cordova 上开发的移动应用程序。我想实现一个后台服务,它可以做一些工作,比如打开套接字连接将本地数据库与远程数据库同步,并在新的远程推送时通知用户等。关键是我在 javascript 中实现了这段代码,但我想在后台执行它。
我在互联网上搜索了一个 cordova 后台服务插件。
katzer/cordova-plugin-background-mode
jocull/phonegap-backgroundjs
red-folder
我认为最好的是red-folder,但它只适用于android,它不允许我编写要在后台执行的javascript。但只是在 java 和 javascript 之间交换 json。
我已经阅读了一些关于 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所以我开始编写 cordova 插件(主要在 android 上)来在后台执行 javascript 代码。我从后台服务创建了一个 webview 以从中执行 javascript。这在我执行普通 javascript 时工作正常,但是当涉及到 cordova 插件 js 时它会失败,例如设备 device.uuid
提供 null
。
这是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
我尝试将标准的webView
替换为cordovaWebView
,但给出了相同的结果。
//WebView wv = new WebView(this); Commented out
CordovaWebView wv = new CordovaWebView(this);
对这个问题有什么帮助吗?
【问题讨论】:
有帮助吗:***.com/questions/21505369/… 在我的情况下,javascript 被执行并继续运行,但问题是在后台执行 cordova plugin js。 能不能发个错误或者日志 @kirchberger 我更新了我的问题看上面我没有错误但设备对象为空 您是否按照我在回答中的建议考虑使用 Cordova WebView?在我看来,设备插件的 .js 只是初始化了一个空的设备对象,然后它调用了本机部分,但这会失败(默默地),因为标准的 WebView 没有处理程序。 【参考方案1】:您应该使用嵌入式 Cordova WebView,而不是标准 WebView。没有设置标准 WebView 来处理 Cordova 插件,并且设备信息是一个插件。
请参阅Cordova docs on embedding webviews。
【讨论】:
给出相同的结果我将编辑我的问题以查看我如何使用cordovaWebView 您是否按照文档中的所有步骤进行操作?您是否为插件设置了线程池以在其中运行? 从您在回答中所写的内容来看,您似乎只使用 CordovaWebView 类,但在 Cordova 文档中(我的回答中的链接)很明显,必须采取更多步骤才能配置CordovaWeb 视图。正是这个配置连接了插件(例如,现在不工作的设备插件)。【参考方案2】:WebViews 无法从后台服务执行 javascript。
我建议改用本机代码。但如果你必须使用 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();
首先将脚本的内容加载到字符串中,然后运行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 来执行我的 js 并且它正在工作,但是在使用 cordova 插件的 javascript 时失败 对这个问题有任何想法吗? @mehsen 你不能在没有初始化的情况下使用 Cordova 插件。当 Cordova 引擎初始化时,它会经过一个复杂的过程来设置插件。您需要在后台服务中重复整个过程。 Webview 可以从后台服务执行js。我在 github.com/mauron85/background-geolocation-android/tree/master/… 中使用 evgenii/jsevaluator。【参考方案3】:为了将 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();
为了防止在 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;
使用方法:
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);
【讨论】:
以上是关于如何在Android后台服务中运行cordova插件?的主要内容,如果未能解决你的问题,请参考以下文章
cordova-ionic 应用程序在后台进行地理定位 - android 和 ios
如何在android studio中cordova的混合开发