ユーザーがChrome拡張機能をインストールしているかどうかを確認する


96

私はChrome拡張機能を作成している最中です。全体を思い通りに機能させるには、ユーザーが私の拡張機能をインストールしているかどうかを検出できる外部JavaScriptスクリプトが必要です。

例:ユーザーがプラグインをインストールしてから、スクリプトを実行しているWebサイトにアクセスします。ウェブサイトは私の拡張機能がインストールされていることを検出し、それに応じてページを更新します。

これは可能ですか?


2
はい、拡張機能IDを知っていれば、拡張機能を検出することは可能です(確かにそうです)。詳細については、このサイトを確認してください。blog.kotowicz.net / 2012/02 / intro-to-chrome-addons-hacking.html「アドオンを1つずつ検索する」のセクションまでスキップしてください。幸運を!
マーティンヒューズ

これを実装する適切な方法は、BJuryのうなり声で説明されています。
Rahatur、2018年

この投稿は役に立ち

回答:


46

私は直接的な方法(拡張機能で関数を直接呼び出すか、拡張機能のJSクラスを使用して)があると確信していますが、間接的な方法(より良いものが来るまで):

Chrome拡張機能に、非常に具体的なIDを持つページ上の特定のDIVまたはその他の要素を検索させる。

例えば:

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

a getElementByIdを実行しinnerHTMLて、拡張機能のバージョン番号などに設定します。その後、そのクライアント側のコンテンツを読み取ることができます。

繰り返しになりますが、直接的な方法がある場合は、それを使用する必要があります。


編集:ダイレクトメソッドが見つかりました!!

ここにある接続方法を使用してくださいhttps : //developer.chrome.com/extensions/extension#global-events

未テストですが、実行できるはずです...

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

2
hmmm chrome.extension.connectは、拡張機能(または任意の拡張機能)内から実行した場合にのみ機能するようです。任意のjsスクリプトから動作させるために必要です。何か案は?

奇妙なことに、ドキュメントはそれがうまくいくはずだと言っています。「他のクローム。*のAPIとは異なり、chrome.extensionの部分は、コンテンツスクリプトで使用することができます」と、それが一覧表示されますsendRequest()onRequestconnect()onRequest、とgetURL()
ブラッド

@Jamesは、ホストされているスクリプトから.connect()を使用するスクリプトを実行していますか?Chromeは、セキュリティ上の目的でホストされていないローカルファイルだけを使用しないように努めています。- チェックしてるだけ。
JamesEggers

@James私が.connect()を実行しているスクリプトは、それがあなたの意味する場合、同じサーバー上にありますか?

23
connect関数がchrome.runtime名前空間に移動されたため、最後のメソッドは無効なりました。最新バージョンについては、BJuryの回答(およびコメント)を参照してください
Xan

115

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

これにより、Webサイトから電話をかけることができます。

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

2
これは魅力のように機能します。もちろん、もう1つの欠点は、拡張機能を制御する必要があることです。これを使用して、任意のサードパーティの拡張機能がインストールされているかどうかを確認することはできません。
エリックP

2
@EricP元の質問では拡張機能を作成していると述べられているため、問題はありません。
BJury 2014年

11
manifest.jsonに次を追加する必要もあります: "externally_connectable":{"matches":[" :// .yourdomain.com / *"]}
noname

3
{version: '1.0'}であり、{version:1.0}ではない必要があります。そうしないと、拡張機能のInspectビューコンソールに「Uncaught SyntaxError:Unexpected number」が表示されます。
ET-CS

1
「チェック」側(特定の拡張機能の可用性をチェックしようとしているWebページ)では、chrome.runtimeは未定義で、Linuxではchrome 36です。
15

22

別の方法は、Webアクセス可能なリソース公開することですが、これにより、どの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チームがDev Toolsからの非常に特定のエラーを単にブラックリストに登録するという、最終的には非常に醜いソリューションです。


重要な注意:このメソッドはFirefox WebExtensionsでは機能しません。URLはIDを知ることで予測できるため、Webアクセス可能なリソースは本質的に拡張機能をフィンガープリントに公開します。Firefoxは、インスタンス固有のランダムURLをWebアクセス可能なリソースに割り当てることによりその穴を塞ぐことを決定しました:

ファイルは次のようなURLを使用して利用できるようになります。

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

このUUIDは、すべてのブラウザーインスタンスに対してランダムに生成され、拡張機能のIDではありません。これにより、Webサイトがユーザーがインストールした拡張機能のフィンガープリントを作成できなくなります。

ただし、拡張機能はruntime.getURL()このアドレスを取得するために使用できますが、Webサイトにハードコードすることはできません。


この答えはstackoverflow.com/a/9216924/1504300から「ジュース」を取得しますが、IMHOは拡張機能でリソースを公開することや、存在を確認するためにajaxリクエストを使用できることなどのかなり重要な情報を追加します(Imageオブジェクトgoo.gl/HBeI1iが間違っていない場合、HTML5でのみ使用できるようです。この回答の情報で問題を解決できたので、「
すぐに使える

@niconicその答え(とにかくリンクのみであるため悪い)は、マニフェストバージョン2が有効になる前の状況を指します。以前は、Webアクセス可能なリソースを宣言する必要はありませんでした。
Xan 2015

19

これに関する私の研究を共有したいと思いました。一部のfile:///リンクが機能するために特定の拡張機能がインストールされているかどうかを検出できるようにする必要がありました。ここでこの記事に遭遇しましたこれ は、拡張機能の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)を使用して、任意の数の拡張機能のインストールを検出できるはずです。


2
Googleがセキュリティを強化したようですが、Ext_Detect()を実行すると、次のエラーが発生します。chrome -extension:// [my_extension_id] /manifest.jsonの負荷を拒否しています。拡張機能の外部のページでリソースをロードするには、リソースをweb_accessible_resourcesマニフェストキーにリストする必要があります。
Lounge9 2014年

2014
2

1
@ Lounge9が言ったように。manifest_version 2(またはそれ以上)を使用するパッケージ内のリソースはデフォルトブロックされ、manifest.json: "web_accessible_resources":["manifest..json"]、
ET-CS

@BJury回答を使用すると、拡張機能からスクリプトにデータを簡単に渡すことができ(拡張機能のバージョンなど)、拡張機能からファイルを公開する必要がありません。
ET-CS

1
私たちの拡張機能は複数のドメインで使用され、新しいドメインが定期的に追加されるため事前定義できないため、これは私にとって最もうまくいきました。manifest.jsonにアクセスする代わりに、新しいファイルversion.jsonを作成し、バージョン番号を中に入れました。これはまったく同じように機能します。
Paul Haggo、2015

7

Webサイトを所有している場合に考えられる別の解決策は、インラインインストールを使用することです

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

私はこれが古い質問であることを知っていますが、この方法はChrome 15で導入されたので、今答えを探している人だけにリストすることにしました。


12
これはChrome アプリでは機能しますが、Chrome拡張機能では機能しません。AFAIK–
Eran Medan

うん、そのウェブサイトは拡張機能をインラインインストールする方法を教えてくれますが、明らかに「拡張機能はコンテンツスクリプトを介して埋め込みページと通信し、既にインストールされていることを知らせることができる」と推奨しています。chrome.app.isInstalledを使用する代わりに。私も混乱しています...
rogerdpack


4

私はcookieメソッドを使用しました:

manifest.jsファイルに、自分のサイトでのみ実行されるコンテンツスクリプトを含めました。

 "content_scripts": [
        {
        "matches": [
            "*://*.mysite.co/*"
            ],
        "js": ["js/mysite.js"],
        "run_at": "document_idle"
        }
    ], 

私のjs / mysite.jsには1行あります:

document.cookie = "extension_downloaded=True";

そして、私のindex.htmlページでそのCookieを探します。

if (document.cookie.indexOf('extension_downloaded') != -1){
    document.getElementById('install-btn').style.display = 'none';
}

私は上記のすべての解決策を試しましたが、うまくいきません、そして私はあなたの答えを見ます、これは私が探しているものです!
John Doe

これにより、今後すべてのHTTPリクエストにオーバーヘッドが追加されます。
mlissner 2018年

3

拡張機能でCookie設定し、そのCookieが存在するかどうかをウェブサイトのJavaScriptでチェックして、それに応じて更新することができます。これはおそらく、ほとんどの他の方法は、ここで言及したが、もちろん、ユーザーによってcirvumventedすることができない限り、あなたがしようとすると、タイムスタンプなどに応じて、カスタムクッキーを拡張機能を作成しており、アプリケーションはそれが本当に持つユーザーであるかどうかを確認するために、それらのサーバー側を分析してい拡張機能または彼のCookieを変更してそれを装う人。


5
唯一の問題は、ユーザーが拡張機能を削除した場合です。クッキーはおそらく設定されたままです。
チェイスロバーツ

3

このGoogleグループの投稿に示されている別の方法があります。つまり、拡張機能アイコンが正常に読み込まれるかどうかを検出してみることができます。これは、チェックしている拡張機能が自分のものでない場合に役立ちます。


1
OK。拡張アイコンが存在するかどうかを確認するにはどうすればよいですか?
マイケルロジャース

3

Webページは、バックグラウンドスクリプトを介して拡張機能と対話します。

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>

externally_connectableがサポートされていないFirefox WebExtensionsでは機能しません。
mlissner 2018年

3

拡張機能がWebサイトと対話し(変数の変更など)、Webサイトがこれを検出する可能性があります。

しかし、これを行うにはもっと良い方法があるはずです。Googleが拡張ギャラリーでそれをどのように行っているのか(すでにインストールされているアプリケーションにマークが付けられています)。

編集:

ギャラリーはchrome.management.get関数を使用します。例:

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

ただし、適切な権限を持つページからのみメソッドにアクセスできます。


1
拡張機能がすべてのタブのすべてのサイトとやり取りする必要があり、実装が遅く/バグが

問題は、Chromeのセキュリティモデルが原因で、他の方向(拡張からページへ)で通信できないことです。「相互作用する」方法を使いたくない場合は、Cookieを使用します。
Fox32、2011年

2
@ Fox32様、chrome.management.get ...様、このエラーを返します:Uncaught TypeError: Cannot read property 'get' of undefined
Hosein Aqajani

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. Webサイトで、そのメッセージを聞きます。

これをあなたのウェブサイトのどこかに追加してください:

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オーバーヘッドが発生したり、ページを操作したりしません。


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

}

少しハッキーな感じがしますが、他のメソッドを機能させることができず、ここでChromeがAPIを変更することを心配しています。この方法がすぐに機能しなくなるのは疑わしい。


上記のように-私はこれをテストしましたが、操作の順序がおかしいようです-どのスクリプトが最初に実行されるかなど。
Brady Moritz

0

また、私が使用したブラウザ間メソッドを使用することもできます。divを追加するという概念を使用します。

コンテンツスクリプト内(スクリプトが読み込まれるたびにこれを実行する必要があります)

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

あなたのウェブサイトであなたは何かを主張します、

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

そして適切なメッセージを投げます。


私はこれをテストしましたが、操作の順序がおかしいようです-どのスクリプトが最初に実行されるかなど。
Brady Moritz

@BradyMoritzは、回答と同じ順序です。最初にクラスを追加してから、アサートします。
Prakash Palnati 2017

コンテンツスクリプトが必ずしもページはめ込みスクリプトの前に実行されているわけではないようですが?
Brady Moritz、2017

それは簡単に修正できると思います。regexを使用して必要なURL /ルートにアクセスした直後にコンテンツスクリプトが実行されることを確認できますか?
Prakash Palnati 2017

0

Webサイトから拡張機能を検出しようとしている場合は、この投稿が役立ちます。 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)
}

0

ここに他の現代的なアプローチがあります:

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')
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.