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

תוספים יכולים להחליף הודעות עם אפליקציות מקומיות באמצעות 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, ‏ Google Chrome for Testing או Chromium). המערכת מחפשת את המארחים להעברת הודעות באפליקציות מקוריות במיקום קבוע, ואת המארחים להעברת הודעות באפליקציות מקוריות ברמת המשתמש היא מחפשת בספריית המשנה NativeMessagingHosts/ של ספריית פרופיל המשתמש.

macOS (כלל המערכת)
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 (נתיב ברירת המחדל שספציפי למשתמש)
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 (כלל המערכת)
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 (ספציפי למשתמש, נתיב ברירת המחדל)
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

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

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

הארגומנט הראשון למארח להעברת הודעות נייטיב הוא המקור של המתקשר, בדרך כלל 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 יעביר אותה לקריאה החוזרת של התגובה שצוינה כשמתבצעת קריאה ל-runtime.sendNativeMessage(). המערכת מתעלמת מכל שאר ההודעות שנוצרו על ידי מארח להעברת הודעות נייטיב במקרה הזה.

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

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

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

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

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

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

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

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

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

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

‫Linux ו-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

מפעילים את Chrome עם רישום ביומן מופעל:

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

מעבירים את --user-data-dir="%TEMP%\nm-debug" כדי להפעיל מופע נפרד בלי לצרף אותו לתהליך קיים של Chrome.

כדי לראות את הפלט, מריצים את הפקודה chrome_debug.log באמצעות PowerShell:

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

אפשר גם לפתוח את chrome_debug.log בעורך טקסט ולחפש את launch_context.cc או native_message_process_host.cc.

פרטים עיקריים ביומן

  • חיפושים וניתוחים של מניפסטים שנכשלו ב-launch_context.cc נרשמים ביומן כאזהרות. משתמשים ב---log-level=1 במקום ב-2 (ERROR), כדי להשבית את האבחון של ההפעלה.
  • מחפשים launch_context כדי למצוא שגיאות בהפעלת מניפסט וקובץ בינארי, ומחפשים native_messag כדי למצוא שגיאות בגודל מטען הייעודי ובצינור תקשורת.

שגיאות נפוצות

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

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

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

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

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

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

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

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

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

  • האם האיות של השם נכון בתוסף ובקובץ המניפסט?
  • ב-Windows, האם מפתח הרישום קיים ב-HKEY_CURRENT_USER או ב-HKEY_LOCAL_MACHINE, והאם ערך ברירת המחדל שלו מצביע על הנתיב המלא של המניפסט? ‫Chrome שולח שאילתות לתצוגת הרישום של ‎32-bit קודם, ואז לתצוגת הרישום של ‎64-bit. משתמשים בregedit כדי לאמת את המפתח. מידע נוסף על מיקום של מארח להעברת הודעות נייטיב
  • ב-macOS וב-Linux, האם קובץ המניפסט נמצא בספרייה הצפויה והשם שלו זהה לשם המארח (למשל com.my_company.my_application.json)? מידע נוסף זמין במאמר בנושא מיקום מארח להעברת הודעות נייטיב.
  • האם קובץ המניפסט בפורמט הנכון? בפרט, האם ה-JSON תקין ומעוצב היטב, והאם הערכים תואמים להגדרה של מניפסט של מארח להעברת הודעות נייטיב?
  • האם הקובץ שצוין ב-path קיים? ב-Windows, הנתיבים יכולים להיות יחסיים, אבל ב-macOS וב-Linux, הנתיבים חייבים להיות מוחלטים.

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

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

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

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

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