从 CRX 文件安装 Chrome 扩展程序

news2024/11/13 12:06:51

在使用嵌入式 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。

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 进行安装:

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 中,我们将这些称为扩展程序弹出窗口,并默认将它们禁用。现在是时候启用它们了:

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

与扩展程序交互

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

React DevTools 的操作弹出窗口

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

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:

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

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

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 文件复制到当前目录,并在文件资源管理器中打开它。

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] 仓库中找到这个示例的源代码。

相关链接

  • 如何为 Java 应用程序创建安装程序[4]
  • Chrome 应用商店中的 React DevTools[5]

参考资料

[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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2091929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8.30工作笔记

要做的事情&#xff1a; 1 测试剩下的三个因子&#xff1a;coppock 潮汐因子 云开雾散 2 整理需要时间序列的因子 以及截面因子 3 灾后重建多了一列&#xff0c;灾后重建’所有值都是nan&#xff0c;这里不仅是灾后重建&#xff0c;所有的都要改 4 coppock 潮汐因子 云开雾散在…

排列数+时间戳+逆元取模

前言&#xff1a;这个题目是真的难&#xff0c;不会做&#xff0c;看了题解才发现是咋回事 题目地址 最主要的就是为啥是除以3&#xff0c;c之前需要完成a 和 b&#xff0c;d 和 e 对我们的答案没有影响&#xff0c;所以我们要除以 A(3,3) ,但是 a 和 b 的排列没有要求&#xf…

Sinc Function介绍

1、定义 Sinc函数全称&#xff1a;sine cardinal&#xff0c;也称作是sampling function&#xff08;采样函数&#xff09;。 2、分类 &#xff08;1&#xff09;归一化sinc函数&#xff1a; 这种定义在信号处理中被广泛采用&#xff0c;其中 x 是一个无量纲的变量&#xff0c;…

基于YOLO的车牌检测识别(YOLO+Transformer)

概述&#xff1a; 基于深度学习的车牌识别&#xff0c;其中&#xff0c;车辆检测网络直接使用YOLO侦测。而后&#xff0c;才是使用网络侦测车牌与识别车牌号。 车牌的侦测网络&#xff0c;采用的是resnet18&#xff0c;网络输出检测边框的仿射变换矩阵&#xff0c;可检测任意形…

同城小程序怎么做 同城小程序系统开发制作方案

很多同城创业的老板们想要做一个同城小程序但是不知道怎么做&#xff0c;本次瀚林就为大家详细介绍一下做同城小程序系统开发制作方法&#xff0c;给大家做个参考。 目前同城类型的小程序系统市面上比较常见的有&#xff1a;同城配送、鲜花订花、同城上门服务、同城跑腿、同城便…

中仕公考怎么样?事业编考试怎么备考?

事业编考试备考可以大致分为三个阶段&#xff0c;按照不同阶段根据自身的学习情况制定不同的学习计划即可。 ①基础阶段 有备考经验的考生可以忽略这一步&#xff0c;刚开始先打好基础很重要&#xff0c;根据课程和教材理解知识点&#xff0c;按照模块学习&#xff0c;对考试…

cnocr 安装

打开终端 如果不会打开终端 -> 终端打开输入 pip install cnocr 执行中途可能报错 去这里下载工具&#xff1a;c构建工具下载完打开&#xff0c;勾选这个 然后点安装安装完回到第2步重新执行

docker镜像所使用到的COW写时复制技术是什么

copy on write 简单来说&#xff0c;所有的读操作都是指向一份内存地址&#xff0c;共享这些数据&#xff0c;节省内存空间。 如果有进程要对数据进行写操作&#xff0c;系统会检测到这个行为&#xff0c;将数据复制一份出来&#xff0c;给这个进程进行写操作。其他进程继续…

5.3二叉树——二叉树链式结构实现

本篇博客梳理二叉树链式结构 明确&#xff1a;二叉树是递归定义的 递归的本质&#xff1a;当前问题子问题&#xff0c;返回条件是最小规模的子问题 一、二叉树的遍历 1&#xff0e;前序、中序与后序遍历 &#xff08;1&#xff09;前序&#xff1a;根->左子树->右子树…

全球知名度最高的华人颜廷利:世界公认十大思想家哲学家

全球知名度最高的华人颜廷利&#xff1a;世界公认十大思想家哲学家 在汉语这一中国优秀传统文化的瑰宝中&#xff0c;“色”与“舍”这两个字的发音分别被解读为“思恶”和“识恶”&#xff0c;揭示了一种深奥的文化现象。这种现象的根源&#xff0c;实则来自于我们的感官——眼…

linux上查找某应用所在的绝对路径

linux上查找某应用所在的绝对路径 1、已知应用名称 找到应用的进程号 例&#xff1a;查找nginx的进程号 ps -ef | grep nginx 或者 ps -aux | grep nginx 2、通过端口号找进程号 lsof -i:80 3、通过进程号找到所在目录&#xff0c;Linux在启动一个进程时,系统会在/proc目…

力扣刷题(3)

整数反转 整数反转-力扣 思路&#xff1a; 利用%和/不断循环取待反转整数的最后一位&#xff0c;注意判断是否超出范围。 int reverse(int x){int y0;while(x){if(y > INT_MAX/10 || y < INT_MIN/10)return 0;int tmpx%10;yy*10tmp;x/10;}return y; }字符串转换整数 …

多线程篇(基本认识 - 锁优化)(持续更新迭代)

目录 一、前言 二、阿里开发手册 三、synchronized 锁优化的背景 四、Synchronized的性能变化 1. Java5之前&#xff1a;用户态和内核态之间的切换 2. java6开始&#xff1a;优化Synchronized 五、锁升级 1. 无锁 2. 偏向锁 2.1. 前言 2.2. 什么是偏向锁 2.3. 偏向…

知识产权案件中的消费者问卷调查证据

在知识产权案件中&#xff0c;消费者问卷调查可以作为一种重要的证据形式。通过调查消费者的认知、态度、行为和观点&#xff0c;消费者问卷调查可以提供以下方面的证据支持&#xff1a; 1、商标或产品混淆&#xff1a;消费者问卷调查可以确定消费者对于涉及知识产权的商标或产…

《python语言程序设计》第8章第9题将二进制数作为字符串转换十六进制print和return的区别

在这里我发现了return和print的区别 def binary_to_hex(binary_value):len_text len(binary_value)for i in range(0, len_text, 4):#能把二进制分成四组进行打印print(binary_value[0 i:4 i])#只能运行将前4个数分成一组return binary_value[0 i:4 i]a binary_to_hex(&q…

HarmonyOS--AGC(认证服务/云函数/云存储/云数据库)

HarmonyOS–AGC(认证服务/云函数/云存储/云数据库) 文章目录 一、注册华为账号开通认证服务二、添加项目&#xff1a;*包名要与项目的包名保持一致三、获取需要的文件四、创建项目&#xff1a;*包名要与项目的包名保持一致五、添加json文件六、加入请求权限七、加入依赖八、修改…

Openai api via azure error: NotFoundError: 404 Resource not found

题意&#xff1a;"OpenAI API通过Azure出错&#xff1a;NotFoundError: 404 找不到资源" 问题背景&#xff1a; thanks to the university account my team and I were able to get openai credits through microsoft azure. The problem is that now, trying to us…

VS2022搭建QT及OpenCV环境

1.背景 由于之前VS2022和QT已经安装好了&#xff0c;所以本次的任务主要是下载OpenCV以及在VS2022上集成QT和OpenCV。关于VS2022和QT的安装大家可以参考别的博客。QT选择的版本是6.2.4&#xff0c;OpenCV版本为3.4.5&#xff0c;Windows版本为Win11。 2.OpenCV下载 OpenCV官…

《黑神话:深度探索与攻略指南》——虎先锋隐藏门在哪里

在《黑神话悟空》这款扣人心弦的游戏中&#xff0c;探索隐藏区域和发现秘密宝箱是许多玩家的乐趣所在。特别是戌狗地窖中那个神秘的宝箱&#xff0c;它不仅藏有泡酒物虎舍利等珍贵道具&#xff0c;更是对玩家探索能力的一次考验。然而&#xff0c;不少玩家在寻找虎先锋隐藏门时…

raksmart机云大宽带服务器托管服务内容

RakSmart是一家提供全球数据中心服务的公司&#xff0c;其业务范围涵盖了服务器托管、专用服务器租赁、云服务等多个领域。其中&#xff0c;机柜大带宽服务器托管服务是其特色之一&#xff0c;特别适合那些需要大量带宽资源的企业级客户。下面我们将详细介绍RakSmart的机柜大带…