컨텐츠 스크립트를 사용하여 페이지 컨텍스트 변수 및 함수에 액세스합니다.
Chrome 확장기능을 만드는 방법을 배우고 있습니다.나는 유튜브 이벤트를 잡기 위해 막 하나를 개발하기 시작했다.YouTube flash Player에서 사용하고 싶습니다(나중에 HTML5에 대응하도록 하겠습니다).
manifest.json:
{
"name": "MyExtension",
"version": "1.0",
"description": "Gotta catch Youtube events!",
"permissions": ["tabs", "http://*/*"],
"content_scripts" : [{
"matches" : [ "www.youtube.com/*"],
"js" : ["myScript.js"]
}]
}
myScript.js:
function state() { console.log("State Changed!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Started!");
문제는 콘솔에 "Started!"라는 메시지가 뜨는데 유튜브 동영상을 재생/일시 정지할 때 "State Changed!"라는 메시지가 표시되지 않는다는 것입니다.
이 코드를 콘솔에 넣었을 때 동작했습니다.내가 뭘 잘못하고 있지?
본본: :
콘텐츠 스크립트는 "독립된 세계" 환경에서 실행됩니다.
★★★★★★★★★★★★★★★★★★:
DOM을 사용하여 코드를 페이지에 주입합니다. 이 코드는 페이지 컨텍스트("메인 월드")의 함수/변수에 액세스하거나 페이지 컨텍스트에 함수/변수를 노출할 수 있습니다(이 경우는state()
★★★★★★★★★★★★★★★★★★」
페이지 스크립트와 통신할 필요가 있는 경우는, 다음의 점에 주의해 주세요.
DOM DOM 을 합니다.CustomEvent
핸들러예: 1개, 2개,chrome
API를 사용하다
★★chrome.*
API를 사용하다 내용 스크립트에서 API를 사용하고 결과를 DOM 메시징을 통해 페이지 스크립트로 전송해야 합니다(위 참고 참조).
안전 경고:
페이지가 내장 프로토타입을 재정의하거나 증강/훅할 수 있으므로 페이지가 호환되지 않는 방식으로 작성된 경우 노출된 코드가 실패할 수 있습니다.노출된 코드가 안전한 환경에서 실행되도록 하려면 a) 컨텐츠 스크립트를 "run_at"로 선언하고 "document_start"를 사용하여 메서드 2-3을 사용하거나 b) 빈 iframe을 통해 원래 기본 빌트인을 추출해야 합니다.주의:document_start
하면 '어울리지 않다'를 써야 할 도 있어요.DOMContentLoaded
DOM을 대기하기 위해 노출된 코드 내에서 이벤트를 발생시킵니다.
목차.
- 방법 1: 다른 파일 삽입 - Manifest V3 호환
- 방법 2: 삽입 코드 삽입 - MV2
- 방법 2b: 기능 사용 - MV2
- 방법 3: 인라인 이벤트 사용 - ManifestV3 호환
- 방법 4: executeScript의 월드 사용 - ManifestV3만
- 삽입된 코드의 동적 값
방법 1: 다른 파일 삽입(ManifestV3/MV2)
을 사용하다안에 합니다. 를 들어, 코드를 입력해 주세요.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 파일은 에서 공개해야 합니다.
Manifest.json의 ManifestV2의 예
"web_accessible_resources": ["script.js"],
Manifest.json의 ManifestV3의 예
"web_accessible_resources": [{ "resources": ["script.js"], "matches": ["<all_urls>"] }]
그렇지 않으면 콘솔에 다음 오류가 나타납니다.
chrome-extension://[EXTENSIONID]/script.js 로드를 거부하고 있습니다.확장자 이외의 페이지에서 로드하려면 리소스가 web_accessible_resources 매니페스트 키에 나열되어야 합니다.
방법 2: 삽입 코드(MV2) 삽입
이 방법은 작은 코드를 빠르게 실행할 때 유용합니다.(「」도 참조해 주세요.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();
참고: 템플릿 리터럴은 Chrome 41 이상에서만 지원됩니다.Chrome 40-에서 확장 기능을 사용하려면 다음을 사용하십시오.
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: 기능 사용(MV2)
큰 코드 청크의 경우 문자열을 따옴표로 묶을 수 없습니다.배열을 사용하는 대신 함수를 사용하여 문자열을 지정할 수 있습니다.
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: 인라인 이벤트 사용(ManifestV3/MV2)
를 들어, 코드를 바로 를 들어 를 실행하면 코드 앞에 됩니다. 「 」, 「 」<head>
요소가 생성됩니다. , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 를 할 수 .<script>
를 달다textContent
('2/2b')
다른 방법으로는 인라인이벤트를 사용하는 것을 권장하지 않습니다.페이지에서 인라인스크립트를 금지하는 Content Security 정책이 정의되어 있는 경우 인라인이벤트 리스너는 차단되기 때문에 권장되지 않습니다.반면 확장에 의해 삽입된 인라인스크립트는 계속 실행됩니다.인라인 이벤트를 계속 사용할 경우 다음과 같이 하십시오.
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
이벤트가 있다면 다른 글로벌 이벤트 중 하나를 선택할 수도 있습니다. 콘솔 JavaScript 를 입력합니다.document.documentElement.on
및 사용 가능한 이벤트를 선택합니다.
4: chrome API © 4 : chrome.scripting API 사용 »world
(매니페스트 V3만 해당)
- 크롬 95 이상,
chrome.scripting.executeScript
와 함께world: 'MAIN'
- 크롬 102 이상,
chrome.scripting.registerContentScripts
world: 'MAIN'
「」도 사용할 수 있습니다.runAt: 'document_start'
페이지 스크립트의 조기 실행을 보증합니다.
다른 방법과는 달리 이 방법은 백그라운드스크립트 또는 팝업스크립트용이지콘텐츠스크립트용이 아닙니다.메뉴얼과 예를 참조해 주세요.
삽입된 코드(MV2)의 동적 값
주입된 함수에 임의 변수를 전달해야 하는 경우가 있습니다.예를 들어 다음과 같습니다.
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!
해결책은 인수를 통과하기 전에 사용하는 것입니다.예:
var actualCode = '(' + function(greeting, name) { ...
} + ')(' + JSON.stringify(GREETING) + ',' + JSON.stringify(NAME) + ')';
변수가 많으면 사용할 가치가 있습니다.JSON.stringify
하다
...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]).slice(1, -1) + ')';
삽입된 코드의 동적 값(ManifestV3)
메서드 1은 콘텐츠스크립트에 스크립트 요소의 URL을 설정할 수 있습니다.
s.src = chrome.runtime.getURL('script.js?') + new URLSearchParams({foo: 1});
그런 다음 script.js에서 읽을 수 있습니다.
const params = new URLSearchParams(document.currentScript.src.split('?')[1]); console.log(params.get('foo'));
4 에는 '4 executeScript'가 .
args
콘텐츠 스크립트를 등록하다
Rob W의 뛰어난 답변에 숨겨진 유일한 것은 삽입된 페이지 스크립트와 콘텐츠 스크립트 간의 통신 방법입니다.
수신측(콘텐츠스크립트 또는 삽입된 페이지스크립트 중 하나)에서 이벤트청취자를 추가합니다.
document.addEventListener('yourCustomEvent', function (e) {
var data = e.detail;
console.log('received', data);
});
이니시에이터 측(콘텐츠 스크립트 또는 주입된 페이지 스크립트)에서 이벤트를 보냅니다.
var data = {
allowedTypes: 'those supported by structured cloning, see the list below',
inShort: 'no DOM elements or classes/functions',
};
document.dispatchEvent(new CustomEvent('yourCustomEvent', { detail: data }));
주의:
- DOM 메시징은 구조화 클로닝알고리즘을 사용합니다.구조화 클로닝알고리즘은 원시값 외에 일부 유형의 데이터만 전송할 수 있습니다.클래스 인스턴스, 함수 또는 DOM 요소를 전송할 수 없습니다.
초기값이 를하려면 , 「」( 「」, 「」)를 사용해 할 .
cloneInto
(내장 기능), 그렇지 않으면 보안 위반 오류로 인해 실패합니다.document.dispatchEvent(new CustomEvent('yourCustomEvent', { detail: cloneInto(data, document.defaultView), }));
또한 로드된 스크립트의 순서를 정하는 문제도 있었습니다.이 문제는 스크립트의 순차적인 로딩으로 해결되었습니다.로딩은 Rob W의 답변을 기반으로 합니다.
function scriptFromFile(file) {
var script = document.createElement("script");
script.src = chrome.extension.getURL(file);
return script;
}
function scriptFromSource(source) {
var script = document.createElement("script");
script.textContent = source;
return script;
}
function inject(scripts) {
if (scripts.length === 0)
return;
var otherScripts = scripts.slice(1);
var script = scripts[0];
var onload = function() {
script.parentNode.removeChild(script);
inject(otherScripts);
};
if (script.src != "") {
script.onload = onload;
document.head.appendChild(script);
} else {
document.head.appendChild(script);
onload();
}
}
사용 예는 다음과 같습니다.
var formulaImageUrl = chrome.extension.getURL("formula.png");
var codeImageUrl = chrome.extension.getURL("code.png");
inject([
scriptFromSource("var formulaImageUrl = '" + formulaImageUrl + "';"),
scriptFromSource("var codeImageUrl = '" + codeImageUrl + "';"),
scriptFromFile("EqEditor/eq_editor-lite-17.js"),
scriptFromFile("EqEditor/eq_config.js"),
scriptFromFile("highlight/highlight.pack.js"),
scriptFromFile("injected.js")
]);
사실, 난 JS에 처음이니까, 더 나은 방법을 가르쳐 줘.
콘텐츠 스크립트에서 스크립트태그를 선두에 추가하여 'onmessage' 핸들러를 바인드합니다.핸들러 내에서는 코드를 실행하기 위해 eval을 사용합니다.부스 콘텐츠 스크립트에서도 온메시지 핸들러를 사용하고 있기 때문에 쌍방향 커뮤니케이션을 할 수 있습니다.크롬 문서
//Content Script
var pmsgUrl = chrome.extension.getURL('pmListener.js');
$("head").first().append("<script src='"+pmsgUrl+"' type='text/javascript'></script>");
//Listening to messages from DOM
window.addEventListener("message", function(event) {
console.log('CS :: message in from DOM', event);
if(event.data.hasOwnProperty('cmdClient')) {
var obj = JSON.parse(event.data.cmdClient);
DoSomthingInContentScript(obj);
}
});
pmListener.js는 포스트 메시지 URL 리스너입니다.
//pmListener.js
//Listen to messages from Content Script and Execute Them
window.addEventListener("message", function (msg) {
console.log("im in REAL DOM");
if (msg.data.cmnd) {
eval(msg.data.cmnd);
}
});
console.log("injected To Real Dom");
이렇게 하면 CS에서 리얼돔으로 양방향 통신을 할 수 있습니다.예를 들어 webscoket 이벤트 또는 메모리 변수 또는 이벤트 중 하나를 수신해야 하는 경우 매우 유용합니다.
페이지 컨텍스트에서 코드를 실행하여 반환된 값을 되돌리기 위해 제가 만든 유틸리티 함수를 사용할 수 있습니다.
이것은 함수를 문자열에 직렬화하여 웹 페이지에 삽입함으로써 수행됩니다.
이 유틸리티는 여기 GitHub에서 사용할 수 있습니다.
사용 예 -
// Some code that exists only in the page context -
window.someProperty = 'property';
function someFunction(name = 'test') {
return new Promise(res => setTimeout(()=>res('resolved ' + name), 1200));
}
/////////////////
// Content script examples -
await runInPageContext(() => someProperty); // returns 'property'
await runInPageContext(() => someFunction()); // returns 'resolved test'
await runInPageContext(async (name) => someFunction(name), 'with name' ); // 'resolved with name'
await runInPageContext(async (...args) => someFunction(...args), 'with spread operator and rest parameters' ); // returns 'resolved with spread operator and rest parameters'
await runInPageContext({
func: (name) => someFunction(name),
args: ['with params object'],
doc: document,
timeout: 10000
} ); // returns 'resolved with params object'
텍스트 대신 순수 함수를 삽입하려면 다음 방법을 사용할 수 있습니다.
function inject(){
document.body.style.backgroundColor = 'blue';
}
// this includes the function as text and the barentheses make it run itself.
var actualCode = "("+inject+")()";
document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');
또한 매개변수를 함수에 전달할 수 있습니다(안타깝게도 개체와 배열은 문자열화할 수 없습니다).다음과 같이 베어시스에 추가합니다.
function inject(color){
document.body.style.backgroundColor = color;
}
// this includes the function as text and the barentheses make it run itself.
var color = 'yellow';
var actualCode = "("+inject+")("+color+")";
언급URL : https://stackoverflow.com/questions/9515704/use-a-content-script-to-access-the-page-context-variables-and-functions
'programing' 카테고리의 다른 글
JavaScript로 쿠키 설정 및 쿠키 가져오기 (0) | 2022.10.15 |
---|---|
파일 출력이 있는 디렉토리 자동 생성 (0) | 2022.10.14 |
JSF backing bean 메서드에서 JSF 컴포넌트를 갱신할 수 있습니까? (0) | 2022.10.14 |
$_REQUEST, $_GET, $_POST 중 어느 것이 가장 빠릅니까? (0) | 2022.10.14 |
object==module 또는 null==object? (0) | 2022.10.14 |