我正在构建 Chrome 扩展程序,为了让整个事情按照我希望的方式工作,我需要一个外部 JavaScript 脚本来检测用户是否安装了我的扩展程序。
例如:用户安装了我的插件,然后访问一个带有我的脚本的网站。该网站检测到我的扩展程序已安装并相应地更新页面。
这可能吗?
我正在构建 Chrome 扩展程序,为了让整个事情按照我希望的方式工作,我需要一个外部 JavaScript 脚本来检测用户是否安装了我的扩展程序。
例如:用户安装了我的插件,然后访问一个带有我的脚本的网站。该网站检测到我的扩展程序已安装并相应地更新页面。
这可能吗?
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
}
我确定有一种直接的方法(直接调用扩展上的函数,或使用 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);
另一种方法是公开 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()
获取此地址,但您不能在您的网站中对其进行硬编码。
我想我会分享我对此的研究。我需要能够检测是否为某些 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) 来检测任意数量的扩展的安装。
如果您拥有该网站,另一种可能的解决方案是使用内联安装。
if (chrome.app.isInstalled) {
// extension is installed.
}
我知道这是一个老问题,但这种方式是在 Chrome 15 中引入的,所以我认为我只为现在正在寻找答案的任何人列出它。