简体   繁体   English

从JavaFXPorts Webview访问本机android.webkit.WebView实例

[英]Access to native android.webkit.WebView instance from JavaFXPorts Webview

I want to implement java-to-javascript method call via 我想通过实现java-to-javascript方法调用

WebView.getEngine().executeScript("browserMessagingServicePush('Push data from Java to JS')");

on Android using javafxports 8.60.9, but got 在使用javafxports 8.60.9的Android上,但是

java.lang.UnsupportedOperationException: Not supported yet.
...
at javafx.scene.web.WebEngine.executeScript(WebEngine.java:860)

exception. 例外。

How can I get reference to Android's native WebView to implement something like this? 我如何引用Android的本地WebView来实现类似的功能?

WebView.addJavascriptInterface(new JSInterface(), "JSInterface");

Or there is some other workaround? 还是有其他解决方法?

SOLUTION

I found a solution to executing JavaScript using Android native WebView (and not using JavaFX WebView) from a JavaFXPorts application: 我找到了从JavaFXPorts应用程序使用Android本机WebView(而不使用JavaFX WebView)执行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
                }
            });
        }
    };

}

I invoke this class using: 我使用以下方法调用此类:

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

I copied "Implements NativeService" as declared on my class statement from Handling Android Native Activities like a Pro though this isn't absolutely necessary to make this work. 我从像Pro那样处理Android本机活动中复制了我的类声明中声明的“ Implements NativeService”,尽管这样做并非绝对必要。 When trying to implement JavaFX WebView (as opposed to Android Native WebView) with this JavaFX WebView code: 当尝试使用此JavaFX WebView代码实现JavaFX WebView(与Android Native WebView相对)时:

Document doc = webEngine.getDocument();
getTitle(webView.getEngine());
String html = (String) webView.getEngine().executeScript("document.documentElement.outerHTML");

I got either nulls or "not supported yet" when running on Android though the code worked OK on desktop. 在Android上运行时,尽管代码在桌面上运行正常,但我还是得到了null或“尚不支持”。 (Haven't tried yet on IOS but I want to implement too here). (还没有在IOS上尝试过,但是我也想在这里实现)。 I want to retrieve the webpage title and execute javascript to retrieve other data from a webpage. 我想检索网页标题并执行javascript来检索网页中的其他数据。 And so my solution was to use Android Native WebView instead of JavaFX WebView when running on Android. 因此,我的解决方案是在Android上运行时使用Android Native WebView而不是JavaFX WebView。 Here's my complete code: 这是我完整的代码:

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

}

Although I have successfully displayed the desired webpage, retrieved the title and executed some JavaScript, I am struggling to close the webpage and return to the JavaFX stage. 尽管我已经成功显示了所需的网页,检索了标题并执行了一些JavaScript,但我仍在努力关闭网页并返回JavaFX阶段。 My 2 callbacks above onBackPressed() and OnClickListener don't work and are not invoked (can't see the System.out.println ). 我在onBackPressed()OnClickListener上面的2个回调不起作用,也不会被调用(看不到System.out.println )。 You can see from above I am trying and struggling to use these alternatives: 您可以从上面看到我正在努力使用这些替代方法:

  • webView.goBack();
  • stage.show(); // get error java.lang.IllegalStateException: Not on FX application thread; currentThread = main
  • FXActivity.getInstance().finish();

But I am only managing to terminate the whole app rather than return to the JavaFX stage (even though I am passing it's value into this class). 但是我只是设法终止整个应用程序,而不是返回到JavaFX阶段(即使我将其值传递给此类)。 Any thoughts? 有什么想法吗?

PS : Looper.prepare(); PSLooper.prepare(); is necessary to be able to invoke this code though I don't understand what I am doing here? 尽管我不明白我在这里做什么,但是必须能够调用此代码?

Update on Solution 解决方案更新

I found a solution to executing JavaScript using Android native WebView (and not using JavaFX WebView) from a JavaFXPorts application - see code below. 我从JavaFXPorts应用程序中找到了使用Android本机WebView(而不使用JavaFX WebView)执行JavaScript的解决方案-请参见下面的代码。 I solved the navigation to and from my JavaFX stage and Android WebView (in my 1st answer on 25 February 2018) by using 2 Activities: my main activity (JavaFX Stage) invokes a 2nd Activity (Android WebView) and passes the URL I want to display and when the 2nd Activity finishes it passes back a result string. 我通过使用2个活动解决了往返JavaFX阶段和Android WebView的导航(在2018年2月25日我的第一个答案):我的主要活动(JavaFX Stage)调用了第二个活动(Android WebView)并传递我想要的URL显示,并且第二个活动完成时,它将传回结果字符串。 You can exit the 2nd Activity by executing finish() or using the back button. 您可以通过执行finish()或使用“后退”按钮退出第二活动。 You need to add an additional entry in the AndroidManifest.xml for the 2nd Activity. 您需要在AndroidManifest.xml中为第二个活动添加一个附加条目。

Here's my main activity: 这是我的主要活动:

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

    }
}

Here's my 2nd Activity (Android WebView): 这是我的第二个活动(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
                        }
                      }
             });
    }
    };

}

Here's my AndroidManifest.xml which I manually changed to add the 2nd Activity for Test.class: 这是我手动更改的AndroidManifest.xml,为Test.class添加了第二个活动:

<?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>

When instantiating MainActivity it crashes with "can't create a handle without a Looper.prepare()". 实例化MainActivity时,它崩溃并显示为“没有Looper.prepare()无法创建句柄”。 A handle is not explicitly created and so it's not clear which handle is referenced. 没有显式创建一个句柄,因此不清楚引用哪个句柄。 Solution: create a looper and then after instantiation destroy it. 解决方案:创建一个循环程序,然后在实例化后销毁它。 You can only issue Looper.prepare() once otherwise it crashes. 您只能发出Looper.prepare()一次,否则它将崩溃。 Subsequent calls to MainActivity.webView() work without Looper. 随后对MainActivity.webView()的调用无需Looper。 Here's my code: 这是我的代码:

Looper.prepare();
new MainActivity();
Looper.myLooper().quitSafely();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 充气错误 class android.webkit.WebView - Error inflating class android.webkit.WebView 加载webview时出错类android.webkit.WebView时出错 - Error inflating class android.webkit.WebView when loading webview 如何使用Appium以字符串形式获取android.webkit.WebView内容 - How to get the android.webkit.WebView contents as a String using Appium 在 android 5 上膨胀类 android.webkit.WebView 时出错 - Error inflating class android.webkit.WebView on android 5 android.webkit.WebView无法转换为android.widget.Button - android.webkit.WebView cannot be cast to android.widget.Button Android.Webkit.WebView not load url in Xamarin.Android - Android.Webkit.WebView not load url in Xamarin.Android 在没有loadUrl或XHR的情况下在android.webkit.WebView中执行javascript代码 - execute javascript code in an android.webkit.WebView without loadUrl or XHR 错误膨胀类 android.webkit.WebView 在生产中偶尔发生 - Error inflating class android.webkit.WebView happens sporadically in production 缩放在 android.webkit.WebView 中如何工作? - How does zoom work in android.webkit.WebView? webview.java中的NullPointerException(android.webkit.WebView $ PrivateHandler.handleMessage) - NullPointerException in webview.java (android.webkit.WebView$PrivateHandler.handleMessage)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM