컨텐츠 스크립트를 사용하여 페이지 컨텍스트에 코드 삽입
Chrome 확장 프로그램을 만드는 방법을 배우고 있습니다. 방금 YouTube 이벤트를 잡기 위해 하나를 개발하기 시작했습니다. YouTube 플래시 플레이어와 함께 사용하고 싶습니다 (나중에 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!");
문제는 콘솔이 "시작되었습니다!"라는 메시지를 표시 한다는 것 입니다. 하지만 '상태가 변경되었습니다!' 는 없습니다 . YouTube 동영상을 재생 / 일시 중지 할 때
이 코드를 콘솔에 넣으면 작동했습니다. 내가 도대체 뭘 잘못하고있는 겁니까?
컨텐츠 스크립트는 "격리 된 세계"환경 에서 실행됩니다 . state()
메소드를 페이지 자체 에 주입해야 합니다.
chrome.*
스크립트 에서 API 중 하나를 사용하려면 다음 답변에 설명 된대로 Chrome 확장 프로그램-Gmail의 원본 메시지 검색에 설명 된대로 특수 이벤트 핸들러를 구현해야 합니다 .
그렇지 않으면 chrome.*
API 를 사용할 필요가 없으면 <script>
태그 를 추가하여 페이지에 모든 JS 코드를 삽입하는 것이 좋습니다 .
목차
- 방법 1 : 다른 파일 삽입
- 방법 2 : 임베디드 코드 삽입
- 방법 2b : 함수 사용
- 방법 3 : 인라인 이벤트 사용
- 삽입 된 코드의 동적 값
방법 1 : 다른 파일 삽입
이것은 코드가 많을 때 가장 쉽고 가장 좋은 방법입니다. 확장명 내의 파일에 실제 JS 코드를 포함하십시오 (예 :) script.js
. 그런 다음 콘텐츠 스크립트를 다음과 같이하십시오 ( Google Chome“애플리케이션 바로 가기”사용자 정의 Javascript 여기에 설명 ).
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
참고 :이 방법을 사용하는 경우 주입 된 script.js
파일을 "web_accessible_resources"
섹션에 추가해야합니다 ( 예 ). 그렇지 않으면 Chrome에서 스크립트로드 를 거부 하고 콘솔에 다음 오류가 표시됩니다.
chrome-extension : // [EXTENSIONID] /script.js의로드 거부 확장 프로그램 외부의 페이지에서로드하려면 리소스가 web_accessible_resources 매니페스트 키에 나열되어 있어야합니다.
방법 2 : 임베디드 코드 삽입
이 방법은 작은 코드를 빠르게 실행하려는 경우에 유용합니다. (또한 Chrome 확장 프로그램으로 페이스 북 단축키를 비활성화하는 방법은 무엇입니까? ).
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 : 함수 사용
큰 코드 덩어리의 경우 문자열을 인용하는 것이 가능하지 않습니다. 배열을 사용하는 대신 함수를 사용하고 문자열화할 수 있습니다.
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
. 있는 경우 다른 글로벌 이벤트 중 하나를 선택할 수도 있습니다. 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
다음과 같이 가독성을 높이기 위해 한 번만 사용하는 것이 좋습니다 .
...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]) + ')';
유일한 것 잃어버린 Rob W의 탁월한 답변에 숨겨진 것은 삽입 된 페이지 스크립트와 컨텐츠 스크립트 사이의 통신 방법입니다.
수신 측 (콘텐츠 스크립트 또는 페이지 스크립트)에서 이벤트 리스너를 추가하십시오.
document.addEventListener('yourCustomEvent', function (e) {
var data = e.detail;
console.log('received', data);
});
개시 자 측 (콘텐츠 또는 페이지 스크립트)에서 이벤트를 보내십시오.
var data = {
any: 'JSON-ifiable data',
meaning: 'no DOM elements or classes/functions',
};
document.dispatchEvent(new CustomEvent('yourCustomEvent', { detail: data }));
전송 된 데이터가 JSON으로 식별 가능한지 확인하십시오
명시 적으로 문자열 화 / 구문 분석을 수행하여 전송할 수없는 데이터를 제거 할 수 있습니다. 그렇지 않으면 최신 Chrome 에서만 null
전체로 전송됩니다 ( crbug.com/917703detail
참조) .
리시버:
document.addEventListener('yourCustomEvent', function (e) { var data = JSON.parse(e.detail); console.log('received', data); });
창시자:
document.dispatchEvent(new CustomEvent('yourCustomEvent', { detail: JSON.stringify(data), }));
또한로드 된 스크립트의 순서 문제에 직면했습니다.로드 된 스크립트는 순차적으로로드 된 스크립트를 통해 해결되었습니다. 로딩은 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에 익숙하지 않으므로 더 나은 방법으로 나를 핑 (ping) 할 수 있습니다.
Content script에서는 'onmessage'핸들러를 바인딩하는 헤드에 스크립트 태그를 추가합니다. 부스 콘텐츠 스크립트에서 onmessage 핸들러도 사용하므로 양방향 통신이 가능합니다. 크롬 문서
//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와 Real Dom간에 양방향 통신이 가능합니다. 예를 들어 webscoket 이벤트를 수신해야하거나 메모리 변수 또는 이벤트를 수신해야하는 경우 매우 유용합니다.
텍스트 대신 순수한 기능을 주입하려면 다음 방법을 사용할 수 있습니다.
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/insert-code-into-the-page-context-using-a-content-script
'Programing' 카테고리의 다른 글
포인터 명확성의 배열 / 배열에 대한 C 포인터 (0) | 2020.02.17 |
---|---|
자동 증분 버전 번호를 얻는 방법 (Visual Studio)? (0) | 2020.02.17 |
파이썬 모듈 소스의 위치는 어떻게 찾습니까? (0) | 2020.02.17 |
Enum 값의 속성 얻기 (0) | 2020.02.17 |
PHP + curl, HTTP POST 샘플 코드? (0) | 2020.02.17 |