Codenameone Codename One-BrowserComponent:使用后退按钮返回历史记录

Codenameone Codename One-BrowserComponent:使用后退按钮返回历史记录,codenameone,Codenameone,已更新 我尝试在Android设备上使用BrowserComponent:如果我按下设备的后退按钮,应用程序将什么也不做(使用以下代码) 在这个问题中,我复制了代码中相关的部分 我的问题是,如果有人能提供一个示例,说明当按下后退按钮时,执行页面中声明的javascript函数的工作代码(特别是转到上一页的函数)。请注意,我需要setBrowserNavigationCallback(如下代码所示) 如果有人能更正代码以正确使用setURLHierarchy,我也很感激,因为它会使模拟器崩溃,并且

已更新

我尝试在Android设备上使用BrowserComponent:如果我按下设备的后退按钮,应用程序将什么也不做(使用以下代码)

在这个问题中,我复制了代码中相关的部分

我的问题是,如果有人能提供一个示例,说明当按下后退按钮时,执行页面中声明的javascript函数的工作代码(特别是转到上一页的函数)。请注意,我需要
setBrowserNavigationCallback
(如下代码所示)

如果有人能更正代码以正确使用
setURLHierarchy
,我也很感激,因为它会使模拟器崩溃,并且不会在真实设备上加载“/community.html”

非常感谢你的帮助


更新:这是我的代码的最新版本

public void start() {
    if (current != null) {
        current.show();
        return;
    }
    Form hi = new Form("Community", new BorderLayout());

    // Suppress Android native indicator
    Display.getInstance().setProperty("WebLoadingHidden", "true");

    // Create the BrowserComponent
    browser = new BrowserComponent();

    // Set user-agent
    browser.setProperty("useragent", appAgent);

    // Set the start page - TO CORRECT, it's messy
    if (Display.getInstance().isSimulator()) {
        // I added this condition because opening a local html page
        // causes that the Simulator crashes
        browser.setURL(startPage_development);
        Log.p("BrowserComponet setUrl: " + startPage_development);
    } else {

        try {
            if (!Display.getInstance().isSimulator()) {
                browser.setURLHierarchy("/community.html");
            } else {
                browser.setURLHierarchy("/testing.html");
            }
            Log.p("BrowserComponet setURLHierarchy successfully");
        } catch (Exception err) {
            Log.e(err);
            browser.setURL(startPage);
            Log.p("BrowserComponet setUrl: " + startPage);
        }
    }

    // Javascript Bridge for back command
    JavascriptContext context = new JavascriptContext(browser);
    // JSObject document = (JSObject) context.get("document");
    JSObject window = context.getWindow();
    hi.setBackCommand(new Command("Back") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            //window.call("goBackButton()");
            window.call("eval", new Object[]{"history.go(-1);"});
        }
    });

    // Allow browsing only inside my domains
    browser.setBrowserNavigationCallback((url) -> {
        if (url.startsWith("javascript")
                || url.startsWith(url_Root_development)
                || url.startsWith(url_Root_production)
                || url.startsWith(loginRoot)) {
            return true; // the BrowserComponent should navigate
        } else {
            Display.getInstance().callSerially(() -> {
                // it opens the url with the native platform
                Boolean can = Display.getInstance().canExecute(url);
                if (can != null && can) {
                    Display.getInstance().execute(url);
                }
            });
            return false; // the BrowserComponent shouldn't navigate
        }
    });

    hi.add(BorderLayout.CENTER, browser);
    hi.show();
}

使用
setBackCommand
覆盖后退按钮行为,并设置您可能拥有的任何业务逻辑,包括对JavaScript代码的调用。

我感谢Shai的建议,但它们不足以获得一个工作代码和工作模拟器(在这种情况下,按escape没有任何作用,我不理解在这种情况下使用断点的意义)我不需要浏览器组件,因为我需要使用更复杂的方法,即调用我编写的javascript函数,使浏览器仅在Internet连接可用时返回(或显示Internet不可用的消息)

因此,这就是为什么我试图自己回答这个问题,将问题分解为几个步骤。我花了几天时间和大量精力来解决一个如此简单的问题(按下后退按钮调用javascript),主要是因为缺少文档(API中包含了几个示例,但不是本例)和崩溃代码名为One的模拟器的(和奇怪的行为),如下文所述

我希望能帮助其他人分享我所做的事情

步骤1:使用BrowserComponent加载本地页面

我用Netbeans创建了一个新的空代码名One项目,我给它命名为“myBrowser”,包名为“it.galgani.demos.myBrowser”,主类名为“myBrowser”,主题为“native”,模板为“Hello world(裸体)”

我修改了默认的
start()
方法,以便:

   public void start() {
        if(current != null){
            current.show();
            return;
        }
        Form hi = new Form("MyBrowser", new BorderLayout());

        // Create the BrowserComponent
        BrowserComponent browser = new BrowserComponent();

        try {
            // Load a web page placed in the "html" package
            browser.setURLHierarchy("/index.html");
            Log.p("setURLHierarchy executed");
        } catch (IOException ex) {
            Log.e(ex);
        }

        hi.add(BorderLayout.CENTER, browser);
        hi.show();
    }
然后,我在“源包”中创建了一个名为“html”的新“Java包”。在我的例子中,创建的文件夹是:“/home/francesco/NetBeansProjects/myBrowser/src/html”

在html文件夹中,我创建了这个
index.html
(选择“新建文件”、类别“其他”、文件类型“html”、文件名“索引”):

在模拟器中,“硬件后退”按钮没有反应,工具栏中没有显示后退箭头。经过几次尝试,我意识到
setBackCommand
方法在Form类和toolbar类中实现,具有不同的行为。本文解释了不同之处:

以下是这一步的最终代码,在模拟器和我的真实Android设备中都能正常工作(我在其中测试了硬件后退按钮和材质图标后退箭头):

步骤4:将后退按钮与Javascript桥一起使用

我更改了
backCommand
如下,以调用简单的
writeln
函数,但新代码只工作了几次,其他时候它会使模拟器崩溃,或者干脆什么也没做:

   // Javascript Bridge
    JavascriptContext context = new JavascriptContext(browser);
    JSObject document = (JSObject)context.get("document");

    Command backCommand = new Command("BackButton") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            // browser.back();
            document.call("writeln", new Object[]{"Hello world"});
        }
    };
我怀疑JavascriptContext没有一直正确加载,但我不确定这一点。日志对理解问题没有帮助:

[EDT] 0:0:0,18 - setURLHierarchy executed
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f3a04f944d1, pid=3730, tid=0x00007f3a07cdf700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libjfxwebkit.so+0x11334d1]  checkJSPeer(long, int, OpaqueJSValue*&, OpaqueJSContext const*&)+0x41
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid3730.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
经过一系列(非常长的)尝试和错误来解决这个奇怪的行为之后,我最终以一种在模拟器和真实的Android设备中正常工作的方式更改了代码(注意,我不再使用JavascriptContext类):

诀窍是使用BrowserComponent的(很少有文档记录的)
execute
方法,而不是
JavascriptContext
+
JSObject
类。StackOverflow问题中有此方法的简要说明:

步骤5:使用我的
goBackButton()
javascript函数

我已经在我打算在我的应用程序中使用的网页中实现了
goBackButton()
函数。我只想在javascript引擎已经加载该方法时调用该方法,因为:«
BrowserComponent.execute(String)
将在调用时在浏览器的当前页面中执行提供JS代码段。如果代码段引用了尚未加载的内容,则javascript将导致错误。»

这就是我更改代码的原因:

// Create a command for the Back button
String jsCode = "function goBack() {                        "
        + "    if (typeof goBackButton == 'function') {     "
        + "        window.goBackButton();                   "
        + "    return 'I\\'m invoking goBackButton()';      "
        + "    } else {                                     "
        + "        window.history.go(-1);                   "
        + "        return 'goBackButton() is not available';"
        + "    }                                            "
        + "}                                                "
        + "goBack();                                        ";
Command backCommand = new Command("BackButton") {
    @Override
    public void actionPerformed(ActionEvent evt) {
        Log.p(browser.executeAndReturnString(jsCode));
    }
};
为了进行基本测试,我在page1.html中实现了一个假的goBackButton():

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script>
            function goBackButton() {
                // My js code
                // ...
                history.go(-1);
            }
        </script>
    </head>
    <body>
        <h1>Page 1</h1>
    </body>
</html>
步骤6:使用
setBrowserNavigationCallback

我使用
setBrowserNavigationCallback
只允许在我的域内浏览:在我最初的有缺陷的代码中,我体验到如果我使用
JavascriptContext
+
JSObject
类,那么我必须使用条件
if(url.startsWith(“javascript”))
,因为NavigationCallback是通过点击后退按钮调用的(不要问我为什么,我不知道)。使用
BrowserComponent.execute(String)
我不需要检查url是否以“javascript”开头,因为NavigationCallback从未被javascript调用过

我向index.html添加了两个链接以进行一些检查:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="page1.html">Page 1</a><br />
        <a href="page2.html">Page 2</a><br />
        <a href="page3.html">Page 3</a><br />
        <a href="https://www.google.com/">WebPage 1 (domain not allowed)</a><br />
        <a href="https://www.utiu-students.net/">WebPage2 (domain allowed)</a>
    </body>
</html>
这是日志:

[JavaFX Application Thread] 0:0:2,86 - URL loaded: https://www.google.com/
[JavaFX Application Thread] 0:0:2,87 - Domain of the URL: google.com
[JavaFX Application Thread] 0:0:2,88 - the BrowserComponent cannot navigate
[JavaFX Application Thread] 0:0:3,815 - URL loaded: https://www.google.it/?gfe_rd=cr&ei=avGmWa-YNKnS8AfqlIGoDw
[JavaFX Application Thread] 0:0:3,815 - Domain of the URL: google.it
[JavaFX Application Thread] 0:0:3,815 - the BrowserComponent cannot navigate
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f3ec48044cf, pid=5754, tid=0x00007f3ec7be4700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libjfxwebkit.so+0xa9e4cf]  WebCore::ResourceLoader::willSendRequestInternal(WebCore::ResourceRequest&, WebCore::ResourceResponse const&)+0x53f
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid5754.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
[EDT] 0:0:0,44 - Native Browser Supported
[EDT] 0:0:0,59 - setURLHierarchy executed
[JavaFX Application Thread] 0:0:0,90 - URL: file:///home/francesco/NetBeansProjects/myBrowser/build/classes/html/index.html
[JavaFX Application Thread] 0:0:2,535 - URL: https://www.codenameone.com/
这很糟糕。奇怪的是,谷歌页面被加载了两次,我猜是因为重定向。如果一个用户将指向谷歌的链接替换为指向代码名为“一”的网站的链接,模拟器会停止崩溃……但它会运行
[EDT] 0:0:0,18 - setURLHierarchy executed
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f3a04f944d1, pid=3730, tid=0x00007f3a07cdf700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libjfxwebkit.so+0x11334d1]  checkJSPeer(long, int, OpaqueJSValue*&, OpaqueJSContext const*&)+0x41
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid3730.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
public void start() {
    if (current != null) {
        current.show();
        return;
    }
    Form hi = new Form("MyBrowser", new BorderLayout());

    // Create the BrowserComponent
    BrowserComponent browser = new BrowserComponent();

    try {
        // Load a web page placed in the "html" package
        browser.setURLHierarchy("/index.html");
        Log.p("setURLHierarchy executed");
    } catch (IOException ex) {
        Log.e(ex);
    }

    hi.add(BorderLayout.CENTER, browser);

    // Create a command for the Back button
    Command backCommand = new Command("BackButton") {
        @Override
        public void actionPerformed(ActionEvent evt) {
             browser.execute("document.writeln('Hello world!');");
        }
    };

    hi.getToolbar().setBackCommand(backCommand);
    hi.show();
}
// Create a command for the Back button
String jsCode = "function goBack() {                        "
        + "    if (typeof goBackButton == 'function') {     "
        + "        window.goBackButton();                   "
        + "    return 'I\\'m invoking goBackButton()';      "
        + "    } else {                                     "
        + "        window.history.go(-1);                   "
        + "        return 'goBackButton() is not available';"
        + "    }                                            "
        + "}                                                "
        + "goBack();                                        ";
Command backCommand = new Command("BackButton") {
    @Override
    public void actionPerformed(ActionEvent evt) {
        Log.p(browser.executeAndReturnString(jsCode));
    }
};
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script>
            function goBackButton() {
                // My js code
                // ...
                history.go(-1);
            }
        </script>
    </head>
    <body>
        <h1>Page 1</h1>
    </body>
</html>
[EDT] 0:0:0,28 - setURLHierarchy executed
[EDT] 0:0:4,395 - I'm invoking goBackButton()
[EDT] 0:0:7,736 - goBackButton() is not available
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="page1.html">Page 1</a><br />
        <a href="page2.html">Page 2</a><br />
        <a href="page3.html">Page 3</a><br />
        <a href="https://www.google.com/">WebPage 1 (domain not allowed)</a><br />
        <a href="https://www.utiu-students.net/">WebPage2 (domain allowed)</a>
    </body>
</html>
public void start() {
    if (current != null) {
        current.show();
        return;
    }
    Form hi = new Form("MyBrowser", new BorderLayout());

    // Create the BrowserComponent
    BrowserComponent browser = new BrowserComponent();

    try {
        // Load a web page placed in the "html" package
        browser.setURLHierarchy("/index.html");
        Log.p("setURLHierarchy executed");
    } catch (IOException ex) {
        Log.e(ex);
    }

    hi.add(BorderLayout.CENTER, browser);

    // Create a command for the Back button
    String jsCode = "function goBack() {                        "
            + "    if (typeof goBackButton == 'function') {     "
            + "        window.goBackButton();                   "
            + "    return 'I\\'m invoking goBackButton()';      "
            + "    } else {                                     "
            + "        window.history.go(-1);                   "
            + "        return 'goBackButton() is not available';"
            + "    }                                            "
            + "}                                                "
            + "goBack();                                        ";
    Command backCommand = new Command("BackButton") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            Log.p(browser.executeAndReturnString(jsCode));
        }
    };

    hi.getToolbar().setBackCommand(backCommand);

    // Allow browsing only inside my domains
    String myDomain1 = "127.0.0.1"; // for local server (using simulator)
    String myDomain2 = "utiu-students.net";
    String myDomain3 = "login.uninettunouniversity.net";
    browser.setBrowserNavigationCallback((url) -> {
        Log.p("URL loaded: " + url);
        String domain = ""; // the domain of the url loaded by BrowserComponent
        if (url.startsWith("http")) {
            try {
                domain = (new URI(url)).getHost();
                domain = domain.startsWith("www.") ? domain.substring(4) : domain;
            } catch (URISyntaxException ex) {
                Log.e(ex);
            }
        }
        Log.p("Domain of the URL: " + domain);
        if (url.startsWith("file") 
                || domain.equals(myDomain1)
                || domain.equals(myDomain2)
                || domain.equals(myDomain3)) {
            Log.p("the BrowserComponent can navigate");
            return true; // the BrowserComponent can navigate
        } else {
            Display.getInstance().callSerially(() -> {
                // it opens the url with the native platform
                Boolean can = Display.getInstance().canExecute(url);
                if (can != null && can) {
                    Display.getInstance().execute(url);
                }
            });
            Log.p("the BrowserComponent cannot navigate");
            return false; // the BrowserComponent cannot navigate
        }
    });

    hi.show();
}
[JavaFX Application Thread] 0:0:2,86 - URL loaded: https://www.google.com/
[JavaFX Application Thread] 0:0:2,87 - Domain of the URL: google.com
[JavaFX Application Thread] 0:0:2,88 - the BrowserComponent cannot navigate
[JavaFX Application Thread] 0:0:3,815 - URL loaded: https://www.google.it/?gfe_rd=cr&ei=avGmWa-YNKnS8AfqlIGoDw
[JavaFX Application Thread] 0:0:3,815 - Domain of the URL: google.it
[JavaFX Application Thread] 0:0:3,815 - the BrowserComponent cannot navigate
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f3ec48044cf, pid=5754, tid=0x00007f3ec7be4700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libjfxwebkit.so+0xa9e4cf]  WebCore::ResourceLoader::willSendRequestInternal(WebCore::ResourceRequest&, WebCore::ResourceResponse const&)+0x53f
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid5754.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
// Check if the native browser is supported (only for logging)
if (BrowserComponent.isNativeBrowserSupported()) {
    Log.p("Native Browser Supported");
} else {
    Log.p("Native Browser NOT Supported");
}
browser.setBrowserNavigationCallback((new BrowserNavigationCallback() {
    @Override
    public boolean shouldNavigate(String url) {
        Log.p("URL: " + url);
        return false;
    }
}));
[EDT] 0:0:0,44 - Native Browser Supported
[EDT] 0:0:0,59 - setURLHierarchy executed
[JavaFX Application Thread] 0:0:0,90 - URL: file:///home/francesco/NetBeansProjects/myBrowser/build/classes/html/index.html
[JavaFX Application Thread] 0:0:2,535 - URL: https://www.codenameone.com/
Log.p("the BrowserComponent cannot navigate");
if (Display.getInstance().isSimulator()) {
    // small workaround because the return value is ignored by the simulator
    browser.setURL("jar:///goback.html");
}
return false; // the BrowserComponent cannot navigate
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script>window.history.go(-1);</script>
    </head>
    <body>
        The link will be opened with an external browser.<br />
    <a href="javascript:window.history.go(-1);">Click here to go back</a>
    </body>
</html>
<a href="https://www.google.com/">WebPage 1 (domain not allowed)</a><br />
public void start() {
    if (current != null) {
        current.show();
        return;
    }
    Form hi = new Form("MyBrowser", new BorderLayout());

    // Create the BrowserComponent
    BrowserComponent browser = new BrowserComponent();

    // Check if the native browser is supported (only for logging)
    if (BrowserComponent.isNativeBrowserSupported()) {
        Log.p("Native Browser Supported");
    } else {
        Log.p("Native Browser NOT Supported");
    }

    try {
        // Load a web page placed in the "html" package
        browser.setURLHierarchy("/index.html");
        Log.p("setURLHierarchy executed");
    } catch (IOException ex) {
        Log.e(ex);
    }

    hi.add(BorderLayout.CENTER, browser);

    // Create a command for the Back button
    String jsCode = "function goBack() {                        "
            + "    if (typeof goBackButton == 'function') {     "
            + "        window.goBackButton();                   "
            + "    return 'I\\'m invoking goBackButton()';      "
            + "    } else {                                     "
            + "        window.history.go(-1);                   "
            + "        return 'goBackButton() is not available';"
            + "    }                                            "
            + "}                                                "
            + "goBack();                                        ";
    Command backCommand = new Command("BackButton") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            Log.p(browser.executeAndReturnString(jsCode));
        }
    };

    hi.getToolbar().setBackCommand(backCommand);

    // Allow browsing only inside my domains
    String myDomain1 = "127.0.0.1"; // for local server (using simulator)
    String myDomain2 = "utiu-students.net";
    String myDomain3 = "login.uninettunouniversity.net";

    browser.setBrowserNavigationCallback((url) -> {

        Log.p("URL loaded: " + url);
        String domain = ""; // the domain of the url loaded by BrowserComponent
        if (url.startsWith("http")) {
            try {
                domain = (new URI(url)).getHost();
                domain = domain.startsWith("www.") ? domain.substring(4) : domain;
            } catch (URISyntaxException ex) {
                Log.e(ex);
            }
        }
        Log.p("Domain of the URL: " + domain);
        if (url.startsWith("file")
                || domain.equals(myDomain1)
                || domain.equals(myDomain2)
                || domain.equals(myDomain3)) {
            Log.p("the BrowserComponent can navigate");
            return true; // the BrowserComponent can navigate
        } else {
            Display.getInstance().callSerially(() -> {
                // it opens the url with the native platform
                Boolean can = Display.getInstance().canExecute(url);
                if (can != null && can) {
                    Display.getInstance().execute(url);
                }
            });
            Log.p("the BrowserComponent cannot navigate");
            if (Display.getInstance().isSimulator()) {
                // small workaround because the return value is ignored by the simulator
                browser.setURL("jar:///goback.html");
            }
            return false; // the BrowserComponent cannot navigate
        }

    }
    );

    hi.show();
}