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

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

例如: 一个用户安装我的插件,然后去一个网站上我的脚本。该网站检测到我的扩展安装和更新相应的网页。

这可能吗?

138936 次浏览

你的扩展可以与网站互动(例如变化的变量) ,你的网站可以检测到这一点。

但应该有更好的办法。我想知道谷歌是如何在他们的扩展库中做到这一点的(已经安装的应用程序被标记)。

编辑:

图库使用 Chrome 管理层函数。示例:

chrome.management.get("mblbciejcodpealifnhfjbdlkedplodp", function(a){console.log(a);});

但是您只能从具有正确权限的页面访问该方法。

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

Have your Chrome extension look for a specific DIV or other element on your page, with a very specific ID.

例如:

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

Do a getElementById and set the innerHTML to the version number of your extension or something. You can then read the contents of that client-side.

但是,如果有可用的方法,则应该使用直接方法。


编辑: 找到直接方法! !

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

未经测试,但你应该可以..。

var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);

您可以使用扩展 放一块饼干,并让您的网站 JavaScript 检查 cookie 是否存在,并相应地进行更新。这里提到的这个方法和其他大多数方法当然可以被用户回避,除非你尝试让扩展根据时间戳创建自定义 cookie 等,让你的应用程序分析它们服务器端,看看它们是否真的是一个拥有扩展的用户,或者有人通过修改他的 cookies 来假装拥有它。

这个谷歌群组的帖子中显示了另一种方法。简而言之,您可以尝试检测扩展图标是否成功加载。如果您正在检查的分机不是您自己的分机,这可能会有所帮助。

另一个可能的解决方案,如果你自己的网站是使用 嵌入式安装嵌入式安装

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

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

我想我可以分享一下我的研究成果。 我需要能够检测是否为某个文件安装了特定的扩展名:///link to work。 我偶然发现了这篇文章 给你 这解释了一种获取扩展的 Manif.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)来检测任意数量的扩展的安装。

Chrome 现在可以将信息从网站发送到扩展。

因此,在扩展 backound.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;
}
});

You can then check the hasExtension variable. The only drawback is the call is asynchronous, so you have to work around that somehow.

编辑: 正如下面提到的,您需要添加一个条目到 宣言 Json中,列出可以向您的插件发送消息的域。例如:

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

2021年更新: chrome.runtime.sendMessage will throw the following exception in console if the extension isn't installed or it's disabled.

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

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

if (chrome.runtime.lastError) {
// handle error
}

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

假设您的扩展的 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 团队从开发工具(Dev Tools)中整合出来的 将非常具体的错误列入黑名单


重要提示: 此方法在 Firefox WebExtended 中无法工作。Web 访问的资源本质上将扩展暴露给指纹识别,因为通过了解 ID 可以预测 URL。Firefox 决定通过 分配特定于实例的随机 URL来弥补这个漏洞:

这些文件可以通过如下 URL 获得:

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

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

然而,虽然扩展可以使用 runtime.getURL()来获得这个地址,但是你不能在你的网站上硬编码它。

我用了 cookie 的方法:

在我的 Manif.js 文件中,我包含了一个只能在我的站点上运行的内容脚本:

 "content_scripts": [
{
"matches": [
"*://*.mysite.co/*"
],
"js": ["js/mysite.js"],
"run_at": "document_idle"
}
],

在我的 js/mysite.js 里有一句话:

document.cookie = "extension_downloaded=True";

然后在 index.html 页面中寻找这个 cookie。

if (document.cookie.indexOf('extension_downloaded') != -1){
document.getElementById('install-btn').style.display = 'none';
}

如果你可以控制 Chrome 扩展,你可以试试我所做的:

// Inside Chrome extension
var div = document.createElement('div');
div.setAttribute('id', 'myapp-extension-installed-div');
document.getElementsByTagName('body')[0].appendChild(div);

然后:

// On web page that needs to detect extension
if ($('#myapp-extension-installed-div').length) {


}

这感觉有点古怪,但我不能让其他方法工作,我担心 Chrome 改变它的 API 在这里。这种方法是否会很快停止工作是值得怀疑的。

网页通过后台脚本与扩展进行交互。

Json:

"background": {
"scripts": ["background.js"],
"persistent": true
},
"externally_connectable": {
"matches": ["*://(domain.ext)/*"]
},


background.js:
chrome.runtime.onMessageExternal.addListener(function(msg, sender, sendResponse) {
if ((msg.action == "id") && (msg.value == id))
{
sendResponse({id : id});
}
});

page.html:

<script>
var id = "some_ext_id";
chrome.runtime.sendMessage(id, {action: "id", value : id}, function(response) {
if(response && (response.id == id)) //extension installed
{
console.log(response);
}
else //extension not installed
{
console.log("Please consider installig extension");
}


});
</script>

You could also use a cross-browser method what I have used. 使用添加 div 的概念。

在您的内容脚本中(无论何时加载脚本,它都应该这样做)

if ((window.location.href).includes('*myurl/urlregex*')) {
$('html').addClass('ifextension');
}

在你的网站上你断言,

if (!($('html').hasClass('ifextension')){}

传递适当的信息。

A lot of the answers here so far are Chrome only or incur an HTTP overhead penalty. The solution that we are using is a little different:

1. 向清单 content _ script 列表添加一个新对象,如下所示:

{
"matches": ["https://www.yoursite.com/*"],
"js": [
"install_notifier.js"
],
"run_at": "document_idle"
}

这将允许 install _ notifier. js 中的代码在该站点上运行(如果您在那里还没有权限的话)。

2. 向上面清单密钥中的每个站点发送消息。

向 install _ notifier 添加类似的内容。Js (注意,这里使用了一个闭包来避免变量是全局的,但是这并不是必须的) :

// Dispatch a message to every URL that's in the manifest to say that the extension is
// installed.  This allows webpages to take action based on the presence of the
// extension and its version. This is only allowed for a small whitelist of
// domains defined in the manifest.
(function () {
let currentVersion = chrome.runtime.getManifest().version;
window.postMessage({
sender: "my-extension",
message_name: "version",
message: currentVersion
}, "*");
})();

Your message could say anything, but it's useful to send the version so you know what you're dealing with. Then...

在你的网站上,收听这条信息。

把这个添加到你的网站:

window.addEventListener("message", function (event) {
if (event.source == window &&
event.data.sender &&
event.data.sender === "my-extension" &&
event.data.message_name &&
event.data.message_name === "version") {
console.log("Got the message");
}
});

这可以在 Firefox 和 Chrome 中使用,并且不会导致 HTTP 开销或操作页面。

如果你想检测任何网站的扩展, 这篇文章有所帮助: < a href = “ https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7”rel = “ nofollow noReferrer”> https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7

基本上,解决方案是通过指定扩展名的路径来从扩展名获取特定的文件(Manif.json 或图像)。这是我用过的。绝对有效:

const imgExists = function(_f, _cb) {
const __i = new Image();
__i.onload = function() {
if (typeof _cb === 'function') {
_cb(true);
}
}
__i.onerror = function() {
if (typeof _cb === 'function') {
_cb(false);
}
}
__i.src = _f;
__i = null;
});


try {
imgExists("chrome-extension://${CHROME_XT_ID}/xt_content/assets/logo.png", function(_test) {
console.log(_test ? 'chrome extension installed !' : 'chrome extension not installed..');
ifrm.xt_chrome = _test;
// use that information
});
} catch (e) {
console.log('ERROR', e)
}

下面是另一种现代方法:

const checkExtension = (id, src, callback) => {
let e = new Image()
e.src = 'chrome-extension://'+ id +'/'+ src
e.onload = () => callback(1), e.onerror = () => callback(0)
}


// "src" must be included to "web_accessible_resources" in manifest.json
checkExtension('gighmmpiobklfepjocnamgkkbiglidom', 'icons/icon24.png', (ok) => {
console.log('AdBlock: %s', ok ? 'installed' : 'not installed')
})
checkExtension('bhlhnicpbhignbdhedgjhgdocnmhomnp', 'images/checkmark-icon.png', (ok) => {
console.log('ColorZilla: %s', ok ? 'installed' : 'not installed')
})

下面是如何检测已安装的特定扩展并显示警告消息。

首先,您需要打开扩展名的清单文件,方法是访问 chrome 扩展名://扩展名 _ id _ here _ hkdppipfbchgpohn/Manif.json,并在“ web _ access _ resources”部分中查找任何文件名。

<div class="chromewarning" style="display:none">
<script type="text/javascript">
$.get("chrome-extension://extension_id_here_hkdppipefbchgpohn/filename_found_in_ web_accessible_resources.png").done(function () {
$(".chromewarning").show();
}).fail(function () {
//  alert("failed.");
});
</script>
<p>We have detected a browser extension that conflicts with learning modules in this course.</p>
</div>