การรับส่งข้อความแบบเดิม

ส่วนขยายสามารถแลกเปลี่ยนข้อความกับแอปพลิเคชันดั้งเดิมได้โดยใช้ 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/"]
}

ไฟล์ Manifest ของโฮสต์การรับส่งข้อความในเครื่องต้องเป็น JSON ที่ถูกต้องและมีช่องต่อไปนี้

name
ชื่อของโฮสต์การรับส่งข้อความในเครื่อง ไคลเอ็นต์จะส่งสตริงนี้ไปยัง runtime.connectNative() หรือ runtime.sendNativeMessage() ชื่อนี้มีได้เฉพาะอักขระที่เป็นตัวอักษรและตัวเลขคละกันพิมพ์เล็ก ขีดล่าง และจุด ชื่อต้องไม่ขึ้นต้นหรือลงท้ายด้วยจุด และจุดต้องไม่ตามด้วยจุดอีกจุด
description
คำอธิบายแอปพลิเคชันแบบย่อ
path
เส้นทางไปยังไบนารีของโฮสต์การรับส่งข้อความในเครื่อง ใน Linux และ macOS เส้นทางต้องเป็นค่าสัมบูรณ์ ใน Windows เส้นทางนี้อาจสัมพันธ์กับไดเรกทอรีที่มีไฟล์ Manifest กระบวนการโฮสต์จะเริ่มต้นโดยตั้งค่าไดเรกทอรีปัจจุบันเป็นไดเรกทอรีที่มีไบนารีของโฮสต์ เช่น หากตั้งค่าพารามิเตอร์นี้เป็น C:\Application\nm_host.exe ระบบจะเริ่มต้นด้วยไดเรกทอรีปัจจุบัน `C:\Application`
type
ประเภทของอินเทอร์เฟซที่ใช้ในการสื่อสารกับโฮสต์การรับส่งข้อความในเครื่อง พารามิเตอร์นี้มีค่าที่เป็นไปได้ค่าเดียวคือ stdio ซึ่งระบุว่า Chrome ควรใช้ stdin และ stdout เพื่อสื่อสารกับโฮสต์
allowed_origins
รายการส่วนขยายที่ควรมีสิทธิ์เข้าถึงโฮสต์การรับส่งข้อความในเครื่อง ค่า allowed_origins ต้องไม่มีไวลด์การ์ด

ตำแหน่งโฮสต์การรับส่งข้อความในเครื่อง

ตำแหน่งของไฟล์ Manifest จะขึ้นอยู่กับแพลตฟอร์ม

ใน Windows คุณวางไฟล์ Manifest ไว้ที่ใดก็ได้ในระบบไฟล์ โปรแกรมติดตั้งแอปพลิเคชัน ต้องสร้างคีย์รีจิสทรี ไม่ว่าจะเป็น HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application หรือ HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application และ ตั้งค่าเริ่มต้นของคีย์นั้นเป็นเส้นทางแบบเต็มไปยังไฟล์ Manifest เช่น ใช้คำสั่งต่อไปนี้

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 ตำแหน่งของไฟล์ Manifest ของโฮสต์การรับส่งข้อความในเครื่องจะแตกต่างกันไปตามเบราว์เซอร์ (Google Chrome, Chrome สำหรับการทดสอบ หรือ Chromium) ระบบจะค้นหาโฮสต์การรับส่งข้อความที่มาพร้อมระบบทั่วทั้งระบบในตำแหน่งที่แน่นอน ส่วนโฮสต์การรับส่งข้อความที่มาพร้อมระบบระดับผู้ใช้จะค้นหาในNativeMessagingHosts/ไดเรกทอรีย่อย ของไดเรกทอรีโปรไฟล์ผู้ใช้

macOS (ทั้งระบบ)
Google Chrome: /Library/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Google Chrome สำหรับการทดสอบ: /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 สำหรับการทดสอบ: ~/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 สำหรับการทดสอบ: /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 สำหรับการทดสอบ: ~/.config/google-chrome-for-testing/NativeMessagingHosts/com.my_company.my_application.json
Chromium: ~/.config/chromium/NativeMessagingHosts/com.my_company.my_application.json

โปรโตคอลการรับส่งข้อความในเครื่อง

Chrome จะเริ่มโฮสต์การรับส่งข้อความในเครื่องแต่ละรายการในกระบวนการแยกต่างหากและสื่อสารกับโฮสต์ดังกล่าวโดยใช้อินพุตมาตรฐาน (stdin) และเอาต์พุตมาตรฐาน (stdout) ระบบจะใช้รูปแบบเดียวกันในการส่งข้อความในทั้ง 2 ทิศทาง โดยจะมีการเรียงอันดับข้อความแต่ละรายการโดยใช้ JSON, เข้ารหัส UTF-8 และนำหน้าด้วยความยาวของข้อความ 32 บิตในลำดับไบต์ดั้งเดิม ขนาดสูงสุดของข้อความเดียวจากโฮสต์การรับส่งข้อความดั้งเดิมคือ 1 MB ซึ่งส่วนใหญ่มีไว้เพื่อปกป้อง Chrome จากแอปพลิเคชันดั้งเดิมที่ทำงานไม่ถูกต้อง ขนาดสูงสุดของ ข้อความที่ส่งไปยังโฮสต์การรับส่งข้อความในเครื่องคือ 64 MiB

อาร์กิวเมนต์แรกของโฮสต์การรับส่งข้อความในเครื่องคือต้นทางของผู้เรียก ซึ่งโดยปกติคือ chrome-extension://[ID of allowed extension] ซึ่งจะช่วยให้โฮสต์การรับส่งข้อความในเครื่องระบุแหล่งที่มาของข้อความได้เมื่อมีการระบุส่วนขยายหลายรายการในคีย์ allowed_origins ในไฟล์ Manifest ของโฮสต์การรับส่งข้อความในเครื่อง

ใน Windows โฮสต์การรับส่งข้อความในเครื่องจะได้รับอาร์กิวเมนต์บรรทัดคำสั่งที่มีแฮนเดิลไปยัง หน้าต่างในเครื่องของ Chrome ที่เรียกใช้ด้วย --parent-window=<decimal handle value> ซึ่งจะช่วยให้โฮสต์การรับส่งข้อความในเครื่องสร้างหน้าต่าง UI ในเครื่องที่เชื่อมโยงกับองค์ประกอบหลักได้อย่างถูกต้อง โปรดทราบว่าค่านี้จะเป็น 0 หากบริบทการเรียกเป็น Service Worker

เมื่อสร้างพอร์ตการรับส่งข้อความโดยใช้ runtime.connectNative() Chrome จะเริ่มกระบวนการโฮสต์การรับส่งข้อความดั้งเดิม และจะเรียกใช้กระบวนการนี้ต่อไปจนกว่าจะทำลายพอร์ต ในทางกลับกัน เมื่อส่งข้อความโดยใช้ runtime.sendNativeMessage() โดยไม่ได้สร้างพอร์ตการรับส่งข้อความ Chrome จะเริ่มกระบวนการโฮสต์การรับส่งข้อความในเครื่องใหม่สำหรับแต่ละข้อความ ในกรณีดังกล่าว ระบบจะจัดการข้อความแรกที่โฮสต์สร้างขึ้น เป็นคำตอบสำหรับคำขอเดิม และ Chrome จะส่งข้อความนั้นไปยังการเรียกกลับการตอบกลับ ที่ระบุเมื่อมีการเรียกใช้ runtime.sendNativeMessage() ระบบจะไม่สนใจข้อความอื่นๆ ทั้งหมดที่โฮสต์การรับส่งข้อความในเครื่องสร้างขึ้นในกรณีดังกล่าว

การเชื่อมต่อกับแอปพลิเคชันแบบเนทีฟ

การส่งและรับข้อความไปยังและจากแอปพลิเคชันแบบเนทีฟจะคล้ายกับการรับส่งข้อความข้ามส่วนขยายเป็นอย่างมาก ความแตกต่างหลักคือใช้ runtime.connectNative() แทน runtime.connect() และใช้ runtime.sendNativeMessage() แทน runtime.sendMessage()

หากต้องการใช้วิธีการเหล่านี้ คุณต้องประกาศสิทธิ์ "nativeMessaging" ในไฟล์ Manifest ของส่วนขยาย

วิธีการเหล่านี้ใช้ไม่ได้ภายใน Content Script แต่ใช้ได้เฉพาะภายในหน้าเว็บและ Service Worker ของส่วนขยาย หากต้องการสื่อสารจาก Content Script ไปยังแอปพลิเคชันแบบเนทีฟ ให้ส่งข้อความไปยัง 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 ได้ด้วย

รายละเอียดการบันทึกที่สำคัญ

  • ระบบจะบันทึกการค้นหาและการแยกวิเคราะห์ไฟล์ Manifest ที่ล้มเหลวใน launch_context.cc เป็นคำเตือน ใช้ --log-level=1 แทน 2 (ข้อผิดพลาด) ซึ่งจะระงับการวินิจฉัยการเริ่มต้นเหล่านี้
  • ค้นหา launch_context เพื่อหาข้อผิดพลาดในการเปิดใช้ไฟล์ Manifest และไบนารี และ native_messag เพื่อหาข้อผิดพลาดเกี่ยวกับขนาดเพย์โหลดและการสื่อสารผ่านไปป์

ข้อผิดพลาดที่พบบ่อย

ข้อผิดพลาดที่พบบ่อยและเคล็ดลับในการแก้ไขมีดังนี้

เริ่มโฮสต์การรับส่งข้อความในเครื่องไม่สำเร็จ

ตรวจสอบว่าคุณมีสิทธิ์เพียงพอที่จะเรียกใช้ไฟล์โฮสต์การรับส่งข้อความในเครื่องหรือไม่

ระบุชื่อโฮสต์การรับส่งข้อความในเครื่องไม่ถูกต้อง

ตรวจสอบว่าชื่อมีอักขระที่ไม่ถูกต้องหรือไม่ อนุญาตให้ใช้เฉพาะอักขระที่เป็นตัวอักษรพิมพ์เล็กและตัวเลขคละกัน ขีดล่าง และจุดเท่านั้น ชื่อต้องไม่ขึ้นต้นหรือลงท้ายด้วยจุด และจุดต้องไม่ ตามด้วยจุดอีก

โฮสต์ดั้งเดิมออกจากการประชุมแล้ว

การเชื่อมต่อกับโฮสต์การรับส่งข้อความในเครื่องขาดหายไปก่อนที่ Chrome จะอ่านข้อความ ซึ่งส่วนใหญ่ มักจะเริ่มจากโฮสต์การรับส่งข้อความในเครื่องของคุณ

ไม่พบโฮสต์การรับส่งข้อความในเครื่องที่ระบุ

โปรดตรวจสอบสิ่งต่อไปนี้

  • ชื่อสะกดถูกต้องในส่วนขยายและในไฟล์ Manifest หรือไม่
  • ใน Windows มีคีย์รีจิสทรีอยู่ภายใต้ HKEY_CURRENT_USER หรือ HKEY_LOCAL_MACHINE และค่าเริ่มต้นของคีย์ชี้ไปยังเส้นทางแบบเต็มของไฟล์ Manifest หรือไม่ Chrome จะค้นหามุมมองรีจิสทรีแบบ 32 บิตก่อน แล้วจึงค้นหามุมมองแบบ 64 บิต ใช้ regedit เพื่อยืนยันคีย์ ดูตำแหน่งโฮสต์การรับส่งข้อความในเครื่อง
  • ใน macOS และ Linux ไฟล์ Manifest อยู่ในไดเรกทอรีที่คาดไว้ และมีชื่อตามโฮสต์ (เช่น com.my_company.my_application.json) หรือไม่ ดูตำแหน่งโฮสต์การรับส่งข้อความในเครื่อง
  • ไฟล์ Manifest อยู่ในรูปแบบที่ถูกต้องหรือไม่ โดยเฉพาะอย่างยิ่ง JSON ถูกต้องและมีรูปแบบที่ถูกต้องหรือไม่ และค่าต่างๆ ตรงกับคำจำกัดความของ Manifest ของโฮสต์การรับส่งข้อความในเครื่องหรือไม่
  • มีไฟล์ที่ระบุใน path หรือไม่ ใน Windows เส้นทางอาจเป็นแบบสัมพัทธ์ แต่ใน macOS และ Linux เส้นทางต้องเป็นแบบสัมบูรณ์

ไม่อนุญาตให้เข้าถึงโฮสต์การรับส่งข้อความในเครื่องที่ระบุ

ต้นทางของส่วนขยายแสดงอยู่ใน allowed_origins หรือไม่

เกิดข้อผิดพลาดเมื่อสื่อสารกับโฮสต์การรับส่งข้อความในเครื่อง

ซึ่งบ่งชี้ว่ามีการติดตั้งใช้งานโปรโตคอลการสื่อสารในโฮสต์การรับส่งข้อความในเครื่องไม่ถูกต้อง

  • ตรวจสอบว่าเอาต์พุตทั้งหมดใน stdout เป็นไปตามโปรโตคอลการรับส่งข้อความที่มาพร้อมระบบ หากต้องการ พิมพ์ข้อมูลบางอย่างเพื่อวัตถุประสงค์ในการแก้ไขข้อบกพร่อง โปรดเขียนถึง stderr
  • ตรวจสอบว่าความยาวของข้อความแบบ 32 บิตอยู่ในรูปแบบจำนวนเต็มดั้งเดิมของแพลตฟอร์ม (little-endian / big-endian)
  • ความยาวของข้อความต้องไม่เกิน 1024*1024
  • ขนาดข้อความต้องเท่ากับจำนวนไบต์ในข้อความ ซึ่งอาจแตกต่างจาก "ความยาว" ของสตริง เนื่องจากอักขระอาจแสดงด้วยหลายไบต์
  • Windows เท่านั้น: ตรวจสอบว่าได้ตั้งค่าโหมด I/O ของโปรแกรมเป็น O_BINARY แล้ว โดยค่าเริ่มต้น โหมด I/O คือ O_TEXT ซึ่งจะทำให้รูปแบบข้อความเสียหายเนื่องจากระบบจะแทนที่ตัวแบ่งบรรทัด (\n = 0A) ด้วย ตัวสิ้นสุดบรรทัดสไตล์ Windows (\r\n = 0D 0A) คุณตั้งค่าโหมด I/O ได้โดยใช้ __setmode