Giter Site home page Giter Site logo

webview_java's Introduction

Webview

The Java port of the webview project. It uses JNA and auto-extracts the required dll/dylib/so libraries for your current system.

browser

Examples

Example
Bridge Example

Supported Platforms

x86, x86_64
aarch64, x86_64
x86, x86_64, arm, aarch64

Linux

Both MUSL and GLibC are supported out of the box. So it should work fine under distros like Debian, Arch, and Alpine.

macOS

macOS requires that all UI code be executed from the first thread, which means you will need to launch Java with -XstartOnFirstThread. This also means that the Webview AWT helper will NOT work at all.

Getting the code

Replace _VERSION with the latest version or commit in this repo. If you want the Bridge bindings you'll need both core and bridge.

Maven
<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.webview.webview_java</groupId>
    <artifactId>core</artifactId>
    <version>_VERSION</version>
</dependency>
Gradle
allprojects {
  repositories {
    maven { url 'https://jitpack.io' }
  }
}

dependencies {
  implementation 'com.github.webview.webview_java:core:_VERSION'
}
SBT
resolvers += "jitpack" at "https://jitpack.io"

libraryDependencies += "com.github.webview.webview_java" % "core" % "\_VERSION"
Leiningen
:repositories [["jitpack" "https://jitpack.io"]]

:dependencies [[com.github.webview.webview_java/core "_VERSION"]]

webview_java's People

Contributors

e3ndr avatar faveoled avatar wannesimon avatar yairlevi avatar zerofancy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

webview_java's Issues

Doesn't run out of the box on Ubuntu (not found, then blank window)

I tried running the release (1.3.0) on Ubuntu 23.04. I have managed to make it show something now.

Expected behavior:

Running example.java shows Google.com

Observed behavior:

First attempt:

Screenshot from 2024-01-28 22-40-45

WebViewNative seems to put the .so file in the working directory, and its not found there. Seems like it needs to be under linux-x86-64/ in a the native search path. IIRC there is an argument that can be used to specify the search path, so that would be easy enough to overcome.

Second attempt:

Webview comes up blank. Seems to be related to this: https://groups.google.com/g/linux.debian.bugs.dist/c/jqFSXiFozd4

Setting the environment variable suggested on the thread there

WEBKIT_DISABLE_DMABUF_RENDERER=1

Makes it work.

Can I repace of 'Json' with other json tool ?

I try to use jackson , but there's a problem,
it seems that complex-object can not be passed to js.

This example binds 3 function ,
await echo("1", "2") , await a() , await b("1") all worked.
await list() doesn't return anything.

Main.java

    public static void main(String[] args) {
        Webview wv = new Webview(true);
        wv.setTitle("My Webview App");
        wv.setSize(200, 100);

        bindsJackson(wv);
        wv.loadURL("https://baidu.com");
        wv.run();
    }

    public static void bindsJackson(Webview wv) {
        // await echo("1", "2")  yes
        wv.bind("echo", (arr) -> {
            return arr;
        });
        // await a()  yes
        wv.bind("a", (arr) -> {
            return "a"; // jackson
//            return Rson.DEFAULT.toJson("a"); // Json
        });
        // await b("1")  yes
        wv.bind("b", (arr) -> {
            arr.add("b");
            return arr;
        });

        // await list().   Nothing return in js, but 'listImage' has been invoked.
        wv.bind("list", (arr) -> {
//            List<CusFileInfo> list = listImage("D:\\Picture");
            List<CusFileInfo> list = listImage("/");
            return list; // jackson
//            return Rson.DEFAULT.toJson(list); //Json
        });
    }

    public static List<CusFileInfo> listImage(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return new ArrayList<>();
        }

        File[] fs = file.listFiles();
        List<CusFileInfo> collect = Arrays.stream(fs).map(e -> {
            String ext = null;
            String name = e.getName();
            int index = name.lastIndexOf('.');
            if ( index > 0 && index!=name.length()-1 ) {
                ext = name.substring(index+1);
            }

            return new CusFileInfo(e.getName(), e.length(), e.isDirectory(),
                    e.getAbsolutePath(), ext);
        }).collect(Collectors.toList());
        return collect;
    }

bind has been rewrite.
WebView.java

    ...
    public void bind(String name, Function<ArrayNode, Object> handler) {
        ObjectMapper mapper = new ObjectMapper();

        N.webview_bind($pointer, name, new BindCallback() {
            @Override
            public void callback(long seq, String req, long arg) {
                    try {
                        ArrayNode arrReq = (ArrayNode) mapper.readTree(req);
                        Object result = handler.apply(arrReq);

                        String jsonRes = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(result);
                        System.out.println("jsonRes: " + jsonRes );
                        N.webview_return($pointer, seq, false, jsonRes);
                    } catch (Exception e) {
                        N.webview_return($pointer, seq, true, e.getMessage());
                        e.printStackTrace();
                    }
            }
        }, 0);
    }
    ...

CusFileInfo.java

@JsonClass(exposeAll = true)
public class CusFileInfo {
    public String name;
    public Long size;
    public Boolean isDir;
    public String path;
    public String ext;
    
   ... getters setters   
}

others:
jdk-17.0.4.1
window10
Idea 2022.2.1

Updated code doesn't compile, missing method

The code was updated two days ago, but SwingExample.java doesn't even compile, it's calling AWTWebview.setOnInitialized() which doesn't exist.

Tried to create a dummy setOnInitialized() to by-pass the issue to ran SwingExample, but got "java.lang.Error: Invalid memory access" using the provided dll.

Appreciate if the complete/working sample could be provided.

Interacting with the webview from a different thread

Hello, what is the recomended way to interact with the webview from a different thread?

Imagine the following use case:

  • Start the java application and spawn a new thread to do some slow operation
  • Start the webview on the main thread
  • Slow operation on background thread finishes
  • How to notify the webview of this?

Since webview.eval cannot be used from a different thread I'm currently doing this from the background thread:

webview.dispatch( () ->{
   webview.eval(etc);
}) ;

This is currently working for me but it has one problem. When calling webview.eval() inside webview.dispatch(), java functions that were binded with webview.bind() do not run. For example if my "etc" variable there contains some javascript code that calls a function that I binded with webview.bind, it wont call the java side. I also noticed on the code it says dispatch is deprecated so I dont understand if there is another way to do this type of thing, or if its planned for the future.

Jackson and Webview compatibility issue

I'm trying use this webview lib and jackson together for something, and I found out that the moment I use Jackson somewhere in the code, webview function binds dont work (like the echo(1,2,3) from the example).

I believe there is some incompatibility between the two libs, which somewhat makes sense since both jackson and webview binds interact with json related stuff.

Is there a way to fix it without an alternative to Jackson?
and moreover, does anyone else have some knowledge or experienced this issue?

Bound java methods stop being called if one of them recursively iterates through the file system?

Ok so this issue is pretty weird, but I've noticed if one of my bound methods ( set up through webview.bind ) recursively iterates through the file system, all other methods that I've bound with webview.bind stop being called. I know it sounds crazy but it's happening. Here's some code to reproduce:

    static int foldersCounted = 0;
    static int folderCountLimit = 8000;

    public static void main(String[] args) throws InterruptedException {

        Webview wv = new Webview(true);

        wv.bind("test", (arguments) -> {
            System.out.println("test called");
            return null;
        });

        wv.bind("onPageReady", (arguments) -> {
            System.out.println("onPageReady called");
            long start = System.currentTimeMillis();
            countFolders(new File("C:\\"));
            long end = System.currentTimeMillis();

            System.out.println("done " + (end - start));
            return null;
        });

        wv.setTitle("My Webview App");
        wv.setSize(800, 600);

        wv.loadURL("file:///C:/index.html");
        wv.run();
        wv.close();
    }

    private static void countFolders(File dir) {
        if (foldersCounted > folderCountLimit) {
            return;
        }

        File[] lstFiles = dir.listFiles();
        if (lstFiles != null) {
            for (File file : lstFiles) {
                if (file.isDirectory()) {
                    foldersCounted++;
                    countFolders(file);
                }
            }
        }
    }

index.html

<!DOCTYPE html>
<html >

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Page Title</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>

<body >
	test
    <script>

        document.addEventListener("DOMContentLoaded", () => {
	    //we wait 500ms for the functions to be bound in java
	   setTimeout(() => {
		onPageReady();
		setTimeout(() => {
		   alert("calling test");
		   test(); //we reach here, but this call never reaches java
		}, 3000);
	   }, 500);
		
        });
    </script>
</body>

</html>

The code above calls onPageReady successfully, and 3 seconds later calls the test() function, but this call never reaches java. I've found that if I remove the call to countFolders() on the java side the issue does not happen. It also does not happen if you reduce the value of the variable folderCountLimit to something like 100 or so. If you cant reproduce this issue with the code above, increase the value of folderCountLimit to a high value and you'll eventually be able to reproduce it. Even if I await each call to onPageReady() and test(), the issue still happens. It also happens even when I wrap countFolders() in a new thread.

At first I thought, maybe this is just an issue with the bound method being too slow, so I tried to reproduce the issue just using a Thread.sleep instead of calling countFolders(), but with Thread.sleep the issue never happens, so it seems to be related to something else.

I'm using version 1.3.0

Swing Example Crashes

The error is posted below. This happens when just running the Swing example from this repo.

Exception in thread "Thread-0" java.lang.Error: Invalid memory access at com.sun.jna.Native.invokeLong(Native Method) at com.sun.jna.Function.invoke(Function.java:431) at com.sun.jna.Function.invoke(Function.java:364) at com.sun.jna.Library$Handler.invoke(Library.java:270) at dev.webview.webview_java.$Proxy0.webview_create(Unknown Source) at dev.webview.webview_java.Webview.<init>(Webview.java:193) at dev.webview.webview_java.Webview.<init>(Webview.java:185) at dev.webview.webview_java.Webview.<init>(Webview.java:177) at dev.webview.webview_java.Webview$1.lambda$paint$0(Webview.java:77) at java.base/java.lang.Thread.run(Thread.java:833)

Fix warning and error messages in BridgeScript.js

NetBeans shows some warning messages in BridgeScript.js mostly because of the use of == and != instead of === and !==. « typeof » already returns a string, there is no need to perform an implicit conversion.

The problems are here :
https://github.com/webview/webview_java/blob/main/bridge/src/main/resources/dev/webview/webview_java/bridge/BridgeScript.js#L1 (return statement outside a function)
https://github.com/webview/webview_java/blob/main/bridge/src/main/resources/dev/webview/webview_java/bridge/BridgeScript.js#L13 (useless implicit conversion)
https://github.com/webview/webview_java/blob/main/bridge/src/main/resources/dev/webview/webview_java/bridge/BridgeScript.js#L87 (useless implicit conversion)
https://github.com/webview/webview_java/blob/main/bridge/src/main/resources/dev/webview/webview_java/bridge/BridgeScript.js#L97 (missing semicolon)

Those « problems » don’t prevent the project from working but maybe relying on such behaviours is a bad idea on a long term.

Can't find native library in Linux

OS: Debian GNU/Linux 12 (bookworm) x86_64
Kernel: 6.1.0-18-amd64
DE: Plasma 5.27.5

I cloned the project and run example project, and got an error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'webview':
libwebview.so: 无法打开共享对象文件: 没有那个文件或目录
libwebview.so: 无法打开共享对象文件: 没有那个文件或目录
Native library (linux-x86-64/libwebview.so) not found in resource path (/home/zero/IdeaProjects/webview_java/examples/target/classes:/home/zero/IdeaProjects/webview_java/bridge/target/classes:/home/zero/.m2/repository/co/casterlabs/commons/async/1.7.0/async-1.7.0.jar:/home/zero/.m2/repository/co/casterlabs/rson/1.17.9/rson-1.17.9.jar:/home/zero/IdeaProjects/webview_java/core/target/classes:/home/zero/.m2/repository/co/casterlabs/commons/platform/1.7.0/platform-1.7.0.jar:/home/zero/.m2/repository/co/casterlabs/commons/io/1.7.0/io-1.7.0.jar:/home/zero/.m2/repository/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar:/home/zero/.m2/repository/net/java/dev/jna/jna-platform/5.14.0/jna-platform-5.14.0.jar:/home/zero/.m2/repository/org/openjfx/javafx-base/19.0.2.1/javafx-base-19.0.2.1.jar:/home/zero/.m2/repository/org/openjfx/javafx-base/19.0.2.1/javafx-base-19.0.2.1-linux.jar:/home/zero/.m2/repository/org/openjfx/javafx-graphics/19.0.2.1/javafx-graphics-19.0.2.1.jar:/home/zero/.m2/repository/org/openjfx/javafx-graphics/19.0.2.1/javafx-graphics-19.0.2.1-linux.jar)
	at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:325)
	at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:481)
	at com.sun.jna.Library$Handler.<init>(Library.java:197)
	at com.sun.jna.Native.load(Native.java:618)
	at dev.webview.webview_java.WebviewNative.runSetup(WebviewNative.java:108)
	at dev.webview.webview_java.WebviewNative.<clinit>(WebviewNative.java:46)
	at dev.webview.webview_java.Webview.<init>(Webview.java:140)
	at dev.webview.webview_java.Webview.<init>(Webview.java:132)
	at dev.webview.webview_java.Webview.<init>(Webview.java:79)
	at dev.webview.webview_java.example.direct.Example.main(Example.java:8)
	Suppressed: java.lang.UnsatisfiedLinkError: libwebview.so: 无法打开共享对象文件: 没有那个文件或目录
		at com.sun.jna.Native.open(Native Method)
		at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:213)
		... 9 more
	Suppressed: java.lang.UnsatisfiedLinkError: libwebview.so: 无法打开共享对象文件: 没有那个文件或目录
		at com.sun.jna.Native.open(Native Method)
		at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:226)
		... 9 more
	Suppressed: java.io.IOException: Native library (linux-x86-64/libwebview.so) not found in resource path (/home/zero/IdeaProjects/webview_java/examples/target/classes:/home/zero/IdeaProjects/webview_java/bridge/target/classes:/home/zero/.m2/repository/co/casterlabs/commons/async/1.7.0/async-1.7.0.jar:/home/zero/.m2/repository/co/casterlabs/rson/1.17.9/rson-1.17.9.jar:/home/zero/IdeaProjects/webview_java/core/target/classes:/home/zero/.m2/repository/co/casterlabs/commons/platform/1.7.0/platform-1.7.0.jar:/home/zero/.m2/repository/co/casterlabs/commons/io/1.7.0/io-1.7.0.jar:/home/zero/.m2/repository/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar:/home/zero/.m2/repository/net/java/dev/jna/jna-platform/5.14.0/jna-platform-5.14.0.jar:/home/zero/.m2/repository/org/openjfx/javafx-base/19.0.2.1/javafx-base-19.0.2.1.jar:/home/zero/.m2/repository/org/openjfx/javafx-base/19.0.2.1/javafx-base-19.0.2.1-linux.jar:/home/zero/.m2/repository/org/openjfx/javafx-graphics/19.0.2.1/javafx-graphics-19.0.2.1.jar:/home/zero/.m2/repository/org/openjfx/javafx-graphics/19.0.2.1/javafx-graphics-19.0.2.1-linux.jar)
		at com.sun.jna.Native.extractFromResourcePath(Native.java:1141)
		at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:297)
		... 9 more

Process finished with exit code 1

It seems that the native library is placed to a wrong path, so I tried to make a copy of it, which works very well.

image

DOMContentLoaded not triggered when window launches without focus, aka in the background

@e3ndr I'm on Windows 10, with the latest webview_java, which uses the Edge webview internally it seems.
Here is my code:

    public void init(String startURL, boolean isTransparent, int widthPercent, int heightPercent) throws Exception {
        AtomicBoolean isLoaded = new AtomicBoolean(false);
        onLoadStateChanged.addAction((action, isLoading) -> {
            if (!isLoading) {
                action.remove();
                isLoaded.set(true);
            }
        }, Exception::printStackTrace);

        frame = new JFrame();

        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        // Using createAWT allows you to defer the creation of the webview until the
        // canvas is fully renderable.
        browserDesktopUI = Webview.createAWT(true, (wv) -> {
            browser = wv;

            wv.setInitScript("  document.addEventListener(\"DOMContentLoaded\", () => {\n" +
                    "      window.tellJavaThatIsLoaded().then(result => {\n" +
                    "      });\n" +
                    "    });");
            wv.bind("tellJavaThatIsLoaded", e -> {
                onLoadStateChanged.execute(false); // stopped loading
                return null;
            });
            wv.loadURL(startURL);

            // Resize browser window too
            frame.addComponentListener(new ComponentAdapter() {
                @Override
                public void componentResized(ComponentEvent e) {
                    wv.dispatch(() -> {
                        wv.setSize(e.getComponent().getWidth(), e.getComponent().getHeight());
                    });
                    frame.revalidate();
                }
            });

            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    close();
                }
            });

            // Run the webview event loop, the webview is fully disposed when this returns.
            wv.run();
        });

        frame.getContentPane().add(browserDesktopUI, BorderLayout.CENTER);
        if (widthPercent <= 0 || heightPercent <= 0) {
            widthPercent = 100;
            heightPercent = 100;
        }
        width(widthPercent);
        height(heightPercent);
        frame.setIconImage(App.getIcon());
        frame.setTitle(App.name);
        Swing.center(frame);
        frame.revalidate();
        frame.setFocusable(true);
        frame.setVisible(true);
        frame.requestFocus();

        // JavaScript cannot be executed before the page is loaded
        while (!isLoaded.get()) Thread.yield();
    }

This issue arises from another issue, namely knowing once the HTML finished loading to safely execute JavaScript.

eval("console.log('hello world!')") is not work

wv.evall("console.log('hello world!')") used by java.

public static void main(String[] args) {
Webview wv = new Webview(true); // Can optionally be created with an AWT component to be painted on.

    // Calling `await echo(1,2,3)` will return `[1,2,3]`
    wv.bind("echo", (arguments) -> {
        return arguments;
    });

    wv.setTitle("My Webview App");
    wv.setSize(800, 600);

    String url = "file:\\\\C:\\mansiExe\\client\\device\\customer\\nwcn-touyinji\\html\\index.html";
    wv.loadURL(url);


    // Run the webview event loop, the webview is fully disposed when this returns.
    new Thread(new Runnable() {
        @Override
        public void run() {
            Scanner sc=new Scanner(System.in);
            String word;
            //定义while控制循环输入
            System.out.println("请输入任意内容(输入exit就退出,否则继续输入):");
            while (true) {
                //键盘接收数据
                word=sc.nextLine();
                //判断接收的数据是否为"exit"
                wv.eval("console.log(11)} ");


                if (word.equals("exit")) {
                    //如果是,提示退出输入
                    System.out.println("退出输入!");
                    //跳出循环
                    break;
                }else {//如果不是,提示继续输入
                    System.out.println("请继续输入:");
                }
            }
        }
    }).start();

    wv.run();

}

when i press anykey, the java log can printf ,but the javascript is not ecxe.

Show nothing on MacOS, no error thrown.

Same issue in WebviewKo

OS: macOS 14.3.1 23D60 arm64
Kernel: 23.3.0
JVM: azul-1.8.0_392

To rule JNA reasons, I tried to write a JNI demo, but no miracle happens.

JNIEXPORT void JNICALL Java_top_ntutn_WebViewJNI_launchAndWait(JNIEnv *env, jobject obj, jstring url) {
    std::cout << "Well begin" << std::endl;
    webview::webview w(true, nullptr);
    std::cout << "Generated" << std::endl;
    w.set_title("Basic Example");
    w.set_size(480, 320, WEBVIEW_HINT_NONE);
    w.set_html("Thanks for using webview!");
    std::cout << "Half done" << std::endl;
    w.run();
}

I tried to add some log to find the position it stucks at:

image

And here is the log:

/Users/bytedance/IdeaProjects/webview-kt-wrapper/src/main/resources
Hello World from CPP
Well begin
Reach 2
Reach 4
Reach 5

I can do nothing more with my poor native development knowledge now.

Component attempts to resize to original size whenever resized

Whenever attempting to resize the Webview component in Swing, the original size is always used rather than any new sizes, a workaround to this is to add a component listener for componentResized on the panel your component is on, but this still yields ugly flashing due to it resizing to the original size before going to the new one.

It completely avoids resizing if the vertical or horizontal values are < the new size, only if both are > than

This video shows the issue I am having (panel color set to red to better show the problem)
https://youtu.be/u-33R8BJLHk

webview.eval() doesnt work when string contains java variables

after calling run(), and waiting for the page to load,
i have a bind method that calls eval(). but eval() doesnt execute on the frontend if i add a parameter as part of the string argument that eval() receives. here is code to reproduce:

       // This code doesn't work, the frontend doesn't log anything, not even an error.
        wv.bind("echo", jsonElements -> {
            String s = "hello world";
            wv.eval("console.log('"+s+"');");
            return jsonElements;
        });

       // This code works perfectly.
        wv.bind("echo", jsonElements -> {
            wv.eval("console.log('hello world');");
            return jsonElements;
        });

it seems like raw strings work but parameters break something. any idea why that is?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.