Chrome 확장 프로그램에서 위치정보를 가져오려면 웹사이트에서 일반적으로 사용하는 것과 동일한 navigator.geolocation
웹 플랫폼 API를 사용하세요. 이 도움말은 Chrome 확장 프로그램이 민감한 정보에 대한 액세스 권한을 웹사이트와 다른 방식으로 처리하기 때문에 표시되었습니다. 위치정보는 매우 민감한 정보이므로 브라우저를 통해 사용자는 정확한 위치가 공유되는 시기와 장소를 완전히 파악하고 제어할 수 있습니다.
MV3 확장 프로그램에서 위치정보 사용
웹에서 브라우저는 사용자가 특정 출처의 위치 정보 액세스 권한을 부여해 달라는 프롬프트가 표시되어 위치정보 데이터를 활용할 수 있습니다. 동일한 권한 모델이 항상 확장 프로그램에 적합한 것은 아닙니다.
<ph type="x-smartling-placeholder">권한만이 다른 것은 아닙니다. 위에서 언급했듯이 navigator.geolocation
는 DOM API로, 웹사이트를 구성하는 API의 일부입니다. 따라서 매니페스트 v3 확장 프로그램의 백본인 확장 프로그램 서비스 워커와 같은 작업자 컨텍스트 내에서 액세스할 수 없습니다. 하지만 geolocation
는 계속 사용할 수 있습니다. 사용하는 방법과 위치에 따라 미묘한 차이가 있을 뿐입니다.
서비스 워커에서 위치정보 사용
서비스 워커 내부에는 navigator
객체가 없습니다. 페이지의 document
객체에 액세스할 수 있는 컨텍스트 내에서만 사용할 수 있습니다. 서비스 워커 내에서 액세스 권한을 얻으려면 확장 프로그램과 번들로 묶을 수 있는 HTML 파일에 대한 액세스 권한을 제공하는 Offscreen Document
를 사용합니다.
먼저 매니페스트의 "permissions"
섹션에 "offscreen"
를 추가합니다.
manifest.json:
{
"name": "My extension",
...
"permissions": [
...
"offscreen"
],
...
}
"offscreen"
권한을 추가한 후 오프스크린 문서가 포함된 HTML 파일을 확장 프로그램에 추가합니다. 이 사례는 페이지의 콘텐츠를 사용하지 않으므로 거의 빈 파일일 수 있습니다. 스크립트에서 로드되는 작은 HTML 파일만 하면 됩니다.
offscreen.html:
<!doctype html>
<title>offscreenDocument</title>
<script src="offscreen.js"></script>
이 파일을 프로젝트의 루트에 offscreen.html
로 저장합니다.
앞서 언급했듯이 offscreen.js
라는 스크립트가 필요합니다. 또한 이를 확장 프로그램과 번들로 묶어야 합니다. 서비스 워커의 위치정보 정보 소스가 됩니다. 애플리케이션과 서비스 워커 간에 메시지를 전달할 수 있습니다.
offscreen.js:
chrome.runtime.onMessage.addListener(handleMessages);
function handleMessages(message, sender, sendResponse) {
// Return early if this message isn't meant for the offscreen document.
if (message.target !== 'offscreen') {
return;
}
if (message.type !== 'get-geolocation') {
console.warn(`Unexpected message type received: '${message.type}'.`);
return;
}
// You can directly respond to the message from the service worker with the
// provided `sendResponse()` callback. But in order to be able to send an async
// response, you need to explicitly return `true` in the onMessage handler
// As a result, you can't use async/await here. You'd implicitly return a Promise.
getLocation().then((loc) => sendResponse(loc));
return true;
}
// getCurrentPosition() returns a prototype-based object, so the properties
// end up being stripped off when sent to the service worker. To get
// around this, create a deep clone.
function clone(obj) {
const copy = {};
// Return the value of any non true object (typeof(null) is "object") directly.
// null will throw an error if you try to for/in it. Just return
// the value early.
if (obj === null || !(obj instanceof Object)) {
return obj;
} else {
for (const p in obj) {
copy[p] = clone(obj[p]);
}
}
return copy;
}
async function getLocation() {
// Use a raw Promise here so you can pass `resolve` and `reject` into the
// callbacks for getCurrentPosition().
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(loc) => resolve(clone(loc)),
// in case the user doesnt have/is blocking `geolocation`
(err) => reject(err)
);
});
}
이를 제자리에 설정했으므로 이제 서비스 워커에서 화면 밖 문서에 액세스할 수 있습니다.
chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: [chrome.offscreen.Reason.GEOLOCATION || chrome.offscreen.Reason.DOM_SCRAPING],
justification: 'geolocation access',
});
화면 밖 문서에 액세스하는 경우 reason
를 포함해야 합니다. geolocation
이유는 원래 사용할 수 없었으므로 DOM_SCRAPING
의 대체를 지정하고 justification
섹션에 코드가 실제로 수행하는 작업을 설명합니다. 이 정보는 Chrome 웹 스토어의 검토 과정에서 화면 밖 문서가 유효한 목적으로 사용되고 있는지 확인하는 데 사용됩니다.
화면 밖 문서에 대한 참조가 있으면 해당 문서를 보내 업데이트된 위치정보 정보를 제공하도록 요청할 수 있습니다.
service_worker.js:
const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html';
let creating; // A global promise to avoid concurrency issues
chrome.runtime.onMessage.addListener(handleMessages);
async function getGeolocation() {
await setupOffscreenDocument(OFFSCREEN_DOCUMENT_PATH);
const geolocation = await chrome.runtime.sendMessage({
type: 'get-geolocation',
target: 'offscreen'
});
await closeOffscreenDocument();
return geolocation;
}
async function hasDocument() {
// Check all windows controlled by the service worker to see if one
// of them is the offscreen document with the given path
const offscreenUrl = chrome.runtime.getURL(OFFSCREEN_DOCUMENT_PATH);
const matchedClients = await clients.matchAll();
return matchedClients.some(c => c.url === offscreenUrl)
}
async function setupOffscreenDocument(path) {
//if we do not have a document, we are already setup and can skip
if (!(await hasDocument())) {
// create offscreen document
if (creating) {
await creating;
} else {
creating = chrome.offscreen.createDocument({
url: path,
reasons: [chrome.offscreen.Reason.GEOLOCATION || chrome.offscreen.Reason.DOM_SCRAPING],
justification: 'add justification for geolocation use here',
});
await creating;
creating = null;
}
}
}
async function closeOffscreenDocument() {
if (!(await hasDocument())) {
return;
}
await chrome.offscreen.closeDocument();
}
따라서 서비스 워커에서 위치정보를 가져오려고 할 때마다 다음을 호출하기만 하면 됩니다.
const location = await getGeolocation()
팝업 또는 측면 패널에서 위치정보 사용
팝업 또는 측면 패널 내에서 위치정보를 사용하는 것은 매우 간단합니다. 팝업 및 측면 패널은 웹 문서이므로 일반 DOM API에 액세스할 수 있습니다. navigator.geolocation
에 직접 액세스할 수 있습니다. 표준 웹사이트와의 유일한 차이점은 manifest.json
"permission"
필드를 사용하여 "geolocation"
권한을 요청해야 한다는 것입니다. 권한을 포함하지 않아도 navigator.geolocation
에 계속 액세스할 수 있습니다. 하지만 이를 사용하려고 하면 사용자가 요청을 거부한 것과 마찬가지로 즉시 오류가 발생합니다. 팝업 샘플에서 이를 확인할 수 있습니다.
콘텐츠 스크립트에서 위치정보 사용
팝업과 마찬가지로 콘텐츠 스크립트에는 DOM API에 대한 전체 액세스 권한이 있습니다. 하지만 사용자는 일반적인 사용자 권한 흐름을 거치게 됩니다. 즉, "geolocation"
를 "permissions"
에 추가해도 사용자의 액세스 권한이 자동으로 부여되지 않습니다. 지리적 위치 정보입니다. 콘텐츠 스크립트 샘플에서 이를 확인할 수 있습니다.