사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

이번 포스팅에서는 Safari 14 버전부터 사용 가능하게 될 웹 확장(Web Extension)에 대해 알아보고, 샘플 확장 프로그램을 개발해보고자 한다.

기존 사파리(14버전 미만) 브라우저에서도 확장 프로그램을 사용할 수 있었지만, 스위프트로 개발된 네이티브 앱을 별도로 설치하고 활성화하는 방식으로 사용한다는 불편함이 있었다. (접근성도 좋지 않았다)

하지만 곧 업데이트될 사파리 14 버전부터는 구글 크롬 브라우저와 같이 자바스크립트로 웹 확장을 개발할 수 있게 되는데,

웹 개발 모델을 따르고, 웹 확장을 지원하는 다른 브라우저와의 호환성도 유지하기 때문에 사파리 웹 확장을 개발한 후 다른 브라우저에서도 동일한 확장 기능을 사용할 수 있을 것으로 보인다.

본 포스팅을 본격적으로 시작하기에 앞서 함께 실습을 진행하려면 아래와 같은 환경이 준비되어있어야 하니 확인해보도록 하자.

👉 준비 사항

- macOS 11(Big Sur)이상의 기기 (Beta 버전 포함)

- Xcode 12 (Beta 버전 포함)

사파리 14버전을 사용하기 위해 macOS 11 버전이 필요하다.

기본적인 사항이 모두 준비되었다면, 이제 사파리 웹 확장에 대해 간단히 살펴보도록 하자.

[ 목차 ]

1. 새롭게 추가되는 사파리 웹 확장의 주요 특징

2. 사파리 웹 확장의 주요 구성요소

3. 샘플 확장 프로그램 개발하기

✨ 새롭게 추가되는 사파리 웹 확장의 주요 특징

 WWDC20의 "Meet Safari Web Extensions" 영상을 통해 웹 확장에 대한 전반적인 내용을 확인할 수 있다.

https://developer.apple.com/wwdc20/10665

Meet Safari Web Extensions - WWDC 2020 - Videos - Apple Developer

When you create a Safari Web Extension, you can help people get common online tasks done more quickly and efficiently. We'll show you how...

developer.apple.com

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

간단히 요약해보면, 아래 내용으로 요약이 가능하다.

- User Agent 확인 가능

- 확장 프로그램이 활성화될 도메인(URL)은 하드 코딩됨 - 빌드 후 수정 불가

- 웹 페이지가 로드될 때 확장 프로그램의 스크립트가 주입됨

- 다른 맥 애플리케이션과 메시지를 통해 커뮤니케이션 가능

- 개인정보와 권한을 보호하여 동작

기본적으론 기존의 크롬 웹 확장과 크게 다르지 않지만, 맥에서 동작하는 사파리 브라우저인 만큼 다른 맥 애플리케이션과 상호작용할 수 있다는 부분이 특징이다.

확장 프로그램을 개발하기에 앞서, 확장 프로그램의 주요 구성 요소에 대해 살펴보도록 하겠다.

⚙️ 사파리 웹 확장의 주요 구성요소

사파리 14 버전에서 개발할 수 있는 웹 확장 뿐만 아니라 기존 크롬의 웹 확장도 동일하다.

대표적으로 아래와 같은 구성요소들을 통해 웹 확장 프로그램을 구현하게 된다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

- 매니페스트

- 백그라운드 스크립트

- 컨텐츠 스크립트

- 팝 오버

매니페스트는 웹 확장에 대한 전반적인 내용을 포함하고 있는 파일이라고 볼 수 있다.

웹 확장의 이름뿐만 아니라 확장을 사용하기 위해 요구해야 하는 권한 정보,

어떠한 도메인 URL에서 동작할지에 대한 정보 등 웹 확장이 동작하기 위한 구성 정보가 정의된다.

백그라운드 스크립트는 웹 확장이 설치되는 즉시 실행되며, 사용자가 웹 확장을 제거하기 전까지 동작하게 된다.

특정 이벤트가 발생하거나 메시지를 수신했을 때 동작하고, 유휴 상태에 진입하면(동작이 불필요하면) 알아서 종료된다.

또한, 웹 브라우저 저장소에 데이터를 저장한다거나 웹 페이지나 확장이 닫히더라도 별도로 작업을 더 수행할 수 있다.

컨텐츠 스크립트는 웹 페이지가 로드될 때 함께 주입(Inject)되며, 이를 통해 웹 페이지의 내용이나 기능을 수정하고 제어할 수 있다.

컨텐츠 스크립트는 웹 페이지의 스크립트가 실행되는 컨텍스트와 서로 다른 곳에 로드되기 때문에 충돌하지 않는다.

(충돌하지 않는다는 것은, 서로의 스크립트 컨텍스트에 접근할 수 없다는 의미이다.)

마지막 구성 요소는 팝 오버입니다. 팝 오버는 사용자에게 보여지는 웹 확장의 모습(UI)이며 HTML, CSS, JS와 같이 일반적인 웹 페이지를 구성하는 요소들로 구현하게 된다.

웹 확장의 구성요소들을 간략히 알아보았으니 간단한 사파리 웹 확장을 만들어보도록 하자.

🔥 샘플 확장 프로그램 개발하기

애플 개발자 페이지(developer.apple.com)의 Apple이라는 단어를 특수 문자 아이콘인 🍎로 변경하는 기능을 수행하는 샘플 확장 프로그램을 개발해보고자 한다.

먼저 Xcode를 실행하고 개발을 위한 macOS 앱 프로젝트를 새로 생성한다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi
사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

프로젝트의 이름은 apple-symbol로 정했으며, 원하는 이름이 있다면 바꾸어도 좋다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

프로젝트가 생성되었다면, Xcode 메뉴의 File > New > Target 메뉴를 선택한다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

해당 메뉴에서 사파리 웹 확장을 개발하기 위한 템플릿을 추가할 수 있는데, macOS 탭에서 safari를 검색하여 Safari Extension을 선택하자.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

확장 이름은 apple-symbol-extension으로 지정하여 개발해보도록 하겠다. (프로젝트 이름과 동일하게 바꾸고 싶으면 변경해도 좋다)

마지막으로 마무리 버튼을 누르면 아래와 같이 새로운 구성 요소들이 프로젝트에 추가된 모습을 볼 수 있다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

사파리 웹 확장을 개발하기 위한 전체 구성요소들을 확인할 수 있고, 매니페스트와 백그라운드/컨텐츠 스크립트, 그리고 팝오버 관련 소스코드가 추가된 것을 확인할 수 있습니다.

먼저, 매니페스트 코드를 아래와 같이 수정한 후 함께 살펴보도록 하겠습니다.

{
    "manifest_version": 2,
    "default_locale": "en",

    "name": "__MSG_extension_name__",
    "description": "__MSG_extension_description__",
    "version": "1.0",

    "icons": {
        "48": "images/icon-48.png",
        "96": "images/icon-96.png",
        "128": "images/icon-128.png",
        "256": "images/icon-256.png",
        "512": "images/icon-512.png"
    },

    "background": {
        "scripts": [ "background.js" ]
    },

    "content_scripts": [{
        "js": [ "content.js" ],
        "matches": [ "*://developer.apple.com/*" ]
    }],

    "browser_action": {
        "default_popup": "popup.html",
        "default_icon": {
            "16": "images/toolbar-icon-16.png",
            "32": "images/toolbar-icon-32.png"
        }
    },

    "permissions": [ "activeTab" ]
}

로케일(언어) 관련 설정과 웹 확장의 이름 및 설명 그리고, 아이콘 이미지 정보가 포함되어 있다.

Xcode를 통해 받아온 템플릿에는 아래와 같은 기본 아이콘 이미지들이 준비되어있으며, 추후 원하는 이미지로 변경하여 빌드할 수 있다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi
웹 확장 아이콘
사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi
상단 툴바에 표시될 아이콘

이외에 수정된 코드는 content_scripts의 matches 부분과, 가장 아래에 위치한 권한 부분이다.

컨텐츠 스크립트의 matches에 컨텐츠 스크립트가 주입될 도메인 패턴을 정의해야 한다.

지정한 도메인에 접근했을 때에만 컨텐츠 스크립트가 주입되어 동작하게 될 것이며, 도메인 패턴 대신 <all_url>을 추가하여 모든 도메인에서 동작하도록 할 수도 있다.

두 번째로 변경된 부분인 권한(permissions)을 살펴보자.

확장 프로그램을 통해 특정 기능을 사용하기 위해선 권한이 요구되는데, 대표적으로 위와 같이 활성화된 탭에서만 동작하도록 하거나, 저장소에 접근하여 데이터를 관리하는 등의 권한을 부여받아 관련 기능을 사용할 수 있다.

이 외에도 optional_permissions와 같이 확장 프로그램에 필수로 요구되진 않지만, 사용자가 선택적으로 권한을 부여할 수 있는 옵션도 존재한다.

다음으로 백그라운드 스크립트와 컨텐츠 스크립트를 살펴보자.

이번 예제에서는 백그라운드 스크립트를 사용하지 않을 것이기 때문에 백그라운드 스크립트의 내용을 모두 지워준다.

(또는 매니페스트의 background 부분을 제거해도 됨)

컨텐츠 스크립트는 아래와 같이 수정한다.

(() => {
    function getText (node) {
        if (node.hasChildNodes()) {
            node.childNodes.forEach(getText);
        } else if (node.nodeType === Node.TEXT_NODE) {
            if (node.textContent.includes("Apple")) {
                node.textContent = node.textContent.replaceAll("Apple", "🍎");
            }
        }
    }

    getText(document.body);
})();

평범한 자바스크립트 파일이며, 웹 페이지가 로드된 후 위의 컨텐츠 스크립트가 웹 페이지에 주입되어 동작하게 된다.

코드를 살펴보면, 웹 페이지의 body 내에 있는 모든 텍스트 요소를 가져온 후, Apple이라는 단어를 모두 🍎 아이콘으로 변경하도록 구현한 모습을 볼 수 있다.

마지막으론, 팝 오버 코드(HTML, CSS)를 아래와 같이 수정하자.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="popup.css">
    <script type="module" src="popup.js"></script>
</head>
<body>
    <strong>Apple Symbol</strong>
    <span></span>
</body>
</html>
:root {
    color-scheme: light dark;
}

body {
    width: 100px;
    padding: 10px;
    font-family: system-ui;
    text-align: center;
}

span {
    display: block;
    margin: auto;
    margin-top: 5px;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background-color: #fff;
    box-shadow: 0, 0, 8px rgba(0, 0, 0, .5);
}

span::before {
    content: "🍎";
    line-height: 30px;
}

@media (prefers-color-scheme: dark) {
    span {
        background-color: #000;
    }
}

팝 오버는 앞에서 이야기했던 것과 같이 눈에 보이게 되는 웹 확장의 UI를 담당하는 부분이다.

웹 페이지와 동일하게 HTML, CSS, JS로 UI 을 구성하고 간단한 이벤트 처리를 수행할 수 있다.

한 번 지금까지 만들어본 샘플 웹 확장을 빌드하고 잘 동작하는지 확인해보도록 하자.

Xcode 메뉴의 Product > Build 메뉴 혹은, 커맨드 + B를 눌러 빌드할 수 있고, 빌드가 성공적으로 완료되었으면 사파리를 실행하자.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

사파리 환경 설정의 Advanced 메뉴로 이동한 후 가장 아래에 있는 Show Develop menu in menu bar를 활성화하여 상단에 개발자 메뉴가 표시되도록 한다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

상단에 추가된 개발자(Develop)메뉴의 Allow Unsigned Extensions를 체그하여 서명되지 않은 웹 확장을 사용할 수 있도록 해주자.

지금까지 개발한 샘플 웹 확장은 배포를 위한 서명을 진행하지 않았기 때문에 위와 같이 설정해야 방금 구현한 웹 확장을 사용할 수 있.

서명되지 않은 확장을 사용하도록 했다면, 사파리 설정의 Extensions 메뉴로 이동한다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

조금전에 빌드했던 웹 확장이 목록에 추가되어있는 모습을 확인할 수 있으며, 체크박스를 활성화하여 확장을 사용할 수 있다.

컨텐츠 스크립트가 주입될 도메인 범위(*://developer.apple.com/*)에 해당하는 developer.apple.com/wwdc20 페이지로 이동해보도록 하겠다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

사파리 상단 메뉴에 확장 아이콘(번개모양)이 표시되었지만, 경고 아이콘이 노출되어있고 동작하지 않고 있다.

이는 웹 확장 프로그램에게 권한을 부여하지 않았기 때문에 표시되는 것이며, 아래와 같이 확장 아이콘을 눌러 권한을 부여할 수 있다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

하루만 권한을 부여하거나, 해당 사이트에서 항상 권한을 부여하거나, 모든 웹 사이트에서 권한을 부여하는 등 사용자의 선택에 따라 웹 확장의 권한을 제어할 수 있다.

적절히 권한을 부여한다면 아래와 같이 완벽하게 동작하는 모습을 볼 수 있을 것이다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

메뉴바에 있는 확장 아이콘을 누르면 간단히 구현했던 팝 오버가 잘 표시되는 모습을 확인할 수 있고, 웹 페이지의 모든 Apple글자가 아래와 같이 사과 아이콘으로 변경된 모습도 확인할 수 있다.

사파리 확장프로그램 만들기 - sapali hwagjangpeulogeulaem mandeulgi

이와 같이 사파리 14 버전부터는 기존의 다른 브라우저와 동일하게 웹 확장 프로그램을 개발할 수 있으며, 이들간의 호환성을 유지하기 때문에 다양한 웹 브라우저의 확장 프로그램을 통합으로 개발할 수 있게 되었다.

지금까지 간단한 웹 확장 프로그램을 개발해보았는데, 웹 확장의 기본적인 구성과 개발 방법에 대해 알아볼 수 있었을 것이라고 생각한다.

궁금한 사항은 댓글 남겨주기 바라며, 이후 더 다양한 내용의 포스트로 찾아뵙도록 하겠다.

(포스트에 포함된 모든 이미지 자료의 저작권은 저에게 있습니다. 사용하게 될 시 출처를 밝혀주세요)