我想通过
实现java-to-javascript方法调用 WebView.getEngine().executeScript("browserMessagingServicePush('Push data from Java to JS')");
在Android上使用javafxports 8.60.9,但得到了
java.lang.UnsupportedOperationException: Not supported yet.
...
at javafx.scene.web.WebEngine.executeScript(WebEngine.java:860)
异常。
如何引用Android的原生WebView来实现类似的东西?
WebView.addJavascriptInterface(new JSInterface(), "JSInterface");
还是有其他一些解决方法?
答案 0 :(得分:0)
<强>解强>
我找到了一个使用Android原生WebView(而不是使用JavaFX WebView)从JavaFXPorts应用程序执行JavaScript的解决方案:
public class AndroidNativeService extends Activity implements NativeService {
private Stage stage;
public void myWebview(Stage stage) {
this.stage = stage;
FXActivity.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
WebView webView = new WebView(FXActivity.getInstance().getApplicationContext());
FXActivity.getInstance().setContentView(webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(webClient);
webView.loadUrl("http://www.example.com/index.html");
}
});
}
WebViewClient webClient = new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
// super.onPageFinished(view, url);
System.out.println(">>>>>>>>>>>>>>>>>>>>> onpagefinished title = "+view.getTitle());
view.evaluateJavascript("(function(){return document.documentElement.outerHTML})();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String html) {
System.out.println(">>>>>>>>>>>>>>>>>>>>> evaluateJavascript html = "+html);
// view.goBack();
// stage.show(); # get error java.lang.IllegalStateException: Not on FX application thread; currentThread = main
}
});
}
};
}
我使用以下方法调用此类:
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater( () -> {
GoNativePlatform goNativePlatform = GoNativePlatformFactory.getPlatform();
Looper.prepare(); // if don't use this then get error Looper.prepare() not set
goNativePlatform.getNativeService().myWebView(stage);
});
return null;
}
};
Thread th = new Thread(task);
th.start();
我复制了来自Handling Android Native Activities like a Pro的类声明中声明的“Implements NativeService”,尽管这不是绝对必要的。 尝试使用此JavaFX WebView代码实现JavaFX WebView(而不是Android Native WebView)时:
Document doc = webEngine.getDocument();
getTitle(webView.getEngine());
String html = (String) webView.getEngine().executeScript("document.documentElement.outerHTML");
我在Android上运行时获得了空值或“不支持”,尽管代码在桌面上运行正常。 (还没有尝试过IOS,但我想在这里实现)。 我想检索网页标题并执行javascript以从网页中检索其他数据。 所以我的解决方案是在Android上运行时使用Android Native WebView而不是JavaFX WebView。 这是我的完整代码:
public class AndroidNativeService extends Activity implements NativeService {
private Stage stage;
public void myWebview(Stage stage) {
this.stage = stage;
FXActivity.getInstance().runOnUiThread(new Runnable() {
@Override
public void run() {
WebView webView = new WebView(FXActivity.getInstance().getApplicationContext());
FXActivity.getInstance().setContentView(webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(webClient);
webView.loadUrl("http://www.example.com/index.html");
webView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println(">>>>>>>>>>>>>>>>>>>>> onClick()");
// webView.goBack();
}
});
}
});
}
WebViewClient webClient = new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
// super.onPageFinished(view, url);
System.out.println(">>>>>>>>>>>>>>>>>>>>> onpagefinished title = "+view.getTitle());
view.evaluateJavascript("(function(){return document.documentElement.outerHTML})();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String html) {
System.out.println(">>>>>>>>>>>>>>>>>>>>> evaluateJavascript html = "+html);
// view.goBack();
// stage.show(); # get error java.lang.IllegalStateException: Not on FX application thread; currentThread = main
}
});
}
};
@Override
public void onBackPressed() {
System.out.println(">>>>>>>>>>>>>>>>>>>>> Back Button Pressed");
setResult(RESULT_CANCELED);
super.onBackPressed();
// FXActivity.getInstance().finish();
}
}
虽然我已经成功显示了所需的网页,检索了标题并执行了一些JavaScript,但我仍在努力关闭网页并返回JavaFX阶段。
我在onBackPressed()
和OnClickListener
之上的2个回调不起作用且未被调用(无法看到System.out.println
)。你可以从上面看到我正在努力使用这些替代品:
webView.goBack();
stage.show(); // get error java.lang.IllegalStateException: Not on FX application thread; currentThread = main
FXActivity.getInstance().finish();
但我只是设法终止整个应用程序而不是返回JavaFX阶段(即使我将它的值传递给这个类)。有什么想法吗?
PS :Looper.prepare();
是必须能够调用此代码,虽然我不明白我在这里做什么?
答案 1 :(得分:0)
解决方案更新
我找到了一个使用Android原生WebView(而不是使用JavaFX WebView)从JavaFXPorts应用程序执行JavaScript的解决方案 - 请参阅下面的代码。 我通过使用2个活动解决了导航到我的JavaFX阶段和Android WebView的导航(在2018年2月25日的第一个回答中):我的主要活动(JavaFX Stage)调用第二个活动(Android WebView)并传递我想要的URL显示,当第二个Activity完成时,它会传回一个结果字符串。您可以通过执行finish()或使用后退按钮退出第二个Activity。您需要在AndroidManifest.xml中为第二个活动添加一个额外的条目。
这是我的主要活动:
import android.content.Intent;
import javafx.application.Platform;
import javafxports.android.FXActivity;
/*****************************************
This is the main activity
******************************************/
public class MainActivity extends FXActivity {
private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;
protected void webView() {
Platform.runLater( () -> {
String url ="http://www.example.com";
Intent intent = new Intent(FXActivity.getInstance().getApplicationContext(), Test.class);
intent.putExtra("url", url);
// Add result handler
FXActivity.getInstance().setOnActivityResultHandler((requestCode, resultCode, data) ->
switch (requestCode) {
case SECOND_ACTIVITY_REQUEST_CODE:
//if (resultCode == RESULT_OK) {}
// get String data from Intent
String result = data.getStringExtra("result");
System.out.println("result = " + result);
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
});
FXActivity.getInstance().startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
});
}
}
这是我的第二个活动(Android WebView):
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/*****************************************
This is the 2nd activity
******************************************/
public class Test extends Activity {
private String url;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
url = bundle.getString("url");
}
WebView webView = new WebView(this);
setContentView(webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(webClient);
webView.loadUrl(url);
}
WebViewClient webClient = new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
String title = view.getTitle();
System.out.println("onpagefinished title = "+view.getTitle());
view.evaluateJavascript("(function(){return document.documentElement.outerHTML})();",
new ValueCallback<String>() {
@Override
public void onReceiveValue(String html) {
System.out.println("evaluateJavascript html = "+html);
if (<exit 2nd activity condition>) {
// put the String to pass back into an Intent and close this activity
Intent intent = new Intent();
intent.putExtra("result", "this is the result string");
setResult(RESULT_OK, intent);
finishAndRemoveTask(); // takes you back to main activity
}
}
});
}
};
}
这是我的AndroidManifest.xml,我手动更改为Test.class添加第二个Activity:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example" android:versionCode="1" android:versionName="1.0">
<supports-screens android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="21"/>
<application android:label="APP" android:name="android.support.multidex.MultiDexApplication" android:icon="@mipmap/ic_launcher">
<activity android:name="javafxports.android.FXActivity" android:label="Main" android:configChanges="orientation|screenSize">
<meta-data android:name="main.class" android:value="com.example.Launcher"/>
<meta-data android:name="debug.port" android:value="0"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.example.Test"
android:label="Test"
android:configChanges="orientation|screenSize">
</activity>
</application>
</manifest>
实例化MainActivity时,它会崩溃“无法创建没有Looper.prepare()的句柄”。未显式创建句柄,因此不清楚引用了哪个句柄。解决方案:创建一个looper然后再创建 实例化破坏它。只有在崩溃时才能发出Looper.prepare()。对MainActivity.webView()的后续调用在没有Looper的情况下工作。这是我的代码:
Looper.prepare();
new MainActivity();
Looper.myLooper().quitSafely();