【问题标题】:Cross-Browser, Cross-Platform native messaging using Xamarin Mac, C#使用 Xamarin Mac、C# 的跨浏览器、跨平台本机消息传递
【发布时间】:2020-02-10 21:01:47
【问题描述】:

我尝试重新创建示例以使用我将用作所有其他浏览器的主干的 chrome 扩展连接到我的 Xamarin Mac 应用程序,但它没有与以下错误一起工作:

与本机消息传递主机通信时出错。

文档在纸面上看起来很简单,但在现实生活中并不是那么简单。

这是我的阅读和聆听功能(那里有很好的例子,https://github.com/anewtonlevey/NativeMessaging):

    public void Listen()
    {

        JObject data;
        while ((data = Read()) != null)
        {
            ProcessReceivedMessage(data);
        }

    }




    private JObject Read()
    {
        try
        {
            Stream stdin = Console.OpenStandardInput();


            byte[] lengthBytes = new byte[4];
            stdin.Read(lengthBytes, 0, 4);


            var buffer = new char[BitConverter.ToInt32(lengthBytes, 0)];

            using (var reader = new StreamReader(stdin)) while (reader.Peek() >= 0) reader.Read(buffer, 0, buffer.Length);
            return JsonConvert.DeserializeObject<JObject>(new string(buffer));


        }
        catch (Exception e)
        {
            Console.WriteLine("Read error: {0}", e);
            return null;
        }
    }

在我的 main 函数中,我使用以下方法调用它们:

        host = new ExtendedHost();


        host.Listen();

请注意,我正在为 macOS 应用程序使用来自 Xamarin 表单的本机消息传递,从我的角度来看,这可能是字节序,如下文档所示:

与本机消息传递主机通信时出错:

https://developer.chrome.com/extensions/nativeMessaging#native-messaging-host-protocol

当我从 Web 扩展发送消息时,我的 C# 应用程序的另一个窗口似乎想要打开,这意味着错误似乎发生在阅读步骤。

帮助非常感谢。

谢谢。

编辑:

我建议使用字节顺序,因为文档建议响应也应该是正确的,否则会导致整个过程损坏,正如 本机消息传递协议文档 中所建议的那样,但这肯定不是问题因为我应该仍然能够解析发送的数据:

https://developer.chrome.com/apps/nativeMessaging#native-messaging-host-protocol

我看到响应与它有关,并且用于发送消息的函数(因为有人建议响应错误可能导致整体错误)会导致问题,或者 Console.StandardInput()不像建议的那样工作,但我不这么认为。

我的想法是尝试附加到正在运行的应用程序会导致问题,因为我使用 ps aux | grep app_name,然后将路径放在主机文件中。

这是协议中的提及:

本机消息传递协议 Chrome 在单独的进程中启动每个本机消息传递主机,并使用标准输入 (stdin) 和标准输出 (stdout) 与其通信。

我还在另一篇帖子中看到了 Xan 的回答,即原生消息无法附加到正在运行的进程,Chrome 应该启动该进程:

Talk to MacOSX app from Chrome Extension

不要忘记我在调试模式下将本机消息传递 API 与 Xamarin macOS 一起使用,并且我的应用程序是 macOS 应用程序。

欢迎提供有关该主题的更多信息,例如:

  • 一种获取应用路径的方法,Chrome 可以通过其原生消息传递 API 使用该路径
  • 以编程方式获取此路径的解决方案,如果可能,该解决方案适用于所有平台,因为 Console.WriteLine(Path.Combine(Assembly.GetExecutingAssembly().Location)); 没有做到把戏。

当然,如果您认为这是导致问题的原因。

提前致谢!

编辑:

将输出发送到 stderr 时,出现以下错误:

读取错误:System.NotSupportedException:流不支持读取 在 /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/src/Xamarin.Mac 中的 System.IO.FileStream.Read(System.Byte[] 数组,System.Int32 偏移量,System.Int32 计数)[0x0002e] /mcs/class/corlib/System.IO/FileStream.cs:493

可能是 Console.OpenStandardInput 不能跨平台工作吗? 如果是这样,那么解析标准输入的另一种方法可能是什么,因为我看到管道可以工作,但我不确定它们是否可以以跨平台方式部署。

阅读时我没有收到任何错误或输出,只有在应用程序启动时出现上述错误。 对我来说,OpenStandardInput 似乎是罪魁祸首。

任何想法表示赞赏!谢谢

【问题讨论】:

  • 我没有在 .NET 中尝试过,但我使用 C++ 完成了此操作,该应用程序必须是 Windows 上的控制台应用程序才能使标准输入正常工作。我尝试使用 GUI(隐藏)应用程序执行此操作,但 stdin 无法从那里工作。将您的应用程序设为控制台应用程序后,它可能会起作用吗?
  • 嗨。感谢您抽出宝贵时间。我已经指出了可执行文件,它也在 .NET 中从命令运行。我正在使用 Xamarin macOS,并为 macOS 制作了一个应用程序。问题是我可以运行执行 bash 脚本的应用程序,但是当我尝试运行它时,它不起作用。这非常烦人。昨天它工作了,但我在消息传递方面遇到了一些错误。我的 bash 脚本确实有效,并从命令行启动了一个应用程序。 Mozilla 似乎无法通过 bash 脚本访问它,并抛出“尝试在断开连接的端口上发布消息”
  • 当我直接输入可执行文件的路径时,例如 /Application/Appname.app/Contents/MacOS/Appname,我收到以下错误。本机应用程序尝试发送 543451477 字节的消息,超过了 1048576 字节的限制。请注意,我在 stin 和 stdout 上没有看到任何内容。

标签: macos xamarin.forms chrome-native-messaging


【解决方案1】:

基本上,从扩展发送的前 32 位对应于消息长度,按本机顺序。

由于前 32 位是 int 类型,并且我尝试解析 JSON 对象,因此引发了 与本机消息传递主机通信时出错。该文档提到该问题存在于损坏的本机消息传递协议中。

最糟糕的是我在Python示例中看到了它,但认为这是由做它的程序员实现的。

我偶然发现了 Stack Overflow 上的这个帖子,这有助于确认 (Chrome App fails to communicate with native host on windows)。

要以更详细的方式调试 Chrome,请在命令行中使用 --enable-logging=stderr --v=1 启动 Chrome,所有 stderr 都将在那里输出。 p>

文档中提到了它,但使用 C# 在这里和那里找到的示例不包括它们。

如果我有时间,我将通过编辑此答案来确认这是问题所在,并提供代码以使其在 Visual Studio for macOS 上运行。

编辑

几天前我设法让这个工作。我修改了代码,使其在没有 while 循环的情况下工作,因为 StreamReader 读取标准输入直到结束,因此不请求 while 循环(这导致我以前的代码挂起)。 SendMessage 方法也与其他示例中的其他方法不同。行数更少,而且工作得很好。

我的工作示例:

public void Listen()
{


    JObject data;

    //while ((data = Read()) != null)
    //{
    //    ProcessReceivedMessage(data);
    //}

    if((data = Read()) != null)
    {
        string message = ProcessReceivedMessage(data);
        SendMessage(message);
    }
}


    private JObject Read()
    {

        Stream stdin = Console.OpenStandardInput();

        byte[] lengthBytes = new byte[4];
        stdin.Read(lengthBytes, 0, lengthBytes.Length);

        char[] buffer = new char[BitConverter.ToInt32(lengthBytes, 0)];

        var reader = new StreamReader(stdin);
        //int messageLength =
        reader.Read(buffer, 0, buffer.Length);

        return JsonConvert.DeserializeObject<JObject>(new string(buffer));
    }





    public void SendMessage(JToken data)
    {
        var bytes = Encoding.UTF8.GetBytes(data.ToString(Formatting.None));
        var lengthBytes = BitConverter.GetBytes(bytes.Length);
        var stdout = Console.OpenStandardOutput();

        stdout.Write(lengthBytes, 0, 4);
        stdout.Write(bytes, 0, bytes.Length);
        stdout.Flush();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-20
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 2011-10-26
    • 2012-07-31
    • 1970-01-01
    相关资源
    最近更新 更多