MS Edge:进程内本地消息传递

MS Edge: In-process native messaging

在阅读 this documentation 的同时,我正在尝试为本机消息实现 Edge-Browser 扩展,以使用 Windows.System.Launcher.LaunchFileAsync.

调用标准桌面应用程序

我明确不会尝试使用后台任务通过 AppService 实现扩展,因为我需要确保 LaunchFileAsync 正在主 UI-Thread 上执行。因此,我想直接在主应用程序组件上使用 OnBackgroundActiviated

上面提到的文档说,将基于应用服务的扩展转变为进程内扩展是通过从包清单中的应用程序标签中删除 "EntryPoint" 属性来完成的。然而,按照这个描述,Visual Studio 2017 抛出扩展无法注册的错误(DEP0700, 0x80073CF6 windows.appService: Element not found).

向 AppService 标签添加 EntryPoint 属性会导致此错误消息消失,但我无法触发 OnBackgroundActivated

这是我的包裹清单:

    <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp">
  <Identity Name="0d2a700c-9f88-4445-8250-a3e82aedb1d2" Publisher="CN=Sebastian Blessing" Version="1.0.0.0" />
  <mp:PhoneIdentity PhoneProductId="0d2a700c-9f88-4445-8250-a3e82aedb1d2" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
  <Properties>
    <DisplayName>edgeextension</DisplayName>
    <PublisherDisplayName>Sebastian Blessing</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
  </Dependencies>
  <Resources>
    <Resource Language="x-generate" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="$targetnametoken$.exe">
      <uap:VisualElements AppListEntry="none" DisplayName="edgeextension" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="abs.mira.edgeextension" BackgroundColor="transparent">
        <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
        </uap:DefaultTile>
        <uap:SplashScreen Image="Assets\SplashScreen.png" />
      </uap:VisualElements>
      <Extensions>
        <uap:Extension Category="windows.appService">
          <uap:AppService Name="EdgeExtensionRuntime" />
        </uap:Extension>
        <uap3:Extension Category="windows.appExtension">
          <uap3:AppExtension Name="com.microsoft.edge.extension" Id="EdgeExtensionRuntime" PublicFolder="Extension" DisplayName="ms-resource:DisplayName">
            <uap3:Properties>
              <Capabilities>
                <Capability Name="browserStorage" />
              </Capabilities>
            </uap3:Properties>
          </uap3:AppExtension>
        </uap3:Extension>
      </Extensions>
    </Application>
  </Applications>
  <Capabilities>
    <Capability Name="internetClient" />
    <Capability Name="internetClientServer" />
  </Capabilities>
</Package>

你能指出这个清单文件的潜在问题吗?应用程序 Class 在文件 App.xaml.cs 中实现为 App 并且还实现了 OnBackgroundActivated,这里是代码:

using System;
using Windows.ApplicationModel;
using Windows.Foundation.Collections;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Newtonsoft.Json;

namespace edgeextension
{
    sealed partial class App : Application
    {
        private BackgroundTaskDeferral appServiceDeferral = null;
        private AppServiceConnection appServiceConnection;

        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
        {
            base.OnBackgroundActivated(args);
            IBackgroundTaskInstance taskInstance = args.TaskInstance;
            AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            appServiceDeferral = taskInstance.GetDeferral();
            taskInstance.Canceled += OnAppServicesCanceled;
            appServiceConnection = appService.AppServiceConnection;
            appServiceConnection.RequestReceived += OnAppServiceRequestReceived;
            appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
        }

        private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            AppServiceDeferral messageDeferral = args.GetDeferral();

            try
            {
                //Has to run on the UI-Thread !!                       
                await Windows.System.Launcher.LaunchFileAsync(...);
            }
            finally
            {
                messageDeferral.Complete();
            }
        }

        private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            this.appServiceDeferral.Complete();

        }

        private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
        {
            this.appServiceDeferral.Complete();
        }

        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO
            //deferral.Complete();
        }
    }
}

在后台脚本中,我使用与清单文件中相同的名称 EdgeExtensionRuntime 连接到扩展:

// Store port for native messaging connections
var port = null;

browser.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        if (port === null) {
            port = browser.runtime.connectNative("EdgeExtensionRuntime");
            port.onDisconnect.addListener(onDisconnected);

            port.onMessage.addListener(function (response) { console.log(response); });
        }

        try {
            port.postMessage(request.message);
        } catch (e) {
            console.log(e);
        }


        return true;
    });

function onDisconnected() {
    console.log("disconnect!");
    port = null;
}

显然,这似乎不起作用(即使在扩展标签中添加了 EntryPoint),因为我确实在扩展背景页面日志中立即得到了 "disconnect"。

我看不出问题出在哪里,MS 文档也很差。

导致 OnBackgroundActivated 触发的解决方案是在程序包清单中添加以下协议信息:

<uap:Extension Category="windows.protocol">
  <uap:Protocol Name="msghost1" />
</uap:Extension>

但是,现在将应用程序转换为进程内插件并不能解决主线程上 Windows.System.Launcher.LaunchFileAsync(IStorageFile) 到 运行 的问题。到目前为止,此调用仅在调试模式下成功(附加了调试器)。将post针对此问题单独提问。