根本的な原因:
コンテンツスクリプトは「孤立した世界」の環境で実行されます。
解決策::ページコンテキスト(「メインワールド」)の関数/変数
にアクセスするには、DOMを使用してページ自体にコードを挿入する必要があります。関数/変数をページコンテキストに公開したい場合も同じです(あなたの場合はstate()
メソッドです)。
安全上の警告:
ページが組み込みのプロトタイプを再定義または拡張/フックする可能性があるため、ページが互換性のない方法で実行した場合、公開されたコードが失敗する可能性があります。公開されたコードが安全な環境で実行されることを確認したい場合は、a)「run_at」:「document_start」でコンテンツスクリプトを宣言し、 1ではなくメソッド2〜3を使用するか、b)元のネイティブビルドを抽出する必要があります。空のiframeを介したins、例。DOMを待機するために、公開されたコード内でイベントdocument_start
を使用する必要がある場合があることに注意してください。DOMContentLoaded
目次
- 方法1:別のファイルを挿入する-ManifestV3と互換性がある
- 方法2:埋め込みコードを挿入する
- 方法2b:関数を使用する
- 方法3:インラインイベントを使用する
- 挿入されたコードの動的な値
方法1:別のファイルを挿入する
現時点で唯一のManifestV3互換メソッド。コードがたくさんある場合は特に便利です。拡張子内のファイルにコードを入れます。たとえば、script.js
。次に、次のようにコンテンツスクリプトにロードします。
var s = document.createElement('script');
s.src = chrome.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
jsファイルは次の場所に公開する必要がありますweb_accessible_resources
:
ManifestV2のmanifest.jsonの例
"web_accessible_resources": ["script.js"],
ManifestV3のmanifest.jsonの例
"web_accessible_resources": [{
"resources": ["script.js"],
"matches": ["<all_urls>"]
}]
そうでない場合、次のエラーがコンソールに表示されます。
chrome-extension://[EXTENSIONID]/script.jsの読み込みを拒否します。拡張機能の外部のページでリソースをロードするには、リソースをweb_accessible_resourcesマニフェストキーにリストする必要があります。
方法2:埋め込みコードを挿入する
このメソッドは、小さなコードをすばやく実行する場合に役立ちます。(「 Chrome拡張機能でFacebookホットキーを無効にする方法」も参照してください)。
var actualCode = `// Code here.
// If you want to use a variable, use $ and curly braces.
// For example, to use a fixed random number:
var someFixedRandomValue = ${ Math.random() };
// NOTE: Do not insert unsafe variables in this way, see below
// at "Dynamic values in the injected code"
`;
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
注:テンプレートリテラルはChrome41以降でのみサポートされています。拡張機能をChrome40-で機能させる場合は、次を使用します。
var actualCode = ['/* Code here. Example: */' + 'alert(0);',
'// Beware! This array have to be joined',
'// using a newline. Otherwise, missing semicolons',
'// or single-line comments (//) will mess up your',
'// code ----->'].join('\n');
方法2b:関数を使用する
コードの大きなチャンクの場合、文字列を引用することはできません。配列を使用する代わりに、関数を使用して文字列化することができます。
var actualCode = '(' + function() {
// All code is executed in a local scope.
// For example, the following does NOT overwrite the global `alert` method
var alert = null;
// To overwrite a global variable, prefix `window`:
window.alert = null;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
+
文字列と関数の演算子がすべてのオブジェクトを文字列に変換するため、このメソッドは機能します。コードを複数回使用する場合は、コードの繰り返しを避けるために関数を作成することをお勧めします。実装は次のようになります。
function injectScript(func) {
var actualCode = '(' + func + ')();'
...
}
injectScript(function() {
alert("Injected script");
});
注:関数はシリアル化されているため、元のスコープとすべてのバインドされたプロパティが失われます。
var scriptToInject = function() {
console.log(typeof scriptToInject);
};
injectScript(scriptToInject);
// Console output: "undefined"
方法3:インラインイベントを使用する
<head>
要素が作成される前にコードを実行するなど、コードをすぐに実行したい場合があります。<script>
これは、でタグを挿入することで実行できますtextContent
(方法2 / 2bを参照)。
別の方法ですが、推奨されませんが、インラインイベントを使用することです。ページがインラインスクリプトを禁止するコンテンツセキュリティポリシーを定義している場合、インラインイベントリスナーがブロックされるため、お勧めしません。一方、拡張機能によって挿入されたインラインスクリプトは引き続き実行されます。それでもインラインイベントを使用する場合は、次のようにします。
var actualCode = '// Some code example \n' +
'console.log(document.documentElement.outerHTML);';
document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');
注:このメソッドは、イベントを処理する他のグローバルイベントリスナーがないことを前提としていreset
ます。ある場合は、他のグローバルイベントの1つを選択することもできます。JavaScriptコンソール(F12)を開き、document.documentElement.on
と入力して、使用可能なイベントを選択するだけです。
挿入されたコードの動的な値
場合によっては、注入された関数に任意の変数を渡す必要があります。例えば:
var GREETING = "Hi, I'm ";
var NAME = "Rob";
var scriptToInject = function() {
alert(GREETING + NAME);
};
このコードを挿入するには、変数を無名関数に引数として渡す必要があります。正しく実装してください!以下は機能しません。
var scriptToInject = function (GREETING, NAME) { ... };
var actualCode = '(' + scriptToInject + ')(' + GREETING + ',' + NAME + ')';
// The previous will work for numbers and booleans, but not strings.
// To see why, have a look at the resulting string:
var actualCode = "(function(GREETING, NAME) {...})(Hi, I'm ,Rob)";
// ^^^^^^^^ ^^^ No string literals!
JSON.stringify
解決策は、引数を渡す前に使用することです。例:
var actualCode = '(' + function(greeting, name) { ...
} + ')(' + JSON.stringify(GREETING) + ',' + JSON.stringify(NAME) + ')';
変数が多い場合はJSON.stringify
、次のように、読みやすさを向上させるために1回使用する価値があります。
...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]) + ')';