JavaFX stop opening URL in WebView - open in browser instead

前端 未结 9 1230
無奈伤痛
無奈伤痛 2020-12-09 05:12

The embedded WebView browser I am using needs special handling for particular URLs, to open them in the native default browser instead of WebView. The actual browsing part w

相关标签:
9条回答
  • 2020-12-09 06:06

    @Avrom's answer of using DOM interceptors offers a better solution than this answer with regards to the question: "JavaFX stop opening URL in WebView - open in browser instead".

    This answer just left for posterity.


    Use option 1 engine.load(oldValue) and wrap the load call in Platform.runLater as a workaround to prevent the jvm crash.

    import javafx.application.*;
    import javafx.beans.value.*;
    import javafx.scene.Scene;
    import javafx.scene.web.*;
    import javafx.stage.Stage;
    
    public class GoogleBlock extends Application {
      public static void main(String[] args) throws Exception { launch(args); }
    
      @Override public void start(final Stage stage) throws Exception {
        final WebView webView = new WebView();
        final WebEngine engine = webView.getEngine();
        engine.load("http://www.google.com");
        engine.locationProperty().addListener(new ChangeListener<String>() {
          @Override public void changed(ObservableValue<? extends String> ov, final String oldLoc, final String loc) {
            if (!loc.contains("google.com")) {
              Platform.runLater(new Runnable() {
                @Override public void run() {
                  engine.load(oldLoc);
                }
              });
            }
          }
        });
    
        stage.setScene(new Scene(webView));
        stage.show();
      }
    }
    

    Update

    Although the above solution works OK for me in the supplied GoogleBlock sample application under jdk7u15, win7, Dreen reports that just wrapping the load value in Platform.runLater does not fix crash issues in all cases, so the complete replacement of the WebView object with a new WebView (as Dreen outlines in the updated question), might be the preferred solution here (at least until the underlying bug is fixed).


    The jvm crash you note in your question is a known issue in JavaFX 2.2:

    JDK-8087652 WebView crashes on calling webEngine.load(url) in a webEngine.locationProperty() ChangeListener.

    0 讨论(0)
  • 2020-12-09 06:08

    This worked for me as I had to generically trap any anchor with target="_blank". I had to work around the fact that the PopupFeatures callback has absolutely no useful context by asking the DOM for all elements under the pointer (e.g. :hover).

    // intercept target=_blank hyperlinks
    webView.getEngine().setCreatePopupHandler(
        new Callback<PopupFeatures, WebEngine>() {
            @Override
            public WebEngine call(PopupFeatures config) {
                // grab the last hyperlink that has :hover pseudoclass
                Object o = webView
                        .getEngine()
                        .executeScript(
                                "var list = document.querySelectorAll( ':hover' );"
                                        + "for (i=list.length-1; i>-1; i--) "
                                        + "{ if ( list.item(i).getAttribute('href') ) "
                                        + "{ list.item(i).getAttribute('href'); break; } }");
    
                // open in native browser
                try {
                    if (o != null) {
                        Desktop.getDesktop().browse(
                                new URI(o.toString()));
                    } else {
                        log.error("No result from uri detector: " + o);
                    }
                } catch (IOException e) {
                    log.error("Unexpected error obtaining uri: " + o, e);
                } catch (URISyntaxException e) {
                    log.error("Could not interpret uri: " + o, e);
                }
    
                // prevent from opening in webView
                return null;
            }
        });
    
    0 讨论(0)
  • 2020-12-09 06:11

    Your "update" section is actually really close to what I got to work, no workaround needed:

    wv.getEngine().locationProperty().addListener(new ChangeListener<String>() {    
                public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
                {
                    if((address.getQuery() + "").indexOf("_openmodal=true") > -1) {
                        Platform.runLater(new Runnable() {
                            public void run() {
                                try {
                                    Desktop.getDesktop().browse(new URI(newValue));
                                } catch (IOException e) { //Decide how to handle:
                                    //Can't find default program handler for link.
                                } catch (URISyntaxException e) {
                                    //Bad syntax on link.
                                }
                                wv.getEngine().reload();
                            }
                        });
                    }
                }
    
            });
    

    What I like about this method is that it accounts for a URL coming from more than just a hyperlink element as well as links to things like emails or local files.

    0 讨论(0)
提交回复
热议问题