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

Javascript 检查用户是否安装了Chrome扩展,javascript,google-chrome,google-chrome-extension,Javascript,Google Chrome,Google Chrome Extension,我正在构建一个Chrome扩展,为了按照我希望的方式工作,我需要一个外部JavaScript脚本来检测用户是否安装了我的扩展 例如:一个用户安装了我的插件,然后转到一个有我脚本的网站。网站检测到我的扩展已安装,并相应地更新页面 这可能吗?您的扩展可以与网站交互,例如更改变量,您的网站可以检测到这一点 但应该有更好的方法来做到这一点。我想知道谷歌在他们的扩展库上是如何做到的,已经安装的应用程序都被标记了 编辑: 画廊使用该功能。例如: chrome.management.get("mblbciej

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

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


这可能吗?

您的扩展可以与网站交互,例如更改变量,您的网站可以检测到这一点

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

编辑:

画廊使用该功能。例如:

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

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

我确信有一种直接方法可以直接调用扩展上的函数,或者使用JS类进行扩展,但在出现更好的方法之前,有一种间接方法:

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

例如:

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

您可以使用扩展,让您的网站JavaScript检查cookie是否存在,并相应地进行更新。当然,这里提到的这个方法和可能的大多数其他方法都可以由用户使用,除非您尝试让扩展根据时间戳等创建自定义cookie,并让您的应用程序在服务器端对其进行分析,以确定它是否真的是具有该扩展的用户,还是通过修改cookie来假装拥有该扩展的用户。

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

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


我知道这是一个老问题,但这种方式是在Chrome 15中引入的,所以我想我现在才把它列出来给任何想知道答案的人。

我想我会分享我在这方面的研究成果。 我需要能够检测是否为某个文件安装了特定的扩展名:///链接才能工作。 我偶然发现了这篇文章 这解释了获取扩展的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_DetectExtensionName、ExtensionID来检测任何数量的扩展的安装。

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/*"]
},
另一种方法是,尽管这将允许任何网站测试是否安装了扩展

假设扩展名的ID为aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

然后,使用web\u可访问的\u资源清单键将此文件公开给网页:

可访问的网络资源:[ test.png ], 在您的网页中,您可以尝试在 注意:如果加载此文件时出错,则控制台中会出现所述网络堆栈错误,无法使其静音。当Chromecast使用这种方法时,它是因为这个;最终,Chrome团队将开发工具中非常具体的错误列入黑名单,这是一个非常丑陋的解决方案

重要提示:此方法在Firefox WebExtensions中不起作用。Web可访问资源固有地将扩展暴露于指纹识别,因为URL可以通过知道ID来预测。Firefox决定通过访问Web可访问资源来关闭该漏洞:

然后,这些文件将使用如下URL可用:

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


但是,虽然扩展可以使用runtime.getURL获取此地址,但您不能在网站中硬编码它。

我使用了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。这种方法是否会很快停止工作是值得怀疑的。

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

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>

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

在内容脚本中,每当加载脚本时,它都应该这样做

if ((window.location.href).includes('*myurl/urlregex*')) {
        $('html').addClass('ifextension');
        }
在你的网站上,你宣称:

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

并抛出适当的消息。

到目前为止,这里的许多答案都是Chrome版的,或者会招致HTTP开销惩罚。我们使用的解决方案有点不同:

1.向清单内容脚本列表添加新对象,如下所示: 这将允许install_notifier.js中的代码在该站点上运行,如果您还没有该站点的权限

2.向上述清单密钥中的每个站点发送消息。 添加类似的内容来安装_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开销或操纵页面。

如果您试图检测任何网站的任何扩展, 这篇文章有助于:

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

以下是另一种现代方法:

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打开扩展名的清单文件-extension://extension_id_here_hkdppipefbchgpohn/manifest.json 并在“web\u可访问的\u资源”部分中查找任何文件名

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


这将要求扩展与每个标签上的每个站点交互,这将是缓慢的/难以实现的,并且存在缺陷:-/问题是,由于chrome的安全模型,页面到扩展的另一个方向的通信是不可能的。如果你不想走“交互”的路,那就走cookie的路。亲爱的@Fox32,chrome.management.get,返回此错误:Uncaught TypeError:无法读取undefinedhmmm chrome.extension的属性“get”。仅当从扩展或任何扩展中执行时,connect似乎才起作用。我需要它从任何随机js脚本工作。有什么想法吗?奇怪,文件上说应该行得通。与其他chrome.*API不同,chrome.extension的某些部分可由内容脚本使用,它列出sendRequest、onRequest、connect、onRequest和getURL。@James您正在执行使用的脚本。从托管脚本连接吗?我知道Chrome努力避免只处理本地文件,而这些文件不是出于安全目的托管的。-正在检查。@James我正在执行的脚本。如果这是您的意思,则“连接自”位于同一服务器上?最后一个方法不再有效,因为“连接”函数已移动到chrome.runtime命名空间。请参阅BJury的答案和评论,了解更为最新的版本,只要您知道您的扩展ID(我相信您知道),就可以检测扩展。查看此网站了解更多信息:跳到“逐个查找您的加载项”部分。祝你好运BJury bellow描述了实现这一点的正确方法。这篇文章有帮助:看起来谷歌让事情变得更安全了,我在运行Ext_Detect时遇到以下错误:拒绝加载chrome扩展名://[my_extension_id]/manifest.json。资源必须列在web_accessible_Resources manifest键中,才能由扩展之外的页面加载。我能够在截至2014年2月27日的Chrome版本32.0.1700.107 m上实现这一点。使用manifest_version 2或更高版本的包中的资源是,并且必须通过此属性添加到manifest.json:web_-accessible_-Resources:[manifest..json],使用@BJury answer,您还可以轻松地将数据从扩展名传递到脚本(例如扩展名版本),您不需要公开扩展名中的任何文件。这对我来说最为有效,因为我们的扩展名将跨多个域使用,并且无法在定期添加新域时预定义。我没有访问manifest.json,而是创建了一个新文件version.json,并将版本号放入其中。这同样适用于Chrome应用程序,但不适用于Chrome扩展AFAIKYep。该网站确实会告诉您如何内联安装扩展,但显然建议扩展可以通过内容脚本与嵌入页面通信,让它知道它们已经安装。而不是能够使用chrome.app.i安装。我也很困惑…这就像一个符咒。另一个缺点当然是您必须控制扩展-您不能使用它来查看是否安装了任意的第三方扩展。@EricP最初的问题是他们正在编写
您还必须将以下内容添加到manifest.json中:外部可连接:{matches:[://.yourdomain.com/*]}它应该是{version:'1.0'}而不是{version:1.0}否则,您将在extension Inspect视图控制台中获得“Uncaught SyntaxError:意外数字”。在检查端,网页试图检查给定扩展的可用性,chrome.runtime未定义,linux上的chrome 36。尽管此答案来自,IMHO添加了一些非常重要的信息,比如在扩展中公开资源,以及可以使用ajax请求检查图像对象是否存在,这似乎只有在我没有错的情况下,才能在HTML5上使用。有了这个答案中的信息,我已经能够解决这个问题,我发现它就像一个开箱即用的东西solution@niconic答案是坏的,因为链接只是指清单版本2生效之前的情况。以前,不需要声明资源为web可访问。唯一的问题是,如果用户删除了您的扩展。cookie可能会保持不变。好的。我们如何检查扩展图标是否存在?我尝试了上面所有的解决方案,但都不起作用,然后我看到了你的答案,这就是我要找的!这会增加以后每个HTTP请求的开销。我已经测试过了,但操作顺序似乎很奇怪-哪个脚本先运行等等?@BradyMoritz,与答案中的顺序相同。首先添加类,然后断言。看起来我的内容脚本不一定在我的页面内脚本之前运行?我认为这很容易修复。您可以确保您的内容脚本在使用regex点击所需的URL/路由后立即运行。您尝试过吗?如上所述-我已经测试过,但操作顺序似乎很奇怪-哪个脚本首先运行等?在Firefox WebExtensions上不起作用,不支持外部可连接的。请确保更新清单以允许访问资源:web可访问的资源:[icons/*.png]
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')
})
<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>