Ответ 1
Вам следует использовать встроенный веб-интерфейс Cordova, а не стандартный WebView. Стандартный WebView не настроен для обработки плагинов Cordova, а информация об устройстве - плагин.
Я работаю над мобильным приложением, разработанным на cordova. Я хочу внедрить фоновый сервис, который выполняет некоторую работу, например, открывать соединение сокета, синхронизировать локальную базу данных с удаленным и уведомлять пользователей о новых удаленных нажатиях и т.д. Дело в том, что у меня этот код реализован в javascript, но я хочу выполнить его в фоновом режиме.
Я искал интернет для плагина поддержки кордовой связи.
Самый лучший, который я считаю red-folder, но он просто для android, и он не позволяет мне писать javascript для выполнения в фоновом режиме. а просто обмен json между java и javascript.
Я прочитал несколько тем о фоновой службе в android, которые я нашел:
Итак, я начал писать плагин cordova (в первую очередь на android), чтобы выполнить код javascript в фоновом режиме. Я создал webview из фоновой службы, чтобы выполнить javascript. Это отлично работает, когда я запускаю обычный javascript, но когда дело доходит до плагинов кордовой 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);
}
Обновление В логарифме нет ошибки. Поэтому я попытался написать объект устройства на экране, и вот что я получаю:
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);
Любая помощь по этой проблеме?
Вам следует использовать встроенный веб-интерфейс Cordova, а не стандартный WebView. Стандартный WebView не настроен для обработки плагинов Cordova, а информация об устройстве - плагин.
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();
}
Сначала загрузите contens вашего script в строку, а затем запустите метод 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 будет выполняться за раз и возвращает значение этой функции.
Чтобы работать с плагинами Cordova в WebView в качестве фоновой службы, я создал класс, который реализует 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();
}
}
Чтобы предотвратить ошибки при инициализации кордовы, я переопределил метод 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);