簡體   English   中英

檢查用戶是否安裝了 Chrome 擴展程序

[英]Check whether user has a Chrome extension installed

我正在構建一個 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 變量。 唯一的缺點是調用是異步的,所以你必須以某種方式解決這個問題。

編輯:如下所述,您需要在清單中添加一個條目。json列出可以向您的插件發送消息的域。 例如:

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

2021 年更新:如果未安裝擴展程序或將其禁用, chrome.runtime.sendMessage將在控制台中引發以下異常。

未選中 runtime.lastError: 無法建立連接。 接收端不存在

要解決此問題,請在sendMessage回調中添加此驗證

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

我確信有一種直接的方法(直接在擴展上調用函數,或者使用 JS 類進行擴展),但有一種間接的方法(直到出現更好的方法):

讓您的 Chrome 擴展程序在您的頁面上查找具有非常特定 ID 的特定 DIV 或其他元素。

例如:

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

另一種方法是公開一個 Web 可訪問的資源,盡管這將允許任何網站測試您的擴展是否已安裝。

假設您的擴展程序的 ID 是aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ,並且您在擴展程序的文件中添加了一個文件(例如,透明像素圖像)作為test.png

然后,使用web_accessible_resources清單鍵將此文件公開給 web 頁面:

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

在您的 web 頁面中,您可以嘗試通過其完整的 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 決定通過將特定於實例的隨機 URL 分配給 web 可訪問資源來關閉該漏洞:

然后,這些文件將使用 URL 提供,例如:

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

此 UUID 是為每個瀏覽器實例隨機生成的,不是您的擴展程序的 ID。 這可以防止網站對用戶安裝的擴展程序進行指紋識別。

但是,雖然擴展程序可以使用runtime.getURL()來獲取此地址,但您不能在您的網站中對其進行硬編碼。

我想我會分享我對此的研究。 我需要能夠檢測是否為某些 file:/// 鏈接安裝了特定的擴展程序才能正常工作。 我在這里遇到了這篇文章 這解釋了一種獲取擴展名的方法。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 中引入的,所以我認為我只為現在尋找答案的任何人列出它。

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

網頁通過后台腳本與擴展交互。

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

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

到目前為止,這里的很多答案都只是 Chrome,否則會導致 HTTP 開銷損失。 我們使用的解決方案有點不同:

1. 將新的 object 添加到清單 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 開銷或操作頁面。

您的擴展程序可以與網站交互(例如更改變量)並且您的網站可以檢測到這一點。

但是應該有更好的方法來做到這一點。 我想知道谷歌在他們的擴展庫上是如何做到的(已經安裝的應用程序被標記)。

編輯:

圖庫使用chrome.management.get function。 例子:

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

但是您只能從具有正確權限的頁面訪問該方法。

您可以讓擴展程序設置一個 cookie ,並讓您的網站 JavaScript 檢查該 cookie 是否存在並相應更新。 用戶當然可以繞過這里提到的這種方法以及可能的大多數其他方法,除非您嘗試讓擴展程序根據時間戳等創建自定義 cookies,並讓您的應用程序在服務器端分析它們以查看它是否真的是具有擴展名或有人通過修改他的 cookies 來假裝擁有它。

此 Google Groups 帖子中顯示了另一種方法。 簡而言之,您可以嘗試檢測擴展圖標是否加載成功。 如果您要檢查的擴展程序不是您自己的,這可能會有所幫助。

這是另一種現代方法:

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 的概念。

在您的內容腳本中(每當腳本加載時,它都應該這樣做)

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

在您的網站中,您斷言類似,

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

並拋出適當的信息。

如果您可以控制 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。 值得懷疑的是,這種方法很快就會停止工作。

如果您試圖檢測來自任何網站的任何擴展,這篇文章有幫助: 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)
}

以下是如何檢測安裝的特定擴展並顯示警告消息的方法。

首先,您需要通過 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>

Chrome 擴展清單 v3:

const isFirefox = chrome.runtime.OnInstalledReason.CHROME_UPDATE != "chrome_update";

對於 FireFox,我相信chrome.runtime.OnInstalledReason.BROWSER_UPDATE將是“browser_update”: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/OnInstalledReason

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM