使用 Xamarin Mac、C# 的跨浏览器、跨平台本机消息传递

Kha*_*ech 7 macos chrome-native-messaging xamarin.forms

我尝试重新创建示例以使用 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

        host = new ExtendedHost();


        host.Listen();
Run Code Online (Sandbox Code Playgroud)

请注意,我正在为 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 应该启动该进程:

从 Chrome 扩展程序与 MacOSX 应用程序交谈

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

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

  • 一种获取应用程序路径的方法,Chrome 可以将其与其原生消息传递 API 一起使用
  • 以编程方式获取此路径的解决方案,如果可能,它可以在所有平台上工作,如Console.WriteLine(Path.Combine(Assembly.GetExecutingAssembly().Location)); 没有做的伎俩。

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

提前致谢!

编辑:

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

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

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

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

任何想法表示赞赏!谢谢

Kha*_*ech 0

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

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

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

我在 Stack Overflow 上偶然发现了这个线程,它帮助确认了(Chrome 应用程序无法与 Windows 上的本机主机通信)。

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

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

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

编辑

几天前我设法让它工作。我修改了代码,使其无需 while 循环即可工作,因为 StreamReader 读取 stdin 直至结束,因此不会请求 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();
    }
Run Code Online (Sandbox Code Playgroud)