Mensagens nativas

As extensões podem trocar mensagens com aplicativos nativos usando uma API semelhante às outras APIs de transmissão de mensagens. Os aplicativos nativos que oferecem suporte a esse recurso precisam registrar um host de mensagens nativas que possa se comunicar com a extensão. O Chrome inicia o host em um processo separado e se comunica com ele usando fluxos de entrada e saída padrão.

Host de mensagens nativas

Para registrar um host de mensagens nativas, o aplicativo precisa salvar um arquivo que define a configuração do host de mensagens nativas.

Confira um exemplo do arquivo:

{
  "name": "com.my_company.my_application",
  "description": "My Application",
  "path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
  "type": "stdio",
  "allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}

O arquivo de manifesto do host de mensagens nativas precisa ser um JSON válido e conter os seguintes campos:

name
Nome do host de mensagens nativas. Os clientes transmitem essa string para runtime.connectNative() ou runtime.sendNativeMessage(). Esse nome só pode conter caracteres alfanuméricos minúsculos, sublinhados e pontos. O nome não pode começar ou terminar com um ponto, e um ponto não pode ser seguido por outro ponto.
description
Breve descrição do aplicativo.
path
Caminho para o binário do host de mensagens nativas. No Linux e no macOS, o caminho precisa ser absoluto. No Windows, ele pode ser relativo ao diretório que contém o arquivo de manifesto. O processo host é iniciado com o diretório atual definido como o diretório que contém o binário host. Por exemplo, se esse parâmetro for definido como C:\Application\nm_host.exe, ele será iniciado com o diretório atual "C:\Application".
type
Tipo da interface usada para se comunicar com o host de mensagens nativas. Esse parâmetro tem um valor possível: stdio. Isso indica que o Chrome deve usar stdin e stdout para se comunicar com o host.
allowed_origins
Lista de extensões que devem ter acesso ao host de mensagens nativas. Os valores allowed_origins não podem conter caracteres curinga.

Local do host de mensagens nativas

O local do arquivo de manifesto depende da plataforma.

No Windows, o arquivo de manifesto pode estar em qualquer lugar do sistema de arquivos. O instalador do aplicativo precisa criar uma chave do Registro, HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application ou HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application, e definir o valor padrão dessa chave como o caminho completo para o arquivo de manifesto. Por exemplo, usando o seguinte comando:

REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application" /ve /t REG_SZ /d "C:\path\to\nmh-manifest.json" /f

ou usando o seguinte arquivo .reg:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application]
@="C:\\path\\to\\nmh-manifest.json"

Quando o Chrome procura hosts de mensagens nativas, primeiro o registro de 32 bits é consultado e depois o de 64 bits.

No macOS e no Linux, o local do arquivo de manifesto do host de mensagens nativas varia de acordo com o navegador (Google Chrome, Google Chrome para testes ou Chromium). Os hosts de mensagens nativas em todo o sistema são pesquisados em um local fixo, enquanto os hosts de mensagens nativas no nível do usuário são pesquisados no subdiretório NativeMessagingHosts/ do diretório de perfil do usuário.

macOS (em todo o sistema)
Google Chrome: /Library/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Google Chrome for Testing: /Library/Google/ChromeForTesting/NativeMessagingHosts/com.my_company.my_application.json
Chromium: /Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
macOS (específico do usuário, caminho padrão)
Google Chrome: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Google Chrome for Testing: ~/Library/Application Support/Google/ChromeForTesting/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ~/Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
Linux (em todo o sistema)
Google Chrome: /etc/opt/chrome/native-messaging-hosts/com.my_company.my_application.json
Google Chrome for Testing: /etc/opt/chrome_for_testing/native-messaging-hosts/com.my_company.my_application.json
Chromium: /etc/chromium/native-messaging-hosts/com.my_company.my_application.json
Linux (específico do usuário, caminho padrão)
Google Chrome: ~/.config/google-chrome/NativeMessagingHosts/com.my_company.my_application.json
Google Chrome for Testing: ~/.config/google-chrome-for-testing/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ~/.config/chromium/NativeMessagingHosts/com.my_company.my_application.json

Protocolo de mensagens nativas

O Chrome inicia cada host de mensagens nativas em um processo separado e se comunica com ele usando entrada padrão (stdin) e saída padrão (stdout). O mesmo formato é usado para enviar mensagens nas duas direções. Cada mensagem é serializada usando JSON, codificada em UTF-8 e precedida com comprimento de mensagem de 32 bits na ordem de bytes nativa. O tamanho máximo de uma única mensagem do host de mensagens nativas é de 1 MB, principalmente para proteger o Chrome de aplicativos nativos com comportamento inadequado. O tamanho máximo da mensagem enviada ao host de mensagens nativas é de 64 MiB.

O primeiro argumento do host de mensagens nativas é a origem do chamador, geralmente chrome-extension://[ID of allowed extension]. Isso permite que os hosts de mensagens nativas identifiquem a origem da mensagem quando várias extensões são especificadas na chave allowed_origins no manifesto do host de mensagens nativas.

No Windows, o host de mensagens nativas também recebe um argumento de linha de comando com um identificador para a janela nativa do Chrome que está chamando: --parent-window=<decimal handle value>. Isso permite que o host de mensagens nativas crie janelas de interface nativa com a relação pai-filho correta. Esse valor será 0 se o contexto de chamada for um service worker.

Quando uma porta de mensagens é criada usando runtime.connectNative(), o Chrome inicia um processo de host de mensagens nativas e o mantém em execução até que a porta seja destruída. Por outro lado, quando uma mensagem é enviada usando runtime.sendNativeMessage(), sem criar uma porta de mensagens, o Chrome inicia um novo processo de host de mensagens nativas para cada mensagem. Nesse caso, a primeira mensagem gerada pelo processo do host é tratada como uma resposta à solicitação original, e o Chrome a transmite ao callback de resposta especificado quando runtime.sendNativeMessage() é chamado. Todas as outras mensagens geradas pelo host de mensagens nativas nesse caso são ignoradas.

Como se conectar a um app nativo

O envio e o recebimento de mensagens de um app nativo são muito semelhantes à troca de mensagens entre extensões. A principal diferença é que runtime.connectNative() é usado em vez de runtime.connect(), e runtime.sendNativeMessage() é usado em vez de runtime.sendMessage().

Para usar esses métodos, a permissão "nativeMessaging" precisa ser declarada no arquivo de manifesto da extensão.

Esses métodos não estão disponíveis em scripts de conteúdo, apenas nas páginas e no service worker da sua extensão. Para se comunicar de um script de conteúdo com o app nativo, envie a mensagem ao service worker para transmiti-la ao app nativo.

O exemplo a seguir cria um objeto runtime.Port conectado ao host de mensagens nativas com.my_company.my_application, começa a detectar mensagens dessa porta e envia uma mensagem de saída:

const port = chrome.runtime.connectNative('com.my_company.my_application');
port.onMessage.addListener((msg) => {
  console.log('Received', msg);
});
port.onDisconnect.addListener(() => {
  if (chrome.runtime.lastError) {
    console.error(
      'Disconnected due to error:',
      chrome.runtime.lastError.message
    );
  } else {
    console.log('Disconnected');
  }
});
port.postMessage({text: 'Hello, my_application'});

Use runtime.sendNativeMessage para enviar uma mensagem ao app nativo sem criar uma porta. Por exemplo:

chrome.runtime.sendNativeMessage(
  'com.my_company.my_application',
  {text: 'Hello'},
  (response) => {
    if (chrome.runtime.lastError) {
      console.error(
        'Error sending native message:',
        chrome.runtime.lastError.message
      );
      return;
    }
    console.log('Received', response);
  }
);

Depurar mensagens nativas

Quando ocorrem falhas de mensagens nativas, a saída de diagnóstico é gravada no registro de erros do Chrome.

Linux e macOS

# Linux
google-chrome --enable-logging=stderr --log-level=1 2>&1 | \
  grep -E "native_messag|launch_context"

# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --enable-logging=stderr --log-level=1 2>&1 | \
  grep -E "native_messag|launch_context"

Windows

Inicie o Chrome com o registro ativado:

chrome.exe --enable-logging --log-level=1

Transmita --user-data-dir="%TEMP%\nm-debug" para iniciar uma instância separada sem anexar a um processo do Chrome atual.

Para conferir a saída, transmita chrome_debug.log usando o PowerShell:

$log = "$env:LOCALAPPDATA\Google\Chrome\User Data\chrome_debug.log"
Get-Content -Wait $log | Select-String "native_messag|launch_context"

Você também pode abrir chrome_debug.log em um editor de texto e pesquisar launch_context.cc ou native_message_process_host.cc.

Detalhes importantes do registro

  • Falhas de pesquisa e análise de manifesto em launch_context.cc são registradas como avisos. Use --log-level=1 em vez de 2 (ERROR), que suprime esses diagnósticos de inicialização.
  • Pesquise launch_context para encontrar erros de manifesto e de inicialização binária e native_messag para encontrar erros de tamanho de payload e de comunicação de pipe.

Erros comuns

Confira alguns erros comuns e dicas para resolvê-los:

Não foi possível iniciar o host de mensagens nativas.

Verifique se você tem permissões suficientes para executar o arquivo host de mensagens nativas.

Nome de host de mensagens nativas inválido especificado.

Verifique se o nome contém caracteres inválidos. São permitidos apenas caracteres alfanuméricos minúsculos, sublinhados e pontos. Um nome não pode começar ou terminar com um ponto, e um ponto não pode ser seguido por outro ponto.

O host nativo foi encerrado.

O pipe para o host de mensagens nativas foi interrompido antes que a mensagem fosse lida pelo Chrome. Isso provavelmente é iniciado pelo host de mensagens nativas.

O host de mensagens nativas especificado não foi encontrado.

Verifique se:

  • O nome está escrito corretamente na extensão e no arquivo de manifesto?
  • No Windows, a chave do Registro existe em HKEY_CURRENT_USER ou HKEY_LOCAL_MACHINE, e o valor padrão dela aponta para o caminho completo do manifesto? O Chrome consulta primeiro a visualização do registro de 32 bits e depois a de 64 bits. Use regedit para verificar a chave. Consulte local do host de mensagens nativas.
  • No macOS e no Linux, o arquivo de manifesto está localizado no diretório esperado e nomeado de acordo com o host (como com.my_company.my_application.json)? Consulte localização do host de mensagens nativas.
  • O arquivo de manifesto está no formato correto? Em particular, o JSON é válido e bem formado, e os valores correspondem à definição de um manifesto de host de mensagens nativas?
  • O arquivo especificado em path existe? No Windows, os caminhos podem ser relativos, mas no macOS e no Linux, eles precisam ser absolutos.

O acesso ao host de mensagens nativas especificado é proibido.

A origem da extensão está listada em allowed_origins?

Erro ao se comunicar com o host de mensagens nativas.

Isso indica uma implementação incorreta do protocolo de comunicação no host de mensagens nativas.

  • Verifique se toda a saída em stdout segue o protocolo de mensagens nativas. Se quiser imprimir alguns dados para depuração, grave em stderr.
  • Verifique se o comprimento da mensagem de 32 bits está no formato de número inteiro nativo da plataforma (little-endian/big-endian).
  • O tamanho da mensagem não pode exceder 1024*1024.
  • O tamanho da mensagem precisa ser igual ao número de bytes nela. Isso pode ser diferente do "comprimento" de uma string, porque os caracteres podem ser representados por vários bytes.
  • Somente Windows:verifique se o modo de E/S do programa está definido como O_BINARY. Por padrão, o modo de E/S é O_TEXT, que corrompe o formato da mensagem porque as quebras de linha (\n = 0A) são substituídas por finais de linha no estilo Windows (\r\n = 0D 0A). O modo de E/S pode ser definido usando __setmode.