检查用户是否安装了 Chrome 扩展

IT技术 javascript google-chrome google-chrome-extension
2021-01-18 21:56:02

我正在构建 Chrome 扩展程序,为了让整个事情按照我希望的方式工作,我需要一个外部 JavaScript 脚本来检测用户是否安装了我的扩展程序。

例如:用户安装了我的插件,然后访问一个带有我的脚本的网站。该网站检测到我的扩展程序已安装并相应地更新页面。

这可能吗?

6个回答

Chrome 现在能够从网站向扩展程序发送消息。

因此,在扩展 background.js(content.js 将不起作用)中添加如下内容:

chrome.runtime.onMessageExternal.addListener(
    function(request, sender, sendResponse) {
        if (request) {
            if (request.message) {
                if (request.message == "version") {
                    sendResponse({version: 1.0});
                }
            }
        }
        return true;
    });

这将让您从网站拨打电话:

var hasExtension = false;

chrome.runtime.sendMessage(extensionId, { message: "version" },
    function (reply) {
        if (reply) {
            if (reply.version) {
                if (reply.version >= requiredVersion) {
                    hasExtension = true;
                }
            }
        }
        else {
          hasExtension = false;
        }
    });

然后您可以检查 hasExtension 变量。唯一的缺点是调用是异步的,所以你必须以某种方式解决这个问题。

编辑:如下所述,您需要在manifest.json 中添加一个条目,列出可以向您的插件发送消息的域。例如:

"externally_connectable": {
    "matches": ["*://localhost/*", "*://your.domain.com/*"]
},

2021 更新: chrome.runtime.sendMessage如果未安装或禁用扩展,将在控制台中引发以下异常。

未经检查的 runtime.lastError:无法建立连接。接收端不存在

要解决此问题,请在sendMessage回调中添加此验证

if (chrome.runtime.lastError) {
    // handle error 
}
您还必须将以下内容添加到 manifest.json: "externally_connectable": { "matches": [" :// .yourdomain.com/*"] }
2021-03-15 21:56:02
@EricP 最初的问题表明他们正在编写扩展程序,所以这个问题没有实际意义。
2021-03-18 21:56:02
它应该是 {version: '1.0'} 而不是 {version: 1.0} 否则你会在扩展检查视图控制台中得到“Uncaught SyntaxError: Unexpected number”。
2021-03-18 21:56:02
在“检查”方面(尝试检查给定扩展的可用性的网页), chrome.runtime 未定义,Linux 上的 chrome 36。
2021-03-21 21:56:02
这就像一个魅力。另一个缺点当然是您必须控制扩展 - 您不能使用它来查看是否安装了任意第三方扩展。
2021-04-06 21:56:02

我确定有一种直接的方法(直接调用扩展上的函数,或使用 JS 类进行扩展),但有一种间接方法(直到出现更好的方法):

让您的 Chrome 扩展程序在您的页面上查找特定的 DIV 或其他元素,并具有非常特定的 ID。

例如:

<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>

执行 agetElementById并将 设置innerHTML为您的扩展程序的版本号或其他内容。然后您可以阅读该客户端的内容。

尽管如此,如果有可用的方法,您应该使用直接方法。


编辑:找到直接方法!!

使用此处找到的连接方法:https : //developer.chrome.com/extensions/extension#global-events

未经测试,但你应该能够做到......

var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);
最后一个方法不再有效,因为connect函数已移至chrome.runtime命名空间。有关更新的版本,请参阅 BJury 的回答(和评论)
2021-03-12 21:56:02
@James 您是否正在执行使用托管脚本中的 .connect() 的脚本?我知道 Chrome 努力不只处理出于安全目的而未托管的本地文件。- 只是检查。
2021-03-25 21:56:02
嗯 chrome.extension.connect 似乎只在从扩展(或任何扩展)中执行时才有效。我需要它从任何随机的 js 脚本中工作。有任何想法吗?
2021-03-29 21:56:02
奇怪的是,文档说它应该可以工作。“不像其他的铬。*的API,chrome.extension的部分可以由内容脚本中使用”,它列出sendRequest()onRequestconnect()onRequest,和getURL()
2021-04-03 21:56:02
@James 我正在执行 .connect() 的脚本在同一台服务器上,如果这就是你的意思?
2021-04-08 21:56:02

另一种方法是公开 Web 可访问的资源,尽管这将允许任何网站测试您的扩展是否已安装。

假设您的扩展程序的 ID 是aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,并且您test.png在扩展程序的文件中添加了一个文件(例如,透明像素图像)

然后,您使用web_accessible_resources清单键将此文件公开给网页

  "web_accessible_resources": [
    "test.png"
  ],

在您的网页中,您可以尝试通过其完整 URL(在<img>标签中、通过 XHR 或任何其他方式)加载此文件

chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.png

如果文件加载,则安装扩展。如果加载此文件时出错,则未安装扩展。

// Code from https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/8ArcsWMBaM4/2GKwVOZm1qMJ
function detectExtension(extensionId, callback) { 
  var img; 
  img = new Image(); 
  img.src = "chrome-extension://" + extensionId + "/test.png"; 
  img.onload = function() { 
    callback(true); 
  }; 
  img.onerror = function() { 
    callback(false); 
  };
}

注意:如果加载此文件时出现错误,所述网络堆栈错误将出现在控制台中,并且无法将其静音。Chromecast在使用这种方式的时候,也因此引起了不小的争议最终非常丑陋的解决方案是由 Chrome 团队将开发工具中的非常具体的错误完全列入黑名单


重要提示:此方法在 Firefox WebExtensions 中不起作用。Web 可访问资源固有地将扩展暴露给指纹,因为 URL 可以通过知道 ID 来预测。Firefox 决定通过为 Web 可访问资源分配一个特定实例的随机 URL来弥补这个漏洞

然后可以使用如下 URL 访问这些文件:

moz-extension://<random-UUID>/<path/to/resource>

此 UUID 是为每个浏览器实例随机生成的,不是您的扩展程序的 ID。这可以防止网站对用户已安装的扩展程序进行指纹识别。

但是,虽然扩展程序可用于runtime.getURL()获取此地址,但您不能在您的网站中对其进行硬编码。

该网页不允许我们访问 chrome-extension://
2021-03-25 21:56:02
@niconic 该答案(无论如何都作为链接不好)指的是清单版本 2 生效之前的情况。以前,不需要声明资源可通过网络访问。
2021-03-26 21:56:02
虽然这个答案从stackoverflow.com/a/9216924/1504300获得了“果汁” ,恕我直言添加了一些非常重要的信息,例如在扩展中公开资源以及您可以使用 ajax 请求检查存在的事实(Image object如果我没记错的话,似乎只能在 HTML5 上使用goo.gl/HBeI1i)。有了这个答案中的信息,我已经能够解决问题,我发现它就像一个“开箱即用”的解决方案
2021-04-07 21:56:02

我想我会分享我对此的研究。我需要能够检测是否为某些 file:/// 链接安装了特定的扩展。我在这里看到了这篇文章 这解释了一种获取扩展的 manifest.json 的方法。

我稍微调整了代码并提出:

function Ext_Detect_NotInstalled(ExtName, ExtID) {
  console.log(ExtName + ' Not Installed');
  if (divAnnounce.innerHTML != '')
    divAnnounce.innerHTML = divAnnounce.innerHTML + "<BR>"

  divAnnounce.innerHTML = divAnnounce.innerHTML + 'Page needs ' + ExtName + ' Extension -- to intall the LocalLinks extension click <a href="https://chrome.google.com/webstore/detail/locallinks/' + ExtID + '">here</a>';
}

function Ext_Detect_Installed(ExtName, ExtID) {
  console.log(ExtName + ' Installed');
}

var Ext_Detect = function (ExtName, ExtID) {
  var s = document.createElement('script');
  s.onload = function () { Ext_Detect_Installed(ExtName, ExtID); };
  s.onerror = function () { Ext_Detect_NotInstalled(ExtName, ExtID); };
  s.src = 'chrome-extension://' + ExtID + '/manifest.json';
  document.body.appendChild(s);
}

var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

if (is_chrome == true) {
  window.onload = function () { Ext_Detect('LocalLinks', 'jllpkdkcdjndhggodimiphkghogcpida'); };
}

有了这个,您应该能够使用 Ext_Detect(ExtensionName,ExtensionID) 来检测任意数量的扩展的安装。

看起来谷歌让事情变得更安全,当我运行 Ext_Detect() 时出现以下错误:拒绝加载 chrome-extension://[my_extension_id]/manifest.json。资源必须列在 web_accessible_resources 清单键中,以便由扩展之外的页面加载。
2021-03-11 21:56:02
使用@BJury 答案,您还可以轻松地将数据从扩展传递到脚本(例如扩展版本),并且您不需要从扩展中公开任何文件。
2021-03-19 21:56:02
正如@Lounge9 所说。使用 manifest_version 2(或更高版本)的包内的资源默认阻止,并且必须通过添加到 manifest.json: "web_accessible_resources": [ "manifest..json" ]将其列入白名单以通过此属性使用
2021-03-31 21:56:02
截至 2014 年 2 月 27 日,我可以使用 Chrome 版本 32.0.1700.107 m
2021-04-01 21:56:02
这对我来说效果最好,因为我们的扩展将在多个域中使用,并且由于定期添加新域而无法预定义。我没有访问 manifest.json,而是创建了一个新文件 version.json 并将版本号放入其中。这也是一样的。
2021-04-08 21:56:02

如果您拥有该网站,另一种可能的解决方案是使用内联安装

if (chrome.app.isInstalled) {
  // extension is installed.
}

我知道这是一个老问题,但这种方式是在 Chrome 15 中引入的,所以我认为我只为现​​在正在寻找答案的任何人列出它。

这适用于 Chrome应用程序,但不适用于 Chrome 扩展程序 AFAIK
2021-03-15 21:56:02
2021-03-19 21:56:02
是的,该网站确实会告诉您如何内联安装扩展程序,但显然建议“扩展程序可以通过内容脚本与嵌入页面进行通信,以使其知道它们已经安装。” 而不是能够使用 chrome.app.isInstalled。也迷惑了我...
2021-03-23 21:56:02