从 CRX 文件安装 Chrome 扩展程序

在使用嵌入式 Browser 中的扩展程序时,您可能希望将它们打包并分发在应用程序中,并静默安装。

在本教程中,我将演示如何通过编程方式从 CRX 文件中安装扩展程序,保持它们的更新,并使用它们。

此外,我还会向您展示如何获取在 Chrome 应用商店中发布的扩展程序的 CRX 文件。

想让终端用户直接访问 Chrome 应用商店吗?我们在JxBrowser 支持 Chrome 扩展程序[1]一文中对此进行了介绍。

扩展程序

在本教程中,我选择了 React DevTools 扩展程序。虽然它对终端用户并不实用,但它非常适合本教程的目的,并且在开发过程中很有用。许多 JavaScript 库提供的开发工具作为扩展程序,最终的功能都是一样的:将库特定的功能扩展到 Chrome DevTools 中。

通过 JxBrowser,您可以使用 React 构建用户界面,将 React DevTools 集成到 JxBrowser 中非常方便。特别是当嵌入式 Web 应用程序需要 JxBrowser 与 Java 宿主应用程序进行通信,而不能在独立 Browser 中运行时,这一点尤为重要。

您可以从源代码[2]构建此扩展程序,或者按照本教程后续部分中的描述从 Chrome 应用商店获取它。

创建应用程序

让我们从创建一个简单的应用程序开始。这个应用程序将显示一个 Browser 和一个按钮,用于打开标准的 Chrome DevTools。

java 复制代码
import static java.awt.BorderLayout.CENTER;
import static java.awt.BorderLayout.NORTH;
import static javax.swing.BoxLayout.X_AXIS;
import static javax.swing.SwingUtilities.invokeLater;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.EngineOptions;
import com.teamdev.jxbrowser.engine.RenderingMode;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.file.Paths;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public final class CrxExtensions {

    private static final Dimension BUTTON_SIZE = new Dimension(32, 32);

    public static void main(String[] args) {
        var options = EngineOptions
                .newBuilder(RenderingMode.HARDWARE_ACCELERATED)
                .userDataDir(Paths.get("<path to the directory>"))
                .build();
        var engine = Engine.newInstance(options);
        var profile = engine.profiles().defaultProfile();
        var browser = profile.newBrowser();

        invokeLater(() -> {
            var frame = new JFrame("在 JxBrowser 中使用 CRX Chrome 扩展程序");
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    engine.close();
                }
            });
            frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
            frame.add(BrowserView.newInstance(browser), CENTER);
            frame.add(createExtensionBar(browser), NORTH);

            frame.setSize(1280, 900);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

            browser.navigation().loadUrl("https://react.dev/");
        });
    }

    private static JPanel createExtensionBar(Browser browser) {
        var extensionBar = new JPanel();
        extensionBar.setLayout(new BoxLayout(extensionBar, X_AXIS));

        var openDevTools = new JButton("打开 DevTools");
        openDevTools.addActionListener(e -> browser.devTools().show());
        extensionBar.add(openDevTools);

        return extensionBar;
    }
}

请注意,我突出显示了配置用户数据目录的行。这是 Chromium 将存储已安装扩展程序的地方。我们希望此目录是持久的,以便在启动之间保留扩展程序的状态。

安装扩展程序

要安装扩展程序,我们需要一个指向 CRX 文件的路径。我们将从资源中找到可用的扩展程序,并将它们传递给 JxBrowser 进行安装:

java 复制代码
private static final List<String> EXTENSION_FILES = List.of(
        "react_dev_tools.crx"
);

public static void main(String[] args) {
    ...
    var profile = engine.profiles().defaultProfile();
    var browser = profile.newBrowser();

    var extensions = profile.extensions();
    for (var crx : EXTENSION_FILES) {
        extensions.install(getResourcePath(crx));
    }
    invokeLater(() -> {
        ...
    });
}

private static Path getResourcePath(String name) {
    try {
        var resource = CrxExtensions.class.getClassLoader()
                                          .getResource(name);
        if (resource != null) {
            return Paths.get(resource.toURI());
        } else {
            throw new IllegalStateException(
                    "Couldn't find the bundled extension.");
        }
    } catch (URISyntaxException e) {
        throw new IllegalStateException(e);
    }
}

在上述代码中,我们在每次启动应用程序时安装扩展程序。这可以确保扩展程序保持最新:如果 CRX 文件的版本不同,JxBrowser 会重新安装该扩展程序。

打开新标签页的权限

扩展程序可以打开带有任意 Web 内容的新标签页。例如,它们可以打开设置页面或授权表单。在 JxBrowser 中,我们将这些称为扩展程序弹出窗口,并默认将它们禁用。现在是时候启用它们了:

java 复制代码
var extensions = profile.extensions();
for (var crx : EXTENSION_FILES) {
    extensions.install(getResourcePath(crx));
    extension.set(OpenExtensionPopupCallback.class, 
              new DefaultOpenExtensionPopupCallback());
}

与扩展程序交互

大多数扩展程序会在 Google Chrome 工具栏中添加一个图标。这个图标称为扩展程序操作,当点击时,它会执行逻辑操作或打开一个弹出窗口。

让我们创建一个类似的扩展工具栏,并将扩展程序操作添加到应用程序的 UI 中:

java 复制代码
import com.teamdev.jxbrowser.extensions.callback.OpenExtensionPopupCallback;
import com.teamdev.jxbrowser.view.swing.callback.DefaultOpenExtensionPopupCallback;
...

private static JPanel createExtensionBar(Browser browser) {
    ...
    var extensions = browser.profile().extensions();
    for (var extension : extensions.list()) {
        extension.action(browser).ifPresent(action -> {
            var button = new JButton();
            extensionBar.add(button);
            configureActionButton(button, action);
        });
    }
    return extensionBar;
}

扩展操作随时可能发生变化。例如,React DevTools 的操作在没有 React 的页面上会变为禁用状态。其他扩展程序可能会根据 Browser 中发生的事情更改图标或徽章。让我们跟踪这些变化并更新 UI:

java 复制代码
import com.teamdev.jxbrowser.extensions.callback.OpenExtensionPopupCallback;
import com.teamdev.jxbrowser.extensions.event.ExtensionActionUpdated;
import com.teamdev.jxbrowser.view.swing.callback.DefaultOpenExtensionPopupCallback;
...

private static JPanel createExtensionBar(Browser browser) {
    ...
    var extensions = browser.profile().extensions();
    for (var extension : extensions.list()) {
        extension.action(browser).ifPresent(action -> {
            var button = new JButton();
            extensionBar.add(button);
            configureActionButton(button, action);
            action.on(ExtensionActionUpdated.class, params -> {
                invokeLater(() -> configureActionButton(button, action));
            });
        });
    }
    return extensionBar;
}

现在,让我们实现显示操作图标和名称的方法并配置点击处理程序:

java 复制代码
import com.teamdev.jxbrowser.extensions.ExtensionAction;
import com.teamdev.jxbrowser.view.swing.graphics.BitmapImage;
...

private static void configureActionButton(JButton button, 
                                          ExtensionAction action) {
    var icon = BitmapImage.toToolkit(action.icon());
    button.setPreferredSize(new Dimension(32, 32));
    button.setText(action.tooltip());
    button.setIcon(new ImageIcon(icon));
    button.setEnabled(action.isEnabled());
    if (button.getActionListeners().length == 0) {
        button.addActionListener(e -> action.click());
    }
}

结果

在这个视频中,您将看到 React DevTools 扩展程序在 JxBrowser 中安装并使用的过程。

video

在 JxBrowser 演示应用程序中从 Chrome 应用商店安装扩展程序。

从 Chrome 应用商店获取 CRX 文件

很多时候,开源扩展程序会在 GitHub 上发布 CRX 文件,或提供如何自行构建这些文件的说明。但如果既没有 CRX 文件也没有说明,您可以从 Chrome 应用商店获取该文件。

要在 JxBrowser 中从 Chrome 应用商店获取扩展程序文件,请按如下方式注册 InstallExtensionCallback,然后导航到 Chrome 应用商店,手动安装扩展程序。

安装扩展程序后,回调函数将把下载的 CRX 文件复制到当前目录,并在文件资源管理器中打开它。

java 复制代码
import static java.awt.Desktop.getDesktop;
import static javax.swing.SwingUtilities.invokeLater;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;

import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.RenderingMode;
import com.teamdev.jxbrowser.extensions.callback.InstallExtensionCallback;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.swing.JFrame;

public final class CrxFileFromChromeWebStore {

    private static final String EXTENSION_URL =
            "https://chromewebstore.google.com/detail/...";

    public static void main(String[] args) {
        var engine = Engine.newInstance(RenderingMode.HARDWARE_ACCELERATED);
        var browser = engine.newBrowser();

        var extensions = browser.profile().extensions();
        extensions.set(InstallExtensionCallback.class, (params, tell) -> {
            var name = params.extensionName();
            var source = Paths.get(params.extensionCrxFile());
            var target = Paths.get(name + ".crx").toAbsolutePath();
            try {
                Files.copy(source, target);
                getDesktop().open(target.getParent().toFile());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            tell.cancel();
        });

        browser.navigation().loadUrl(EXTENSION_URL);

        invokeLater(() -> {
            var view = BrowserView.newInstance(browser);
            var frame = new JFrame("Chrome 应用商店");
            frame.add(view);
            frame.setSize(1280, 900);
            frame.setLocationRelativeTo(null);
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    engine.close();
                }
            });
            frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
            frame.setVisible(true);
        });
    }
}

源代码

您可以在 JxBrowser-Examples[3] 仓库中找到这个示例的源代码。

相关链接

参考资料

[1] JxBrowser 支持 Chrome 扩展程序: https://teamdev.cn/jxbrowser/blog/chrome-extensions-in-jxbrowser/?utm_source=csdn\&utm_medium=article\&utm_campaign=install-chrome-extensions-from-crx-files

[2] 源代码: https://github.com/facebook/react/tree/main/packages/react-devtools-extensions?utm_source=csdn\&utm_medium=article\&utm_campaign=install-chrome-extensions-from-crx-files

[3] JxBrowser-Examples: https://github.com/TeamDev-IP/JxBrowser-Examples/tree/v8.0.0-eap/tutorials/crx-extensions/src/main/java?utm_source=csdn\&utm_medium=article\&utm_campaign=install-chrome-extensions-from-crx-files

[4] 如何为 Java 应用程序创建安装程序: https://teamdev.cn/jxbrowser/blog/how-to-create-installer-for-java-application/?utm_source=csdn\&utm_medium=article\&utm_campaign=install-chrome-extensions-from-crx-files

[5] Chrome 应用商店中的 React DevTools: https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?pli=1\&utm_source=csdn\&utm_medium=article\&utm_campaign=install-chrome-extensions-from-crx-files

相关推荐
y先森21 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy22 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891125 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
弗拉唐1 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi771 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
少说多做3432 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀2 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20202 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea