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

תוספים יכולים להחליף הודעות עם אפליקציות מקוריות באמצעות 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 אם הקשר הקריאה הוא קובץ שירות (service worker).

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

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

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

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

השיטות האלה לא זמינות בסקריפטים של תוכן, אלא רק בדפי התוסף וב-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 כמו שמוסבר במאמר איך מפעילים את הרישום ביומן.

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

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

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

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

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

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

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

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

מומלץ לבדוק ולבצע את הדברים הבאים:

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

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

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

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

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

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

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

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