Native Messaging — 확장이 로컬 바이너리를 실행하는 법

확장 샌드박스 안: content.js → runtime.sendMessage → background.js(service worker). content.js 에서는 네이티브 통신을 못 한다. background.js → sendNativeMessage → Chrome. Chrome 은 OS 지정 위치의 manifest 에서 allowed_origins 에 이 확장이 있는지 대조한 뒤 호스트를 자식 프로세스로 spawn 한다. Chrome → 호스트는 stdin 으로 최대 64MiB, 호스트 → Chrome 은 stdout 으로 최대 1MB. 메시지 하나는 4바이트 길이 헤더 다음 UTF-8 JSON 이다. stdout 에 print 한 글자라도 새면 길이 자리에 끼어 프로토콜이 깨지므로 로그는 stderr 로 보낸다.

호스트를 OS 의 정해진 자리에 manifest 로 올린다 — Windows 는 레지스트리 키, macOS·Linux 는 지정된 디렉터리(macOS 는 ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/). manifest 는 name·description·path·type(stdio)·allowed_origins 를 갖는다. path 는 절대경로여야 한다. allowed_origins 가 게이트다: 확장이 호출하면 Chrome 이 이 목록에 그 확장이 있는지 대조해 있을 때만 path 의 바이너리를 띄운다. 와일드카드는 못 쓴다 — 확장이 아무 프로그램이나 실행하지 못하는 이유다.

Chrome 이 path 의 바이너리를 자식 프로세스로 spawn 하고, 대화는 소켓도 HTTP 도 아니고 stdin/stdout 이다. 메시지마다 네이티브 바이트 순서의 4바이트 길이 헤더 다음에 UTF-8 JSON 본문이 온다. 읽을 때는 4바이트를 읽어 길이를 풀고 그만큼 본문을 읽는다 — 4바이트가 비어 있으면 Chrome 이 파이프를 닫은 것이니 종료한다. 보낼 때도 길이를 먼저 쓰고 본문을 쓰고 flush 한다. stdout 에 print 로 글자 하나라도 새면 그게 길이 헤더 자리에 끼어 프로토콜이 깨지니 로그는 stderr 로 보낸다. 호스트가 부르는 프로그램(yt-dlp)도 절대경로로 부른다 — GUI 로 띄운 Chrome 은 .zshrc 를 안 읽고 호스트는 사용자 셸 환경을 물려받지 않는다.

sendNativeMessage·connectNative 는 background(service worker)에서만 부를 수 있다. content script 는 통로 밖이라 흐름이 두 파일로 갈라진다: content.js 는 페이지에서 값만 뽑아 runtime.sendMessage 로 넘기고, background.js 가 네이티브 통신을 한다 — 응답이 비동기라 onMessage 리스너에서 true 를 돌려 채널을 열어둔다. sendNativeMessage 는 첫 응답 뒤 프로세스가 끝나 값 던지고 끝에 맞고, 진행률을 흘려보내려면 connectNative 로 Port 를 열어둔다. 크기 제한이 비대칭이다: 호스트 → Chrome 은 1MB, Chrome → 호스트는 64MiB. 돌려보낼 게 크면 잘라 보내거나(stderr 를 500자로) connectNative 로 나눠 보낸다.

근거 — manifest 필드·와일드카드 불가·크기 제한은 공식 문서 그대로다.1

Footnotes

  1. manifest는 name·description·path·type·allowed_origins 를 갖는다. “List of extensions that should have access to the native messaging host. allowed-origins values can’t contain wildcards.” / 크기 제한 — “The maximum size of a single message from the native messaging host is 1 MB”, “The maximum size of the message sent to the native messaging host is 64 MiB.” (Native messaging — Chrome for Developers) ↩

#553