11

我已经构建了一个 Chrome 扩展,我一直在使用 Selenium 将它安装到 Chrome 中。

现在我想从源代码构建我自己的 Chromium,以便我的扩展预先捆绑到构建的分布式包中,这样我就不必担心需要 Selenium 为我的用例安装 CRX 文件。

我找到了几个论坛,人们建议他们尝试这个,但没有一个看起来像是成功的。

我发现了一些关于系统管理员如何为他们网络中的用户强制将扩展安装到 chromium 中的提示:https: //support.google.com/chrome/a/answer/6306504?hl=en 但这可能适用于 chrome 企业不会对我有用。

这是另一篇关于如何离线安装 chrome 扩展的文章。我也许可以使用其中的一些来实现我想要的。

有没有人成功地将 CRX构建到铬中,以便自动安装 CRX?

快速更新:

我只想注意:我正在使用 InnoSetup 安装程序安装我的自定义版本的 chrome。所以我确实有机会在安装铬叉后,在安装后执行一些自定义执行步骤。我的扩展程序托管在 chrome 网上商店并获得批准。

因此,如果有某种方法可以从网上商店以编程方式将 chrome 扩展安装到 Chromium 安装中,我会很容易地使用它。

4

1 回答 1

14

这已66.0.3359.139 to 7x.x.x在 Windows 10 上的 Chromium fork 版本中进行了测试。Linux 和 macOS 的扩展捆绑过程可能不同。我还试图让完成这项任务尽可能容易。要做到这一点,您需要做几件事:

  1. 将您的 Chromium 扩展 (.crx) 文件添加到默认扩展列表中以与迷你安装程序捆绑
  2. 找出该扩展程序的 ID
  3. 自动化扩展安装过程
  4. 通过 Chrome 网上应用店检查
  5. 构建迷你安装程序以安装您的 Chromium fork

1:要将您的扩展程序与安装程序捆绑在一起,您必须修改:src\chrome\browser\extensions\default_extensions\BUILD.gn文件。假设tab_capture.crx是你的扩展,那么它的内容应该是这样的:

if (is_win) {
copy("default_extensions") {
sources = [
  "external_extensions.json",
  "tab_capture.crx"
]
outputs = [
  "$root_out_dir/extensions/{{source_file_part}}",
]

我刚刚附加tab_capture.crx并且没有修改任何其他内容。您的扩展文件应该在这个位置:src\chrome\browser\extensions\default_extensions\tab_capture.crx

2:每个扩展都会有一个由 Chromium 分配给它的唯一 ID,以识别该扩展。要找出您的扩展程序的 ID,您应该转到chrome://extensions/页面并拖放您的crx文件。应弹出一个确认对话框。单击Add extension按钮并确保Developer mode已启用,然后您的 ID 应该可见,但扩展程序将被禁用,如下所示:

在此处输入图像描述

3:现在,我们将开始修改C++源文件。让我们声明我们的扩展名和 ID。我们将在这些文件中这样做: src\extensions\common\extension.h

namespace extensions {

extern const int kOurNumExtensions;
extern const char* kOurExtensionIds[];
extern const char* kOurExtensionFilenames[];

我刚刚在extensions命名空间下声明了这些变量。请记住,我们在下面分配的扩展 ID 必须与 Chromium 分配的扩展 ID 匹配。

这些变量的定义在:src\extensions\common\extension.cc

namespace extensions {

const char* kOurExtensionIds[] = {
    "aaaaaaaaaaaaaaaaaaaaaaaaaaa"}; // Assumed extension ID of tab_capture
const char* kOurExtensionFilenames[] = {
    "tab_capture.crx"};
const int kOurNumExtensions = 1;

Chromium 将在首次启动时创建一个配置文件。因此,我们假设尚不存在配置文件,因为我们将在首次启动时在运行时安装我们的扩展。Windows 机器上的配置文件通常应该存在于此处:C:\Users\Username\AppData\Local\CompanyName\ChromiumForkName因此请确保CompanyName在启动 Chromium 之前删除文件夹。当然,我们也可以在创建配置文件后执行安装过程。为此,您必须检查我们的扩展是否已安装,以防止多次尝试安装。

Chromium 在这个文件中处理启动浏览器创建的东西:src\chrome\browser\ui\startup\startup_browser_creator.cc所以我们在配置文件被初始化并且浏览器已经启动之后安装这个扩展。您还必须添加一些头文件。我们将在方法中这样做LaunchBrowser

// Add these header files cause we we will be using them
#include "base/path_service.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/chrome_paths.h"
#include "extensions/browser/extension_system.h"

bool StartupBrowserCreator::LaunchBrowser(
const base::CommandLine& command_line,
Profile* profile,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
chrome::startup::IsFirstRun is_first_run) {
    // Omitted Chromium code
    in_synchronous_profile_launch_ = false;
}

// Install our extension
base::FilePath extension_dir;
if (first_run::IsChromeFirstRun() &&
    base::PathService::Get(chrome::DIR_EXTERNAL_EXTENSIONS, &extension_dir)) 
{
    for (int i = 0; i < extensions::kOurNumExtensions; ++i) {
        base::FilePath file_to_install(extension_dir.AppendASCII(
            extensions::kOurExtensionFilenames[i]));
        std::unique_ptr<ExtensionInstallPrompt> prompt(
            new ExtensionInstallPrompt(chrome::FindBrowserWithProfile(profile)->tab_strip_model()->GetActiveWebContents()));
        scoped_refptr<extensions::CrxInstaller> crx_installer(extensions::CrxInstaller::Create(
            extensions::ExtensionSystem::Get(profile)->extension_service(), std::move(prompt)));
        crx_installer->set_error_on_unsupported_requirements(true);
        crx_installer->set_off_store_install_allow_reason(
            extensions::CrxInstaller::OffStoreInstallAllowedFromSettingsPage);
        crx_installer->set_install_immediately(true);
        crx_installer->InstallCrx(file_to_install);
    }
}
// End of install our extension

// Chromium code
profile_launch_observer.Get().AddLaunched(profile);

这应该安装我们的扩展,但我们希望在没有任何用户交互的情况下强制安装我们的扩展,让我们在这里做:chrome/browser/extensions/extension_install_prompt.cc

void ExtensionInstallPrompt::ShowDialog(
const DoneCallback& done_callback,
const Extension* extension,
const SkBitmap* icon,
std::unique_ptr<Prompt> prompt,
std::unique_ptr<const PermissionSet> custom_permissions,
const ShowDialogCallback& show_dialog_callback) {
// Chromium code
return;
}

// Don't show add extension prompt for our extensions
for (int i = 0; i < extensions::kOurNumExtensions; ++i) {
    if (extension->id() == extensions::kOurExtensionIds[i]) {
        
        // Note: The line below won't work in recent versions of Chromium. So if you are using a recent version then use the code just below it instead of this one
        base::ResetAndReturn(&done_callback_).Run(
           Result::ACCEPTED);

        // Note: For recent versions of Chromium. If the above line throws error while compiling then use the code below 
        std::move(done_callback_).Run(
           DoneCallbackPayload(Result::ACCEPTED));
        return;
    }
}
// End of don't show add extension prompt for our extensions

// Chromium code
LoadImageIfNeeded();

4:即使我们自动执行安装过程,Chromium 也会禁用我们的扩展程序,因为它不是从 Chrome 网上应用店安装的。它在这里处理:src\chrome\browser\extensions\install_verifier.cc在这种方法中:

bool InstallVerifier::MustRemainDisabled(const Extension* extension,
                                     disable_reason::DisableReason* reason,
                                     base::string16* error) const {
// Omitted Chromium code

// Chromium code
if (Manifest::IsUnpackedLocation(extension->location())) {
MustRemainDisabledHistogram(UNPACKED);
return false;
}

// Always enable our tab capture extension
// Use loop if you have more than one extension
if (extension->id() == extensions::kOurExtensionIds[0]) {
    return false;
}
// End of always enable our tab capture extension

// Chromium code
if (extension->location() == Manifest::COMPONENT) {
    MustRemainDisabledHistogram(COMPONENT);
    return false;
}

这将确保在我们绕过 Chrome 网上应用店检查时启用我们的扩展程序。

如果您不希望您的扩展程序被卸载并保持启用,那么您可以通过修改此文件来做到这一点:chrome/browser/extensions/standard_management_policy_provider.cc并修改这些方法:MustRemainInstalledMustRemainEnabled

5:现在您可以通过执行此命令来构建迷你安装程序

ninja -C out\BuildFolder mini_installer

上面的命令将构建mini_installer.exe. 注意如果你传递--system-level参数,那么它应该在文件夹mini_installer.exe中安装你的 Chromium fork 。Program files安装完成后,您的 crx 文件应位于此处:C:\Program Files (x86)\YourChromium\Application\66.0.3359.139\Extensions\tab_capture.crx.

Chromium 会将这个 crx 文件解压缩并安装到您的配置文件中:(C:\Users\Username\AppData\Local\YourChromium\User Data\Default\Extensions假定默认配置文件)

注意:为了提高代码的可读性和易用性,您可以使用容器类来保存这些扩展文件名及其对应的 ID,并在基于范围的 for 循环中轻松使用它。

让我知道它是否有效。花费的时间比预期的要长,因为我注意到他们的代码库发生了很多变化,而且我们的旧代码在这个最新的 Chromium 版本中不起作用。我敢肯定,我没有错过任何其他东西:)

于 2018-05-12T10:12:51.340 回答