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

时间:2011-06-09 13:27:17

标签: javascript google-chrome google-chrome-extension

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

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

这可能吗?

16 个答案:

答案 0 :(得分:98)

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

答案 1 :(得分:41)

我确信有一种直接的方式(直接调用扩展函数,或者使用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);

答案 2 :(得分:18)

另一种方法是expose a web-accessible resource,但这将允许任何网站测试您的扩展程序是否已安装。

假设您的扩展程序ID为aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,并在扩展程序的文件中添加test.png文件(例如透明像素图片)。

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

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

在您的网页中,您可以尝试按其完整网址(<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使用此方法时,caused quite a bit of controversy就是这样;最简单的解决方案是Chrome团队完全从Dev Tools中将列入非常具体的错误


重要说明:此方法在Firefox WebExtensions中无效。 Web可访问资源固有地将扩展名暴露给指纹识别,因为通过知道ID可以预测URL。 Firefox决定通过assigning an instance-specific random URL将这个漏洞关闭到可访问的Web资源:

  

然后可以使用以下网址获取文件:

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

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

但是,虽然扩展程序可以使用runtime.getURL()来获取此地址,但您无法在自己的网站中对其进行硬编码。

答案 3 :(得分:17)

我以为我会分享我对此的研究。 我需要能够检测是否为某些文件安装了特定的扩展名:///链接工作。 我看到了这篇文章here 这解释了获取扩展的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)来检测任意数量扩展的安装。

答案 4 :(得分:7)

如果您拥有该网站,另一种可能的解决方案是使用inline installation

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

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

答案 5 :(得分:4)

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

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

修改

图库使用chrome.management.get功能。例如:

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

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

答案 6 :(得分:3)

您可以使用扩展程序set a cookie并让您的网站JavaScript检查该Cookie是否存在并相应更新。这个以及可能在此提到的大多数其他方法当然可以被用户阻止,除非您尝试让扩展根据时间戳等创建自定义cookie,并让您的应用程序分析它们服务器端以查看是否它实际上是一个带扩展名的用户,或者是一个假装通过修改他的cookie而拥有它的人。

答案 7 :(得分:3)

this Google Groups post显示了另一种方法。简而言之,您可以尝试检测扩展图标是否成功加载。如果您要检查的扩展程序不是您自己的扩展程序,这可能会有所帮助。

答案 8 :(得分:3)

我使用了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';
}

答案 9 :(得分:3)

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

的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>

答案 10 :(得分:3)

到目前为止,很多答案都只是Chrome或者会产生HTTP开销。我们使用的解决方案略有不同:

1。将新对象添加到清单content_scripts列表中,如下所示:

{
  "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
  }, "*");
})();

您的邮件可以说什么,但发送版本对您有用,因此您知道自己要处理的内容。然后...

3。在您的网站上,收听该消息。

将其添加到您的网站:

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开销或操纵页面。

答案 11 :(得分:2)

这是另一种现代方法:

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')
})

答案 12 :(得分:0)

如果您可以控制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) {

}

感觉有点hacky,但我无法使用其他方法,我担心Chrome会在这里更改其API。令人怀疑的是,这种方法很快就会停止工作。

答案 13 :(得分:0)

您也可以使用我使用的跨浏览器方法。 使用添加div的概念。

在您的内容脚本中(无论何时加载脚本,都应该执行此操作)

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

在您的网站中,您声明了类似的内容,

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

并发出适当的信息。

答案 14 :(得分:0)

如果您尝试检测来自任何网站的任何扩展名, 这篇文章对您有帮助:https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7

基本上,解决方案是简单地尝试通过指定扩展名的路径从扩展名中获取特定文件(manifest.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)
}

答案 15 :(得分:0)

在这里,您可以检测到已安装的特定扩展并显示警告消息。

首先,您需要转到chrome-extension://extension_id_here_hkdppipefbchgpohn/manifest.json打开扩展的清单文件,并在“ web_accessible_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>