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

我正在建立一个Chrome扩展,整个事情的工作方式,我希望它,我需要一个外部的JavaScript脚本能够检测到,如果用户有我的扩展安装。

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

这可能吗?

我确定有一个直接的方法(直接调用你的扩展的函数,或者使用JS类的扩展),而是一个间接的方法(直到更好的东西出现):

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

例如:

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

做一个getElementById并将innerHTML设置为您的扩展的版本号或者其他。 然后你可以读取客户端的内容。

同样,如果有一个可用的,你应该使用直接的方法。


编辑:直接的方法发现!

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

未经测试,但你应该可以做…

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

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/*"] }, 

另一种方法是公开一个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使用这种方法时,由于这个原因, 引起了相当多的争议 。 最终非常丑陋的解决方案只是简单地来自Dev Tools的非常具体的错误列入 Chrome团队。


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

这些文件将可以使用像这样的URL:

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

这个UUID是为每个浏览器实例随机生成的,而不是你的扩展的ID。 这可以防止网站指纹用户安装的扩展名。

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

我以为我会分享我的研究。 我需要能够检测某个文件是否安装了特定的扩展名:///链接才能工作。 我在这里遇到了这篇文章这解释了获取扩展名的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中引入的,所以我认为Id列出了任何人只有现在寻找答案。

在这个Google网上论坛帖子中显示了另一种方法。 总之,您可以尝试检测扩展图标是否加载成功。 如果您要检查的扩展名不是您自己的,这可能会有所帮助。

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

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

编辑:

图库使用chrome.management.get函数。 例:

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

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

你可以让扩展名设置一个cookie ,让你的网站JavaScript检查该cookie是否存在,并相应地更新。 当然这里提到的大多数其他的方法当然可以被用户饶恕, 除非你试着让扩展创建定制的cookie,这取决于时间戳等,并让你的应用程序分析它们在服务器端,看看它是否真的是一个用户扩展名或者通过修改他的cookie来假装拥有它的人。

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

manifest.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> 

我使用了cookie方法:

在我的manifest.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。 这种方法很快就会停止工作,这是值得怀疑的。

你也可以使用我用过的一个跨浏览器的方法。 使用添加div的概念。

在你的内容脚本中(每当脚本加载,它应该这样做)

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

在你的网站你断言的东西,

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

并抛出适当的信息。