메뉴 건너뛰기

Hodol's Blog

구글 크롬 브라우저의 확장 프로그램 만들기

목차

간단한 구글 크롬 브라우저의 확장 프로그램을 만들어 보자. 조금만 익히면 인터넷 생활이 편해지고 맛들이다 보면 다른 사람이 만든 확장 프로그램이나 웹페이지를 입맛대로 수정해 쓰는 재미도 있다. 필자는 모 포털사이트 카페의 자료실의 자료를 자동으로 다운받는 확장 프로그램을 만들어서 재미 좀 보았다. 5000개가 넘는 게시물을 일일히 클릭하는 수고를 줄일 수 있었다. 여기서는 간단한 Hello, World! 확장 프로그램을 만들어 보도록 한다. 명예를 위해 한마디 하자면, 다운받은 자료는 강좌 자료 파일이다. 그리고 성교육 강좌 아니다. 아, 쫌!

필수 사항
  • Javascript - 적어도 기초적인 자바스크립트를 사용할 수 있어야 한다. 확장 프로그램은 자바스크립트로 만들어진다.
  • HTML - 간단한 HTML 문서를 작성할 수 있어야 한다. 자바스크립트 프로그램의 실행 결과가 대부분 HTML로 표현되기 때문이다.
  • Chrome Browser - 당연한 이야기이지만 크롬의 확장 프로그램을 만드는 것이니 크롬 브라우저가 필요하다.
  • 구글 확장 프로그램 API 설명서 - 크롬에 내장된 API 함수들을 어떻게 사용하는지를 알아야 한다. 다음 사이트에서 확인할 수 있다.
    https://developer.chrome.com/extensions/api_index
확장 프로그램 제작하기 예제
사실 https://developer.chrome.com/extensions를 방문하면 모든 것을 익힐 수 있다. 그러나 해당 사이트가 영어로 작성되어 있고 원론적인 설명보다는 빠르게 실습을 해보고 싶어하는 급하신 분들도 있으니 보고 따라할 수 있는 예제를 만들어 보기로 한다.
manifest.json 만들기
manifest.json은 확장 프로그램의 정보가 담긴다. 확장 프로그램의 이름, 설명, 어떠한 파일들을 사용하는지, 브라우저의 어떤 퍼미션을 필요로 하는지 등을 기술한다. 다음과 같이 작성하여 manifest.json 파일을 만들자.
{
    "manifest_version": 2,
    
    "name": "Hello_World",
    "description": "Print Hello, World! message",
    "version": "1.0",
    
    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "permissions": [
        "activeTab",
        "<all_urls>"
    ]
}
버튼
브라우저 우측 상단에 우리가 만들 프로그램이 작동시키는 버튼이 될 작은 이미지 파일이 필요하다. 구글에서는 19x19 픽셀 사이즈를 권장한다. 일단 귀찮으니 구글에서 제공하는 이미지를 받아서 쓰도록 하자. 다음을 클릭하면 이미지를 받을 수 있다.

주의해야 할 부분은 파일 이름이 위의 manifest.jsondefault_icon에 명시된 파일 이름과 같아야 한다.
팝업창 만들기
버튼을 클릭하면 뜰 팝업창의 내용이 담긴 파일을 만들도록 하자. 단순 HTML 파일이다. popup.html 파일을 다음과 같이 새로 작성하여 저장하자. 버튼의 경우와 같이, 파일 이름이 manifest.jsondefault_popup에 명시된 파일 이름과 같아야 한다.
<!DOCTYPE html>
<html>
    <head>
        <style>
            BODY {width : 520px; min-height:250px;}
        </style>
        <script src="popup.js"></script>
    </head>
    <body>
    </body>
</html>
프로그램 만들기
이제 실제 작동할 프로그램을 만들어 보도록 하자. popup.js 파일을 다음과 같이 새로 작성하자. 여기서도 파일명은 popup.html<script> 태그에 src 속성에 명시된 파일명과 같아야 한다.
function sayHello(){
    document.body.innerText = "Hello, World!";
}
window.onload = sayHello;
주의할 점은 window.onload = sayHello; 대신에 그냥 sayHello();를 호출하면 페이지가 완전히 로딩되기 전에 함수가 호출되어 함수가 잘못 실행되거나 실행되었더라도 그 결과를 확인할 수 없다. 이는 다른 자바스크립트 프로그래밍에서도 적용되는 이야기이다. 네트워크에 물린 프로그래밍의 특수성이라 하겠다.
크롬에서 테스트하기
이제 프로그램을 크롬에 등록하고 실행하기만 하면 된다. 이번 작업은 확장 프로그램을 배포하기 전에 미리 내 컴퓨터에서만 테스트를 해보는 것이다. 작성한 파일들이 서로 다른 디렉토리에 떨어져 있다면(그럴 일은 없겠지만..) 같은 디렉토리에 존재하도록 복사 또는 이동 후 다음 설명대로 따라해 보자.
  1. 주소줄에 chrome://extensions를 입력하거나 크롬 브라우저의 메뉴 박스를 클릭하여 도구 더보기 > 확장 프로그램을 선택하면 확장 프로그램 관리 페이지를 볼 수 있다.
  2. 페이지 오른쪽 위에 개발자 모드 체크 박스에 체크를 하자.
  3. 개발자 모드 체크 박스에 체크를 하면 압축해제된 확장 프로그램 로드... 라는 버튼이 나타난다. 이를 눌러 뜨는 창에서 우리가 만든 프로그램이 저장된 디렉토리를 찾아서 확인 버튼을 누르자.
  4. 브라우저 오른쪽 상단에 버튼이 새로 나타나는 것을 확인할 수 있다. 혹 없다면 >> 버튼을 클릭해 보자. 숨어 있을 수도 있다. 버튼을 클릭하면 팝업창이 뜨면서 Hello, World!가 출력되는 것을 확인할 수 있다.
동작 설명
확장 프로그램 버튼을 누르면, popup.html이 작은 창에 로딩된다. popup.html이 로딩되면서 <script> 태그에 명시된 popup.js가 로딩되어 실행된다. manifest.json 파일을 만드는 작업이나 아이콘 등록하고 프로그램을 브라우저에 인식시키는 작업을 빼면 웹프로그래밍과 다를게 없다.
스크립트 밀어넣기(Script Injection) 예제
구글 API 페이지를 보면 여러가지 기능들이 확인할 수 있으나, 꼭 강조하고 싶은 API가 있다. 바로 스크립트 밀어넣기(Script Injection)이다. 앞의 예제의 수준으로도 간단한 알람 기능이나 날씨 체크, 메모, RSS리더 등의 확장 프로그램을 제작할 수 있지만 다른 웹페이지들을 수정할 수는 없다. 다른 웹페이지를 수정하기 위해서는 스크립트 밀어넣기 기법을 사용한다. 다른 웹페이지에 내가 만든 스크립트를 강제로 주입하여 실행시키는 것이다. 해킹 기법에도 이런 스크립트 주입 공격( 예: SQL injection )이 있는데, 이와는 달리 합법적인 것이니 걱정하지 말자. 타인이 만들어 놓은 웹페이지를 변조하는 경우, 저작권 문제가 있을 수도 있지만 기능 자체는 쓰라고 만들어 놓은 것이다. 인간 문명의 이기들 중에 양날의 검이 아니었던게 얼마나 되던가? 좋은 기술을 불순한 의도로 사용하지 말자.
이번에는 웹페이지의 텍스트(body.innerText)를 추출하여 팝업창에 출력하는 확장 프로그램을 만들어 보자. 앞서 제작한 확장 프로그램을 수정하여 쓰도록 하겠다.
manifest.json
permission부분이 바뀌었다. 스크립트 주입 기능을 사용하기 위해 꼭 필요한 부분이다.
{
    "manifest_version": 2,
    
    "name": "get_source",
    "description": "print html code.",
    "version": "1.0",
    
    "browser_action": {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "permissions": [
        "tabs",
        "<all_urls>"
    ]
}
popup.html
수정없이 그대로 쓰도록 하자.
popup.js
기존의 Hello, World!를 출력하는 코드를 완전히 삭제하고 앞으로 새로 작성할 스크립트를 밀어넣는 코드를 작성한다. 다음은 popup.js의 내용이다.
chrome.extension.onMessage.addListener(function(request, sender) {
    if (request.action == "getSource") {
        document.body.innerText = request.source;
    }
});

function onWindowLoad() {
    chrome.tabs.executeScript(null, {
        file: "getSource.js"
        }, function() {
            if (chrome.extension.lastError) {
                document.body.innerText = 'There was an error injecting script : \n' + chrome.extension.lastError.message;
            }
        });
}
window.onload = onWindowLoad;
popup.js에서는 getSource.js파일을 현재 탭에 로딩된 웹페이지에 밀어 넣어 마치 원래 getSource.js가 해당 웹페이지에서 포함되었던 것처럼 동작하게끔 한다.
getSource.js
새로 getSource.js파일을 다음과 같이 작성하여 만들자.
function get_source(document_body){
    return document_body.innerText;
}

chrome.extension.sendMessage({
    action: "getSource",
    source: get_source(document.body)
});
실행!
확장 프로그램 관리 페이지에가서 우리가 앞서 만든 확장 프로그램 아래 새로고침(Ctrl+R)을 클릭하거나 Ctrl+R을 눌러서 확장 프로그램을 브라우저에 재인식 시키자. 새로고침을 해주지 않으면 새로 바뀐 manifest.jsonpermission 설정이 적용되지 않아 프로그램이 실행되지 않는다. 재인식을 시켜주었다면, 아무 웹페이지를 방문한 후, 확장 프로그램 버튼을 클릭하여 실행시켜 보자. 현재 창에 보여지는 웹페이지의 내용의 텍스트가 팝업에 출력이 된다면 성공한 것이다. 글쓴이는 위의 소스들을 복붙하여 실행에 성공하였다. 제대로 실행되지 않는다면 버그를 천천히 찾아보도록 하자. 프로그래밍은 코딩반, 디버그반이 아니던가? 특히, manifest.json을 점검해보기를 바란다. 자바스크립트의 에러는 f12키를 눌러서 체크하자. 실수로 무한 루프를 작성하여 실행하였다면 shift + esc를 누르거나 브라우저 메뉴의 도구 더보기에 있는 작업 관리자를 실행하여 프로세스를 종료할 수 있다.
동작 설명
http://www.abc.com/index.htm을 방문한 후, 확장 프로그램을 실행시켰다고 가정하자.
  1. popup.html이 로딩되면서 함께 로딩되는 popup.js가 실행된다.
  2. popup.js 안에 있는 chrome.extension.onMessage.addListener함수가 브라우저 내부의 메세지를 수신하는 리스너를 등록한다.
  3. 다음으로 chrome.tabs.executeScript함수가 작동하여 getSource.js를 현재 탭에 로딩된 웹페이지인 http://www.abc.com/index.htm에 주입한 후 실행시킨다.
  4. getSource.js는 마치 원래부터 http://www.abc.com/index.htm에 포함되었던 것처럼 동작하는데, getSource.js 안에 기술된 get_source함수는 http://www.abc.com/index.htm의 텍스트 내용을 추출한다.
  5. 이 텍스트 내용은 chrome.extension.sendMessage 함수가 받아와서 브라우저 내부 메세지로 송신한다.
  6. popup.js가 로딩될 때 등록된 리스너가 이 메세지를 수신하고 팝업에 수신한 내용을 출력한다.
Extension code, Content scripts, Injected scripts
크롬 확장 프로그램의 자바스크립트 코드는 크게 세 가지 부류로 나뉜다.
  • Extension code는 허용된 모든 chrome.* API에 접근 가능하다. 여기에는 Popup page, Background page, Event page가 포함된다. 이들은 보통 모든 탭에 공통적으로 적용되는 기능이나 브라우저 자체의 기능 등을 구현하는데 쓰인다. 또한 모든 페이지에서 chrome.extension.getBackgroundPage()와 같은 메서드를 호출하여 이 페이지들에 직접 접근이 가능하다.
  • Content scriptschrome API들에 부분적으로 접근 가능하고 객체를 제외하고 페이지의 DOM 객체(frame을 포함한 window 객체 제외)에 완전히 접근 가능하다. Content scripts는 보통 웹페이지를 방문 시 자동으로 페이지를 수정하는 등의 각 탭마다 따로 적용되는 기능들을 구현하는데 쓰인다. Content scripts의 실행 범위는 확장 프로그램과 페이지 사이이다. Content scripts의 전역 window 객체는 웹페이지나 확장프로그램의 전역 namespace와 구분된다.
  • Injected scripts는 보통 Content scripts에 의해 페이지에 주입되는데, 페이지의 모든 속성에 완전히 접근할 수 있고 chrome.* API들에는 접근할 수 없다. Injected scripts는 마치 자신이 페이지에 원래부터 있었던 것처럼 작동한다.