Nhắn tin bằng ứng dụng gốc

Các tiện ích có thể trao đổi thông báo với các ứng dụng gốc bằng một API tương tự như các API truyền thông báo khác. Các ứng dụng gốc hỗ trợ tính năng này phải đăng ký máy chủ nhắn tin gốc có thể giao tiếp với tiện ích. Chrome khởi động máy chủ trong một quy trình riêng và giao tiếp với máy chủ này bằng luồng đầu vào và luồng đầu ra tiêu chuẩn.

Máy chủ nhắn tin gốc

Để đăng ký một máy chủ nhắn tin gốc, ứng dụng phải lưu tệp xác định cấu hình máy chủ nhắn tin gốc.

Sau đây là ví dụ về tệp này:

{
  "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/"]
}

Tệp kê khai của máy chủ thông báo gốc phải ở định dạng JSON hợp lệ và có chứa các trường sau:

name
Tên của máy chủ nhắn tin gốc. Ứng dụng sẽ truyền chuỗi này đến runtime.connectNative() hoặc runtime.sendNativeMessage(). Tên này chỉ có thể chứa các ký tự chữ-số viết thường, dấu gạch dưới và dấu chấm. Tên không được bắt đầu hoặc kết thúc bằng một dấu chấm và theo sau một dấu chấm không được là một dấu chấm khác.
description
Nội dung mô tả ngắn về ứng dụng.
path
Đường dẫn đến tệp nhị phân của máy chủ nhắn tin gốc. Trên Linux và macOS, đường dẫn phải là tuyệt đối. Trên Windows, giá trị này có thể là tương đối với thư mục chứa tệp kê khai. Quá trình lưu trữ bắt đầu bằng việc đặt thư mục hiện tại thành thư mục chứa tệp nhị phân của máy chủ. Ví dụ: nếu tham số này được đặt thành C:\Application\nm_host.exe, thì tham số sẽ bắt đầu bằng thư mục hiện tại "C:\Application".
type
Loại giao diện dùng để giao tiếp với máy chủ nhắn tin gốc. Tham số này có thể có một giá trị: stdio. Nó cho biết rằng Chrome cần sử dụng stdinstdout để giao tiếp với máy chủ.
allowed_origins
Danh sách các tiện ích có quyền truy cập vào máy chủ nhắn tin gốc. Các giá trị allowed-origins không được chứa ký tự đại diện.

Vị trí máy chủ nhắn tin gốc

Vị trí của tệp kê khai phụ thuộc vào nền tảng.

Trên Windows, tệp kê khai có thể nằm ở bất cứ đâu trong hệ thống tệp. Trình cài đặt ứng dụng phải tạo một khoá đăng ký, HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application hoặc HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application, và đặt giá trị mặc định của khoá đó thành đường dẫn đầy đủ đến tệp kê khai. Ví dụ: sử dụng lệnh sau:

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

hoặc sử dụng tệp .reg sau:

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

Khi Chrome tìm kiếm các máy chủ nhắn tin gốc, trước tiên, hệ thống đăng ký 32 bit sẽ được truy vấn, sau đó là hệ thống đăng ký 64 bit.

Trên macOSLinux, vị trí của tệp kê khai của máy chủ nhắn tin gốc sẽ thay đổi tuỳ theo trình duyệt (Google Chrome hoặc Chromium). Các máy chủ nhắn tin gốc trên toàn hệ thống được tra cứu tại một vị trí cố định, trong khi các máy chủ nhắn tin gốc cấp người dùng được tra cứu trong thư mục con NativeMessagingHosts/ của thư mục hồ sơ người dùng.

macOS (toàn hệ thống)
Google Chrome: /Library/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium: /Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
macOS (đường dẫn dành riêng cho người dùng, mặc định)
Google Chrome: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ~/Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
Linux (toàn hệ thống)
Google Chrome: /etc/opt/chrome/native-messaging-hosts/com.my_company.my_application.json
Chromium: /etc/chromium/native-messaging-hosts/com.my_company.my_application.json
Linux (đường dẫn mặc định dành riêng cho người dùng)
Google Chrome: ~/.config/google-chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ~/.config/chromium/NativeMessagingHosts/com.my_company.my_application.json

Giao thức nhắn tin gốc

Chrome khởi động từng máy chủ thông báo gốc trong một quy trình riêng và giao tiếp với máy chủ đó bằng đầu vào chuẩn (stdin) và đầu ra tiêu chuẩn (stdout). Định dạng tương tự được dùng để gửi thông báo theo cả hai hướng; mỗi thông báo được chuyển đổi tuần tự bằng cách sử dụng JSON, UTF-8 và theo sau độ dài thông báo 32 bit theo thứ tự byte gốc. Kích thước tối đa của một thông báo từ máy chủ nhắn tin gốc là 1 MB, chủ yếu để bảo vệ Chrome khỏi các ứng dụng gốc hoạt động không đúng cách. Kích thước tối đa của tin nhắn gửi đến máy chủ nhắn tin gốc là 4 GB.

Đối số đầu tiên cho máy chủ nhắn tin gốc là nguồn gốc của phương thức gọi, thường là chrome-extension://[ID of allowed extension]. Điều này cho phép các máy chủ nhắn tin gốc xác định nguồn của thông báo khi có nhiều tiện ích được chỉ định trong khoá allowed_origins trong tệp kê khai của máy chủ nhắn tin gốc.

Trên Windows, máy chủ nhắn tin gốc cũng được truyền một đối số dòng lệnh có ô điều khiển đến cửa sổ gốc Chrome đang gọi: --parent-window=<decimal handle value>. Việc này cho phép máy chủ nhắn tin gốc tạo các cửa sổ giao diện người dùng gốc được phân cấp chính xác. Lưu ý rằng giá trị này sẽ là 0 nếu ngữ cảnh gọi là một trình chạy dịch vụ.

Khi một cổng nhắn tin được tạo bằng runtime.connectNative(), Chrome sẽ bắt đầu quy trình lưu trữ nhắn tin gốc và tiếp tục chạy cho đến khi cổng bị huỷ bỏ. Mặt khác, khi một thông báo được gửi bằng runtime.sendNativeMessage() mà không tạo cổng nhắn tin, Chrome sẽ bắt đầu một quy trình lưu trữ thông báo gốc mới cho từng thông báo. Trong trường hợp đó, thông báo đầu tiên do quy trình lưu trữ tạo sẽ được xử lý như một phản hồi cho yêu cầu ban đầu và Chrome sẽ chuyển thông báo đó tới lệnh gọi lại phản hồi được chỉ định khi runtime.sendNativeMessage() được gọi. Trong trường hợp đó, tất cả các thông báo khác do máy chủ nhắn tin gốc tạo ra đều sẽ bị bỏ qua.

Kết nối với ứng dụng gốc

Việc gửi và nhận thông báo đến và từ một ứng dụng gốc rất giống với việc gửi và nhận thông báo trên nhiều tiện ích. Điểm khác biệt chính là runtime.connectNative() được dùng thay cho runtime.connect(), còn runtime.sendNativeMessage() được dùng thay cho runtime.sendMessage().

Để sử dụng các phương thức này, bạn phải khai báo quyền "nativeMessaging" trong tệp kê khai của tiện ích.

Các phương thức này không hoạt động trong tập lệnh nội dung, chỉ có thể sử dụng trong các trang và trình chạy dịch vụ của tiện ích. Nếu bạn muốn giao tiếp từ một tập lệnh nội dung đến ứng dụng gốc, hãy gửi thông báo đến trình chạy dịch vụ để truyền tập lệnh đó đến ứng dụng gốc.

Ví dụ sau đây sẽ tạo một đối tượng runtime.Port được kết nối với máy chủ nhắn tin gốc com.my_company.my_application, bắt đầu lắng nghe thông báo từ cổng đó và gửi một tin nhắn đi:

var port = chrome.runtime.connectNative('com.my_company.my_application');
port.onMessage.addListener(function (msg) {
  console.log('Received' + msg);
});
port.onDisconnect.addListener(function () {
  console.log('Disconnected');
});
port.postMessage({text: 'Hello, my_application'});

Sử dụng runtime.sendNativeMessage để gửi thông báo đến ứng dụng gốc mà không cần tạo cổng, ví dụ:

chrome.runtime.sendNativeMessage(
  'com.my_company.my_application',
  {text: 'Hello'},
  function (response) {
    console.log('Received ' + response);
  }
);

Gỡ lỗi thông báo gốc

Khi một số lỗi thông báo gốc nhất định xảy ra, kết quả sẽ được ghi vào nhật ký lỗi của Chrome. Điều này bao gồm cả khi máy chủ nhắn tin gốc không khởi động, ghi vào stderr hoặc vi phạm giao thức giao tiếp. Trên Linux và macOS, bạn có thể truy cập vào nhật ký này bằng cách khởi động Chrome qua dòng lệnh rồi xem kết quả của nhật ký này trong thiết bị đầu cuối. Trên Windows, hãy sử dụng --enable-logging như giải thích trong bài viết Cách bật tính năng ghi nhật ký.

Sau đây là một số lỗi thường gặp và mẹo khắc phục:

Không khởi động được máy chủ nhắn tin gốc.

Kiểm tra xem bạn có đủ quyền để thực thi tệp lưu trữ tin nhắn gốc hay không.

Đã chỉ định tên máy chủ nhắn tin gốc không hợp lệ.

Kiểm tra xem tên có chứa các ký tự không hợp lệ hay không. Chỉ cho phép các ký tự chữ-số viết thường, dấu gạch dưới và dấu chấm. Tên không được bắt đầu hoặc kết thúc bằng một dấu chấm và theo sau không được là một dấu chấm khác.

Máy chủ gốc đã thoát.

Đường dẫn đến máy chủ nhắn tin gốc bị lỗi trước khi Chrome đọc thông báo. Nhiều khả năng quá trình này sẽ được bắt đầu từ máy chủ nhắn tin gốc.

Không tìm thấy máy chủ nhắn tin gốc đã chỉ định.

Kiểm tra những thông tin sau:

  • Tên có được viết đúng chính tả trong tiện ích và trong tệp kê khai không?
  • Tệp kê khai có nằm trong đúng thư mục và có đúng tên không? Xem vị trí lưu trữ tin nhắn gốc để biết các định dạng dự kiến.
  • Tệp kê khai có đúng định dạng không? Cụ thể, JSON có hợp lệ và được định dạng đúng cách không, đồng thời các giá trị có khớp với định nghĩa của tệp kê khai máy chủ thông báo gốc không?
  • Tệp được chỉ định trong path có tồn tại không? Trên Windows, đường dẫn có thể mang tính tương đối, nhưng trên macOS và Linux, đường dẫn phải là tuyệt đối.

Tên máy chủ máy chủ nhắn tin gốc chưa được đăng ký. (chỉ dành cho Windows)

Không tìm thấy máy chủ nhắn tin gốc trong sổ đăng ký Windows. Kiểm tra kỹ bằng regedit xem khoá có thực sự được tạo và khớp với định dạng bắt buộc như trong vị trí lưu trữ tin nhắn gốc hay không.

Quyền truy cập vào máy chủ nhắn tin gốc đã chỉ định bị cấm.

Nguồn gốc của tiện ích có được liệt kê trong allowed_origins không?

Lỗi khi kết nối với máy chủ nhắn tin gốc.

Điều này cho thấy giao thức liên lạc đã được triển khai không chính xác trong máy chủ nhắn tin gốc.

  • Đảm bảo tất cả đầu ra trong stdout đều tuân thủ giao thức nhắn tin gốc. Nếu bạn muốn in một số dữ liệu cho mục đích gỡ lỗi, hãy ghi vào stderr.
  • Hãy đảm bảo độ dài thông báo 32 bit có định dạng số nguyên gốc của nền tảng (little-endian/big-endian).
  • Độ dài thông báo không được vượt quá 1024*1024.
  • Kích thước của thư phải bằng với số byte trong thư. Giá trị này có thể khác với "độ dài" của một chuỗi vì các ký tự có thể được biểu thị bằng nhiều byte.
  • Chỉ dành cho Windows: Đảm bảo chế độ I/O của chương trình đã được đặt thành O_BINARY. Theo mặc định, chế độ I/O là O_TEXT sẽ làm hỏng định dạng thông báo dưới dạng ngắt dòng (\n = 0A) được thay thế bằng phần kết thúc dòng kiểu Windows (\r\n = 0D 0A). Bạn có thể thiết lập chế độ I/O bằng cách sử dụng __setmode.