简体   繁体   English

Chrome 扩展 NativeMessaging 'connectNative' 未定义

[英]Chrome Extension NativeMessaging 'connectNative' undefined

I am trying to implement a chrome extension using runtime.connectNative and postMessage.我正在尝试使用 runtime.connectNative 和 postMessage 实现一个 chrome 扩展。 I am following the chrome documentation , downloaded the native messaging example which I'm trying to run without any changes, while the code for the native host application can be found here .我正在关注chrome 文档,下载了我试图在没有任何更改的情况下运行的本机消息传递示例,而本机主机应用程序的代码可以在这里找到。

However, I'm getting the error: Uncaught TypeError: Cannot read property 'connectNative' of undefined.但是,我收到错误:未捕获的类型错误:无法读取未定义的属性“connectNative”。

The error is being triggered from the javascript extension file, in this line:错误是从 javascript 扩展文件触发的,在这一行:
port = chrome.runtime.connectNative(hostName);端口 = chrome.runtime.connectNative(hostName);

while the extension is being loaded from the manifest like so:当从清单加载扩展时,如下所示:

"app": {
   "launch": {
      "local_path": "main.html"
   }
}

Any ideas how to solve the problem please?任何想法如何解决问题?

Chrome version 34, tested on windows 7, 8.1 Chrome 版本 34,在 Windows 7、8.1 上测试

The immediate problem is that you are not running the sample code correctly.直接的问题是您没有正确运行示例代码。 The larger problem is that Google has not provided comprehensive documentation on how to use this sample code.更大的问题是谷歌没有提供关于如何使用这个示例代码的全面文档。

The Native Messaging example you referenced only links to the sample code for the Chrome extension.您引用的本机消息传递示例仅链接到 Chrome 扩展程序的示例代码。 After searching around I was able to find related sample code for the native messaging host application.四处搜索后,我找到了本机消息传递主机应用程序的相关示例代码。 To get the sample code for both the Chrome extension and native messaging host application together you'll want to download nativeMessaging.zip .要同时获取 Chrome 扩展程序和本机消息传递主机应用程序的示例代码,您需要下载nativeMessaging.zip In that zip file you'll also find some brief instructions on how to install the native messaging host on Windows, Linux and Mac OS X. I'll tell you right now that the instructions are incomplete as they do not tell you how to install the Chrome extension.在该 zip 文件中,您还会找到一些关于如何在 Windows、Linux 和 Mac OS X 上安装本机消息传递主机的简要说明。我现在告诉您这些说明不完整,因为它们没有告诉您如何安装Chrome 扩展程序。 Additionally the scripts for installing and uninstalling the native messaging host do not work as-is on OS X. See below for my installation instructions and corrected scripts.此外,用于安装和卸载本机消息传递主机的脚本在 OS X 上无法按原样运行。有关我的安装说明和更正脚本,请参见下文。

How to install the sample extension and native host application如何安装示例扩展和本机主机应用程序

  1. Download and unzip the nativeMessaging.zip file.下载并解压缩 nativeMessaging.zip 文件。
  2. Install the Chrome extension安装 Chrome 扩展程序
    1. In Chrome enter chrome://extensions/ in the address bar在 Chrome 中,在地址栏中输入chrome://extensions/
    2. Click the “Load unpacked extension...” button单击“加载已解压的扩展程序...”按钮
    3. Navigate to the unzipped nativeMessaging directory and select the app directory for import导航到解压的nativeMessaging目录并选择要导入的app目录
  3. Install the native messaging host application安装本机消息传递主机应用程序
    1. For OS X and Linux you'll need to add execute permission to some of the files.对于 OS X 和 Linux,您需要为某些文件添加执行权限。 Run the command: chmod a+rx nativeMessaging/host/install_host.sh nativeMessaging/host/native-messaging-example-host nativeMessaging/host/uninstall_host.sh运行命令: chmod a+rx nativeMessaging/host/install_host.sh nativeMessaging/host/native-messaging-example-host nativeMessaging/host/uninstall_host.sh
    2. For OS X you'll need to fix some bugs in nativeMessaging/host/install_host.sh and nativeMessaging/host/uninstall_host.sh .对于 OS X,您需要修复nativeMessaging/host/install_host.shnativeMessaging/host/uninstall_host.sh一些错误。 See below for the corrected scripts.有关更正后的脚本,请参见下文。
    3. For OS X, Linux and Windows follow the instructions in nativeMessaging/README.txt对于 OS X、Linux 和 Windows,请按照nativeMessaging/README.txt的说明进行nativeMessaging/README.txt
  4. Run the Chrome extension运行 Chrome 扩展程序
    1. In Chrome enter chrome://apps/ in the address bar在 Chrome 中,在地址栏中输入chrome://apps/
    2. Click on the Native Messaging Example app icon单击本机消息传递示例应用程序图标
    3. After the app loads you should see a single button named “Connect.”应用加载后,您应该会看到一个名为“连接”的按钮。 Click that button and you should see the native messaging host application launch automatically.单击该按钮,您应该会看到本机消息传递主机应用程序自动启动。

Corrected nativeMessaging/host/install_host.sh更正了nativeMessaging/host/install_host.sh

#!/bin/sh
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

set -e

DIR="$( cd "$( dirname "$0" )" && pwd )"
if [ $(uname -s) == 'Darwin' ]; then
  if [ "$(whoami)" == "root" ]; then
    TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts"
  else
    TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
  fi
else
  if [ "$(whoami)" == "root" ]; then
    TARGET_DIR="/etc/opt/chrome/native-messaging-hosts"
  else
    TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
  fi
fi

HOST_NAME=com.google.chrome.example.echo

# Create directory to store native messaging host.
mkdir -p "$TARGET_DIR"

# Copy native messaging host manifest.
cp "$DIR/$HOST_NAME.json" "$TARGET_DIR"

# Update host path in the manifest.
HOST_PATH="$DIR/native-messaging-example-host"
ESCAPED_HOST_PATH=${HOST_PATH////\\/}
sed -i -e "s/HOST_PATH/$ESCAPED_HOST_PATH/" "$TARGET_DIR/$HOST_NAME.json"

# Set permissions for the manifest so that all users can read it.
chmod o+r "$TARGET_DIR/$HOST_NAME.json"

echo Native messaging host $HOST_NAME has been installed.

Corrected nativeMessaging/host/uninstall_host.sh更正了nativeMessaging/host/uninstall_host.sh

#!/bin/sh
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

set -e

if [ $(uname -s) == 'Darwin' ]; then
  if [ "$(whoami)" == "root" ]; then
    TARGET_DIR="/Library/Google/Chrome/NativeMessagingHosts"
  else
    TARGET_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
  fi
else
  if [ "$(whoami)" == "root" ]; then
    TARGET_DIR="/etc/opt/chrome/native-messaging-hosts"
  else
    TARGET_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
  fi
fi

HOST_NAME=com.google.chrome.example.echo
rm "$TARGET_DIR/com.google.chrome.example.echo.json"
echo Native messaging host $HOST_NAME has been uninstalled.

I would like to provide a python 3 version of the script to replace native-messaging-example-host .我想提供一个 python 3 版本的脚本来替换native-messaging-example-host It is tested with Chrome v86 and works as expected.它已使用 Chrome v86 进行测试并按预期工作。 Note that python kernel crashes when tkinter window is closed - this is because of binary data exchange inside threading which causes thread to be hard locked (more info here ).请注意,当 tkinter 窗口关闭时,python 内核会崩溃 - 这是因为线程内部的二进制数据交换导致线程被硬锁定(更多信息在这里)。 I added a command exit to be send from chrome app to stop thread's waiting for another stdin.我添加了一个从 chrome 应用程序发送的命令退出,以停止线程等待另一个标准输入。 After receiving it, python won't crash on exit.收到后,python 不会在退出时崩溃。

Python 3 version (tested with 3.7.4): Python 3 版本(使用 3.7.4 测试):

# A simple native messaging host. Shows a Tkinter dialog with incoming messages
# that also allows to send message back to the webapp.

import struct
import sys
import threading
import queue as Queue

try:
  import tkinter as Tkinter
  import tkinter.messagebox
except ImportError:
  Tkinter = None

# On Windows, the default I/O mode is O_TEXT. Set this to O_BINARY
# to avoid unwanted modifications of the input/output streams.
if sys.platform == "win32":
  import os, msvcrt
  msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
  msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

# Helper function that sends a message to the webapp.
def send_message(message):
   # Write message size.
  sys.stdout.buffer.write(struct.pack('I', len(message)))
  # Write the message itself.
  sys.stdout.write(message)
  sys.stdout.flush()

# Thread that reads messages from the webapp.
def read_thread_func(queue):
  message_number = 0
  while 1:
    # Read the message length (first 4 bytes).
    text_length_bytes = sys.stdin.buffer.read(4)

    if len(text_length_bytes) == 0:
      if queue:
        queue.put(None)
      sys.exit(0)

    # Unpack message length as 4 byte integer.
    text_length = struct.unpack('@I', text_length_bytes)[0]

    # Read the text (JSON object) of the message.
    text = sys.stdin.buffer.read(text_length).decode('utf-8')

    if text == '{"text":"exit"}':
      break

    if queue:
      queue.put(text)
    else:
      # In headless mode just send an echo message back.
      send_message('{"echo": %s}' % text)

if Tkinter:
  class NativeMessagingWindow(tkinter.Frame):
    def __init__(self, queue):
      self.queue = queue

      tkinter.Frame.__init__(self)
      self.pack()

      self.text = tkinter.Text(self)
      self.text.grid(row=0, column=0, padx=10, pady=10, columnspan=2)
      self.text.config(state=tkinter.DISABLED, height=10, width=40)

      self.messageContent = tkinter.StringVar()
      self.sendEntry = tkinter.Entry(self, textvariable=self.messageContent)
      self.sendEntry.grid(row=1, column=0, padx=10, pady=10)

      self.sendButton = tkinter.Button(self, text="Send", command=self.onSend)
      self.sendButton.grid(row=1, column=1, padx=10, pady=10)

      self.after(100, self.processMessages)

    def processMessages(self):
      while not self.queue.empty():
        message = self.queue.get_nowait()
        if message == None:
          self.quit()
          return
        self.log("Received %s" % message)

      self.after(100, self.processMessages)

    def onSend(self):
      text = '{"text": "' + self.messageContent.get() + '"}'
      self.log('Sending %s' % text)
      try:
        send_message(text)
      except IOError:
        tkinter.messagebox.showinfo('Native Messaging Example',
                              'Failed to send message.')
        sys.exit(1)

    def log(self, message):
      self.text.config(state=tkinter.NORMAL)
      self.text.insert(tkinter.END, message + "\n")
      self.text.config(state=tkinter.DISABLED)


def Main():
  if not Tkinter:
    send_message('"Tkinter python module wasn\'t found. Running in headless ' +
                 'mode. Please consider installing Tkinter."')
    read_thread_func(None)
    sys.exit(0)

  queue = Queue.Queue()

  main_window = NativeMessagingWindow(queue)
  main_window.master.title('Native Messaging Example')

  thread = threading.Thread(target=read_thread_func, args=(queue,))
  thread.daemon = True
  thread.start()

  main_window.mainloop()

  sys.exit(0)


if __name__ == '__main__':
  Main()

Disclaimer: I used 2to3 utility for initial conversion to python 3. I also adopted changes from a webextensions (firefox) version of the nativeMessage API example (it is simplified and not using tkinter gui).免责声明:我使用2to3实用程序初始转换为 python 3。我还采用了webextensions (firefox) 版本的 nativeMessage API 示例的更改(它已简化且不使用 tkinter gui)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM