Jestem w trakcie tworzenia rozszerzenia do Chrome i aby wszystko działało tak, jak bym chciał, potrzebuję zewnętrznego skryptu JavaScript, aby móc wykryć, czy użytkownik ma zainstalowane moje rozszerzenie.
Na przykład: użytkownik instaluje moją wtyczkę, a następnie przechodzi do witryny internetowej z moim skryptem. Witryna wykrywa, że moje rozszerzenie jest zainstalowane i odpowiednio aktualizuje stronę.
czy to możliwe?
javascript
google-chrome
google-chrome-extension
Yehuda Katz
źródło
źródło
Odpowiedzi:
Jestem pewien, że istnieje sposób bezpośredni (wywołanie funkcji bezpośrednio na twoim rozszerzeniu lub użycie klas JS do rozszerzeń), ale metoda pośrednia (dopóki nie pojawi się coś lepszego):
Poproś rozszerzenie do Chrome o wyszukanie na stronie określonego DIV lub innego elementu z bardzo konkretnym identyfikatorem.
Na przykład:
<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>
Zrób a
getElementById
i ustawinnerHTML
numer wersji swojego rozszerzenia lub coś w tym stylu. Następnie możesz przeczytać zawartość tej strony klienta.Ponownie jednak powinieneś użyć metody bezpośredniej, jeśli jest dostępna.
EDYCJA: Znaleziono metodę bezpośrednią !!
Skorzystaj z metod połączenia, które znajdziesz tutaj: https://developer.chrome.com/extensions/extension#global-events
Nie przetestowano, ale powinieneś być w stanie to zrobić ...
var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);
źródło
sendRequest()
,onRequest
,connect()
,onRequest
, igetURL()
.connect
funkcja została przeniesiona dochrome.runtime
przestrzeni nazw. Zobacz odpowiedź (i komentarze) BJury, aby uzyskać bardziej aktualną wersjęChrome ma teraz możliwość wysyłania wiadomości ze strony internetowej do rozszerzenia.
Więc w rozszerzeniu background.js (content.js nie będzie działać) dodaj coś takiego:
chrome.runtime.onMessageExternal.addListener( function(request, sender, sendResponse) { if (request) { if (request.message) { if (request.message == "version") { sendResponse({version: 1.0}); } } } return true; });
Umożliwi to nawiązanie połączenia ze strony internetowej:
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; } });
Następnie możesz sprawdzić zmienną hasExtension. Jedyną wadą jest to, że wywołanie jest asynchroniczne, więc musisz jakoś to obejść.
Edycja: Jak wspomniano poniżej, musisz dodać wpis do pliku manifest.json zawierający listę domen, z których można wysyłać wiadomości do Twojego dodatku. Na przykład:
"externally_connectable": { "matches": ["*://localhost/*", "*://your.domain.com/*"] },
źródło
Inną metodą jest udostępnienie zasobu dostępnego w sieci , chociaż pozwoli to dowolnej witrynie na sprawdzenie, czy rozszerzenie jest zainstalowane.
Załóżmy, że identyfikator rozszerzenia to
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
i dodajesz plik (powiedzmy przezroczysty obraz pikselowy) jakotest.png
w plikach rozszerzenia.Następnie udostępniasz ten plik na stronach internetowych za pomocą
web_accessible_resources
klucza manifestu:"web_accessible_resources": [ "test.png" ],
Na swojej stronie internetowej możesz spróbować załadować ten plik
<img>
, używając pełnego adresu URL (w tagu, przez XHR lub w inny sposób):chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.png
Jeśli plik zostanie załadowany, rozszerzenie zostanie zainstalowane. Jeśli podczas ładowania tego pliku wystąpi błąd, rozszerzenie nie jest zainstalowane.
// 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); }; }
Uwaga: jeśli wystąpi błąd podczas ładowania tego pliku, wspomniany stos sieciowy błąd pojawi się w konsoli bez możliwości jego wyciszenia. Kiedy Chromecast używał tej metody, wywołało to sporo kontrowersji z tego powodu; z ostatecznym bardzo brzydkim rozwiązaniem polegającym na umieszczeniu na czarnej liście bardzo konkretnych błędów z Narzędzi dla programistów przez zespół Chrome.
Ważna uwaga: ta metoda nie będzie działać w Firefox WebExtensions. Zasoby dostępne w sieci z natury narażają rozszerzenie na odciski palców, ponieważ adres URL jest przewidywalny dzięki znajomości identyfikatora. Firefox postanowił zamknąć tę lukę, przypisując losowy adres URL specyficzny dla instancji do zasobów dostępnych w sieci:
Jednak chociaż rozszerzenie może użyć
runtime.getURL()
do uzyskania tego adresu, nie można go na stałe zakodować w swojej witrynie.źródło
Pomyślałem, że podzielę się moimi badaniami na ten temat. Musiałem być w stanie wykryć, czy jest zainstalowane określone rozszerzenie, aby niektóre linki file: /// działały. Natknąłem się tutaj na ten artykuł. Wyjaśniło to metodę uzyskiwania pliku manifest.json rozszerzenia.
Poprawiłem nieco kod i wymyśliłem:
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'); }; }
Dzięki temu powinieneś być w stanie użyć Ext_Detect (ExtensionName, ExtensionID) do wykrywania instalacji dowolnej liczby rozszerzeń.
źródło
Innym możliwym rozwiązaniem, jeśli jesteś właścicielem witryny, jest instalacja bezpośrednia .
if (chrome.app.isInstalled) { // extension is installed. }
Wiem, że to stare pytanie, ale w ten sposób zostało wprowadzone w Chrome 15, więc pomyślałem, że wymienię je dla każdego, kto dopiero teraz szuka odpowiedzi.
źródło
Wykorzystałem metodę cookies:
W moim pliku manifest.js umieściłem skrypt zawartości, który działa tylko w mojej witrynie:
"content_scripts": [ { "matches": [ "*://*.mysite.co/*" ], "js": ["js/mysite.js"], "run_at": "document_idle" } ],
w moim js / mysite.js mam jedną linię:
document.cookie = "extension_downloaded=True";
i na mojej stronie index.html szukam tego pliku cookie.
if (document.cookie.indexOf('extension_downloaded') != -1){ document.getElementById('install-btn').style.display = 'none'; }
źródło
Rozszerzenie może ustawić plik cookie i poprosić JavaScript witryny, aby sprawdzał, czy ten plik cookie jest obecny, i odpowiednio aktualizuje. Ta i prawdopodobnie większość innych wymienionych tutaj metod może oczywiście zostać omówione przez użytkownika, chyba że spróbujesz i rozszerzenie utworzy niestandardowe pliki cookie w zależności od sygnatur czasowych itp., A aplikacja przeanalizuje je po stronie serwera, aby sprawdzić, czy naprawdę jest to użytkownik z rozszerzenie lub ktoś udaje, że je posiada, modyfikując swoje pliki cookie.
źródło
Istnieje inna metoda pokazana w tym poście w Grupach dyskusyjnych Google . Krótko mówiąc, możesz spróbować wykryć, czy ikona rozszerzenia ładuje się pomyślnie. Może to być pomocne, jeśli szukane rozszerzenie nie jest Twoim własnym.
źródło
Strona internetowa współdziała z rozszerzeniem poprzez skrypt działający w tle.
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>
źródło
Twoje rozszerzenie może wchodzić w interakcje z witryną (np. Zmieniać zmienne), a witryna może to wykryć.
Ale powinien istnieć lepszy sposób, aby to zrobić. Ciekawe, jak Google to robi na swojej galerii rozszerzeń (zaznaczone są już zainstalowane aplikacje).
Edytować:
Galeria korzysta z funkcji chrome.management.get . Przykład:
chrome.management.get("mblbciejcodpealifnhfjbdlkedplodp", function(a){console.log(a);});
Ale możesz uzyskać dostęp do metody tylko ze stron z odpowiednimi uprawnieniami.
źródło
Uncaught TypeError: Cannot read property 'get' of undefined
Wiele odpowiedzi tutaj do tej pory dotyczy tylko Chrome lub wiąże się z karą narzutu HTTP. Rozwiązanie, z którego korzystamy, jest trochę inne:
1. Dodaj nowy obiekt do listy manifestu content_scripts w następujący sposób:
{ "matches": ["https://www.yoursite.com/*"], "js": [ "install_notifier.js" ], "run_at": "document_idle" }
Umożliwi to uruchomienie kodu z pliku install_notifier.js w tej witrynie (jeśli nie masz tam jeszcze uprawnień).
2. Wyślij wiadomość do każdej witryny w powyższym kluczu manifestu.
Dodaj coś takiego do pliku install_notifier.js (zwróć uwagę, że jest to użycie zamknięcia, aby zmienne nie były globalne, ale nie jest to bezwzględnie konieczne):
// 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 }, "*"); })();
Twoja wiadomość może mówić wszystko, ale warto wysłać wersję, aby wiedzieć, z czym masz do czynienia. Następnie...
3. W witrynie posłuchaj tego komunikatu.
Dodaj to gdzieś do swojej witryny:
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"); } });
Działa to w przeglądarkach Firefox i Chrome i nie powoduje obciążenia HTTP ani nie manipuluje stroną.
źródło
Oto inne nowoczesne podejście:
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') })
źródło
Jeśli masz kontrolę nad rozszerzeniem Chrome, możesz spróbować tego, co zrobiłem:
// Inside Chrome extension var div = document.createElement('div'); div.setAttribute('id', 'myapp-extension-installed-div'); document.getElementsByTagName('body')[0].appendChild(div);
I wtedy:
// On web page that needs to detect extension if ($('#myapp-extension-installed-div').length) { }
Wydaje się to trochę hakerskie, ale nie mogłem uruchomić innych metod i martwię się, że Chrome zmieni tutaj swoje API. Wątpliwe, że ta metoda wkrótce przestanie działać.
źródło
Możesz także użyć metody cross-browser, której użyłem. Używa koncepcji dodawania div.
w skrypcie treści (powinien to zrobić za każdym razem, gdy skrypt się ładuje)
if ((window.location.href).includes('*myurl/urlregex*')) { $('html').addClass('ifextension'); }
na swojej stronie zapewniasz coś takiego,
if (!($('html').hasClass('ifextension')){}
I wyślij odpowiednią wiadomość.
źródło
Jeśli próbujesz wykryć jakiekolwiek rozszerzenie z dowolnej strony internetowej, ten post pomógł: https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7
Zasadniczo rozwiązaniem byłoby po prostu spróbować pobrać określony plik (manifest.json lub obraz) z rozszerzenia, określając jego ścieżkę. Oto, czego użyłem. Zdecydowanie działające:
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) }
źródło
Oto, jak możesz wykryć określone zainstalowane rozszerzenie i wyświetlić komunikat ostrzegawczy.
Najpierw musisz otworzyć plik manifestu rozszerzenia, przechodząc do chrome-extension: //extension_id_here_hkdppipefbchgpohn/manifest.json i poszukaj dowolnej nazwy pliku w sekcji „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>
źródło