העברת הודעות באפליקציות מקוריות

תוספים יכולים להחליף הודעות עם אפליקציות נייטיב באמצעות ממשק API שדומה לשאר ממשקי ה-API להעברת הודעות. אפליקציות מקומיות שתומכות בתכונה הזו צריכות לרשום מארח מקומי להעברת הודעות שיכול לתקשר עם התוסף. Chrome מפעיל את המארח בתהליך נפרד ומנהל איתו תקשורת באמצעות מקורות קלט ופלט רגילים.

מארח להעברת הודעות נייטיב

כדי לרשום מארח העברת הודעות נייטיב, האפליקציה צריכה לשמור קובץ שמגדיר את תצורת המארח להעברת הודעות נייטיב.

דוגמה לקובץ:

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

קובץ המניפסט של מארח ההודעות המקומיות חייב להיות קובץ JSON תקין ולהכיל את השדות הבאים:

name
השם של המארח להעברת הודעות נייטיב. לקוחות מעבירים את המחרוזת הזו אל runtime.connectNative() או אל runtime.sendNativeMessage(). השם יכול להכיל רק תווים אלפאנומריים (אותיות קטנות), קווים תחתונים ונקודות. השם לא יכול להתחיל או להסתיים בנקודה, ואי אפשר להוסיף אחריה נקודה.
description
תיאור קצר של האפליקציה.
path
הנתיב לקובץ הבינארי של המארח להעברת הודעות נייטיב. ב-Linux וב-macOS, הנתיב חייב להיות מוחלט. ב-Windows, הוא יכול להיות יחסי לספרייה שמכילה את קובץ המניפסט. תהליך המארח מופעל כשהספרייה הנוכחית מוגדרת לספרייה שמכילה את קובץ הבינארי של המארח. לדוגמה, אם הפרמטר הזה מוגדר לערך C:\Application\nm_host.exe, הוא יתחיל בספרייה הנוכחית 'C:\Application'.
type
סוג הממשק שמשמש לתקשורת עם מארח ההודעות המקורי. לפרמטר הזה יש ערך אפשרי אחד: stdio. המשמעות היא ש-Chrome צריך להשתמש ב-stdin וב-stdout כדי לתקשר עם המארח.
allowed_origins
רשימת התוספים שצריכה להיות להם גישה למארח של העברת ההודעות באפליקציות מקוריות. הערכים של allowed-origins לא יכולים להכיל תווים כלליים לחיפוש.

מיקום המארח להעברת הודעות נייטיב

המיקום של קובץ המניפסט תלוי בפלטפורמה.

ב-Windows, אפשר למקם את קובץ המניפסט בכל מקום במערכת הקבצים. מתקין האפליקציה צריך ליצור מפתח רישום, HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application או HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application, ולהגדיר את ערך ברירת המחדל של המפתח הזה לנתיב המלא לקובץ המניפסט. לדוגמה, באמצעות הפקודה הבאה:

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

או באמצעות קובץ ה-.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"

כש-Chrome מחפש מארחים של הודעות מקוריות, מתבצעת שאילתה בתחילה במרשם של 32 ביט, ואז במרשם של 64 ביט.

ב-macOS וב-Linux, המיקום של קובץ המניפסט של מארח ההודעות המקומי משתנה בהתאם לדפדפן (Google Chrome או Chromium). המארחים להעברת הודעות באפליקציות מקוריות ברמת המערכת נמצאים במיקום קבוע, ואילו המארחים להעברת הודעות באפליקציות מקוריות ברמת המשתמש נמצאים בתיקיית המשנה NativeMessagingHosts/ בספריית פרופיל המשתמש.

macOS (ברמת המערכת)
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 (נתיב ברירת המחדל שספציפי למשתמש)
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 (כל המערכת)
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 (נתיב ברירת המחדל, ספציפי למשתמש)
Google Chrome: ‏ ~/.config/google-chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ‏ ~/.config/chromium/NativeMessagingHosts/com.my_company.my_application.json

פרוטוקול להעברת הודעות מקומי

Chrome מפעיל כל מארח של העברת הודעות נייטיב בתהליך נפרד ויוצר איתו קשר באמצעות קלט סטנדרטי (stdin) ופלט סטנדרטי (stdout). אותו פורמט משמש לשליחת הודעות בשני הכיוונים. כל הודעה עוברת סריאליזציה באמצעות JSON וקידוד UTF-8 ולפניה הודעה באורך 32 ביט לפי סדר בייט מקורי. הגודל המקסימלי של הודעה אחת ממארח ההודעות המקומי הוא 1MB, בעיקר כדי להגן על Chrome מאפליקציות מקומיות שמתנהגות בצורה לא תקינה. הגודל המקסימלי של ההודעה שנשלחת למארח של הודעות מקוריות הוא 4GB.

הארגומנט הראשון למארח שליחת ההודעות המקורי הוא המקור של מבצע הקריאה החוזרת, בדרך כלל chrome-extension://[ID of allowed extension]. כך מארחים להעברת הודעות יכולים לזהות את המקור של ההודעה כשמצוינים כמה תוספים במפתח allowed_origins במניפסט של המארח להעברת הודעות.

ב-Windows, למארח להעברת הודעות נייטיב מועברת גם ארגומנט של שורת פקודה עם אחיזה בחלון הנייטיב של Chrome שמבצע את הקריאה: --parent-window=<decimal handle value>. כך מארח ההודעות המקורי יוכל ליצור חלונות ממשק משתמש נייטיב עם הורה תקין. הערה: הערך הזה יהיה 0 אם הקשר הקריאה הוא שירות עובד.

כשיוצרים יציאת שליחת הודעות באמצעות runtime.connectNative(), Chrome מפעיל את תהליך המארח המקומי של שליחת ההודעות וממשיך להפעיל אותו עד שהיציאה נהרסת. לעומת זאת, כששולחים הודעה באמצעות runtime.sendNativeMessage(), בלי ליצור יציאת שליחת הודעות, Chrome מפעיל תהליך חדש של מארח שליחת הודעות מקומי לכל הודעה. במקרה כזה, ההודעה הראשונה שנוצרת על ידי תהליך המארח מטופלת בתור תגובה לבקשה המקורית, ו-Chrome מעביר אותה ל-callback של התגובה שצוין בקריאה ל-runtime.sendNativeMessage(). במקרה כזה, המערכת תתעלם מכל ההודעות האחרות שנוצרות על ידי המארח המקומי להעברת הודעות.

התחברות לאפליקציה מקורית

שליחה וקבלה של הודעות אל אפליקציית נייטיב דומה מאוד להעברת הודעות בין תוספים. ההבדל העיקרי הוא שמשתמשים ב-runtime.connectNative() במקום ב-runtime.connect(), וב-runtime.sendNativeMessage() במקום ב-runtime.sendMessage().

כדי להשתמש בשיטות האלה, צריך להצהיר על ההרשאה nativeMessaging בקובץ המניפסט של התוספים.

השיטות האלה לא זמינות בתוך סקריפטים של תוכן, אלא רק בדפים וב-service worker של התוסף. אם רוצים לתקשר מסקריפט תוכן לאפליקציה המקורית, צריך לשלוח את ההודעה ל-Service Worker כדי להעביר אותה לאפליקציה המקורית.

הדוגמה הבאה יוצרת אובייקט runtime.Port שמחובר למארח העברת הודעות נייטיב com.my_company.my_application, מתחיל להקשיב להודעות מהיציאה הזו ושולח הודעה יוצאת אחת:

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'});

משתמשים ב-runtime.sendNativeMessage כדי לשלוח הודעה לאפליקציה המקורית בלי ליצור יציאה, למשל:

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

ניפוי באגים בהעברת הודעות מקומיות

כשמתרחשים כשלים מסוימים בהעברת הודעות מקומיות, הפלט נכתב ביומן השגיאות של Chrome. כולל מקרים שבהם המארח להעברת הודעות נייטיב לא מצליח להתחיל, כותב ל-stderr או מפר את פרוטוקול התקשורת. ב-Linux וב-macOS, אפשר לגשת ליומן הזה על ידי הפעלת Chrome משורת הפקודה וצפייה בפלט שלו במסוף. ב-Windows, משתמשים ב---enable-logging כפי שמוסבר במאמר איך מפעילים את הרישום ביומן.

ריכזנו כאן כמה שגיאות נפוצות וטיפים לפתרון שלהן:

Failed to start native messaging host

בודקים אם יש לכם הרשאות מספיקות להרצת קובץ המארח להעברת הודעות באפליקציות מקוריות.

צוין שם מארח לא חוקי של הודעות מקוריות.

יש לבדוק אם השם מכיל תווים לא חוקיים. מותר להשתמש רק בתווים אלפאנומריים באותיות קטנות, קווים תחתונים ונקודות. שם לא יכול להתחיל או להסתיים בנקודה, ולא יכולה להיות נקודה אחרי נקודה.

המארח המקומי עזב.

החיבור למארח העברת ההודעות הפנימי נשבר לפני ש-Chrome קרא את ההודעה. סביר להניח שהמצב הזה מתחיל על ידי מארח העברת ההודעות הנייטיב.

המארח שצוין להעברת הודעות נייטיב לא נמצא.

בדוק את הפרטים הבאים:

  • האם השם מאוית נכון בסיומת ובקובץ המניפסט?
  • האם המניפסט נמצא בספרייה הנכונה ועם השם הנכון? במיקום המארח של העברת ההודעות מפורטים הפורמטים הצפויים.
  • האם קובץ המניפסט בפורמט הנכון? באופן ספציפי, האם ה-JSON תקין ובפורמט תקין, והאם הערכים תואמים להגדרה של מניפסט של מארח להעברת הודעות נייטיב?
  • האם הקובץ שצוין ב-path קיים? ב-Windows, הנתיבים יכולים להיות יחסיים, אבל ב-macOS וב-Linux, הנתיבים חייבים להיות מוחלטים.

שם המארח של המארח להעברת הודעות באפליקציות מקוריות לא רשום. (Windows בלבד)

המארח המקורי להעברת הודעות לא נמצא במרשם של Windows. בודקים באמצעות regedit אם המפתח נוצר באמת ושהוא תואם לפורמט הנדרש, כפי שמתואר במאמר מיקום המארח של הודעות מקוריות.

הגישה למארח העברת ההודעות המקורי שצוין אסורה.

האם המקור של התוסף מופיע ב-allowed_origins?

שגיאה בתקשורת עם מארח ההודעות המקורי.

המשמעות היא שהטמעת פרוטוקול התקשורת במארח להעברת הודעות מקוריות שגויה.

  • יש לוודא שכל הפלט ב-stdout תואם לפרוטוקול להעברת הודעות נייטיב. כדי להדפיס נתונים מסוימים למטרות ניפוי באגים, כותבים אל stderr.
  • חשוב לוודא שאורך ההודעה של 32 ביט הוא בפורמט המספר השלם המקורי של הפלטפורמה (Lite-endian / big-endian).
  • אורך ההודעה לא יכול לחרוג מ-1024*1024.
  • גודל ההודעה חייב להיות שווה למספר הבייטים בהודעה. הערך הזה עשוי להיות שונה מ'אורך' המחרוזת, כי תווים יכולים להיות מיוצגים על ידי כמה בייטים.
  • ב-Windows בלבד: מוודאים שמצב הקלט/פלט של התוכנית מוגדר ל-O_BINARY. כברירת מחדל, מצב הקלט/פלט הוא O_TEXT, והוא גורם לפגיעה בפורמט ההודעה כי תוספי השורה (\n = 0A) מוחלפים בסימני סיום שורה בסגנון Windows (\r\n = 0D 0A). אפשר להגדיר את מצב הקלט/פלט באמצעות __setmode.