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

Các tiện ích và ứng dụng 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 biết cách 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áy chủ nhắn tin gốc, ứng dụng phải cài đặt một tệp kê khai xác định cấu hình máy chủ nhắn tin gốc. Dưới đây là một ví dụ về tệp kê khai:

{
  "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 là định dạng JSON hợp lệ và có chứa các trường sau:

TênNội dung mô tả
nameTên của máy chủ nhắn tin gốc. Ứng dụng sẽ chuyể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 không được là một dấu chấm khác.
descriptionNộ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à OSX, đường dẫn phải là tuyệt đối. Trên Windows, giá trị này có thể 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ẽ được bắt đầu bằng thư mục hiện tại C:\Application\.
typeLoại giao diện dùng để giao tiếp với máy chủ nhắn tin gốc. Hiện tại, bạn chỉ có thể sử dụng một giá trị cho tham số này: stdio. Nó cho biết rằng Chrome cần sử dụng stdinstdout để giao tiếp với máy chủ.
allowed_originsDanh sách các tiện ích có quyền truy cập vào máy chủ nhắn tin gốc. Không cho phép các ký tự đại diện như chrome-extension://*/*.

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 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 OS XLinux, vị trí của tệp kê khai của máy chủ nhắn tin gốc sẽ khác nhau 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 một thư mục con thuộc thư mục hồ sơ người dùng có tên là NativeMessagingHosts.

  • OS X (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
  • OS X (đường dẫn mặc định dành riêng cho người dùng)
    • 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 phương thức nhập tiêu 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 JSON, được mã hoá UTF-8 và đứng 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. Cảnh báo: Trong Windows, trong Chrome 54 trở xuống, nguồn gốc được chuyển dưới dạng tham số thứ hai thay vì tham số đầu tiên.

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ý dưới dạng phản hồi cho yêu cầu ban đầu, tức là Chrome sẽ chuyển thông báo đó đến lệnh gọi lại phản hồi được chỉ định khi gọi runtime.sendNativeMessage. 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.

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ẽ bằng 0 nếu ngữ cảnh gọi là trang tập lệnh nền.

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 sử dụng thay cho runtime.connectruntime.sendNativeMessage được sử dụng thay cho runtime.sendMessage. Bạn chỉ có thể sử dụng các phương thức này nếu quyền "nativeMessaging" được khai báo trong tệp kê khai của ứng dụng.

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 thông báo gửi đ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" });

Bạn có thể 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áy chủ nhắn tin gốc không khởi động được, ghi vào stderr hoặc khi máy chủ đó vi phạm giao thức giao tiếp, kết quả sẽ được ghi vào nhật ký lỗi của Chrome. Trên Linux và OS X, bạn có thể dễ dàng truy cập nhật ký này bằng cách khởi động Chrome qua dòng lệnh và 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ý.

Dưới đây là một số lỗi và mẹo để giải quyết vấn đề:

  • 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 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 ký tự không hợp lệ nào 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 được chỉ định.
    • 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ó được đặt vào đúng thư mục và đú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ể, cú pháp JSON có chính xác không và các giá trị có khớp với định nghĩa của tệp kê khai máy chủ nhắn tin 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ể là tương đối, nhưng trên OS X và Linux, đường dẫn phải là tuyệt đối.
  • Tên máy chủ của 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.
  • Cấm truy cập vào máy chủ nhắn tin gốc đã chỉ định.
    • 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.
    • Đây là một lỗi rất phổ biến và chỉ ra việc triển khai giao thức liên lạc 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.