zoukankan      html  css  js  c++  java
  • UWP

    App Service 是一种背景工作运行的服务,提供给其他Apps 使用就像Web Service。它本身无使用介面(UI-less),允许Apps 在同一个设备被引用,甚至Windows 10 1607 开始允许remote devices 使用它。

    [ 重点观念 ]

    Windows 10, version 1607 开始, App Service 支持新模式:
    可以与host App 运行在相同的process;(一般属于Background Task 执行在不同的process)
    支援从App呼叫Remote Devices中的App Service;
    想要App Service每次被启动都是新的instance,在Package.appmanifest加入宣告;uap4:SupportsMultipleInstances="true";但需要Windows 10, version 15063以上才支援
    App Service 的生命周期,因为Process 有所不同:
    后台任务(进程外):
    当它被建立时会进入Run(),随着Run()执行完毕就会被结束
    它被启动后,基本会维持活着约有30秒,可搭配呼叫GetDeferral()多加5秒来完成任务
    In-app process model:生命周期则跟着呼叫者一起共存,让两个Apps 之间更容易沟通,不用再分成两份code 来串联与维护
    App Service 的OnTaskCancel() 被触发有几个原因:
    Client app释放AppServiceConnection
    Client app 被 suspended
    系统关闭或睡眠
    系统执行该Task 用过高的资源
    大略有概念之后,接着介绍怎么做基本的App Service (two process),再介绍怎么整合到App 的process 里面;

    • 如何建立App service 并使用它:

    分成两个App 做说明:一个是拥有App Service 的Host App;一个是使用App Service 的Client App;

    1建立一个Windows Runtime Component,并且加入AppServiceConnection 的处理逻辑:

    public sealed class ServiceTask : IBackgroundTask
    {
        private BackgroundTaskDeferral backgroundTaskDeferral;
        private AppServiceConnection appServiceconnection;
    
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            // Background Task 被建立時,取得 deferral 拉長生命周期,避免被結束
            this.backgroundTaskDeferral = taskInstance.GetDeferral();
    
            // 一定要註冊處理 Canceled 事件來正確釋放用到的資源
            taskInstance.Canceled += OnTaskCanceled;
    
            // 根據被啓動的 Instance 類型,建立 App Service Connection,並註冊 Request 事件.
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            appServiceconnection = details.AppServiceConnection;
            appServiceconnection.RequestReceived += OnRequestReceived;
        }
    
        private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            if (this.backgroundTaskDeferral != null)
            {
                // Complete the service deferral.
                this.backgroundTaskDeferral.Complete();
            }
        }
    
        private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            // 當 App Service 收到請求時,該 method 就會被觸發
            // 先要求取得 取得 deferral 拉長生命周期
            var requestDeferral = args.GetDeferral();
    
            ValueSet message = args.Request.Message;
            string cmd = message["cmd"] as string;
            string id = message["id"] as string;
    
            ValueSet responseMsg = new ValueSet();
    
            switch (cmd)
            {
                case "Query":
                    responseMsg.Add("id", "123456");
                    responseMsg.Add("name", "pou");
                    responseMsg.Add("status", "OK");
                    var result = await args.Request.SendResponseAsync(responseMsg);
                    break;
            }
    
            requestDeferral.Complete();
        }
    }

    2在Host App 的Package.manifest 宣告App Service 并设定Entry Point,记得把App Service 的专案加入到Host App 的专案参考:

    <Applications>
        <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="ServiceHost.App">
            <uap:VisualElements  />
            <Extensions>
                <uap:Extension Category="windows.appService" EntryPoint="MyAppService.ServiceTask">
                    <uap:AppService Name="com.pou.MyApService" />
                </uap:Extension>
            </Extensions>
        </Application>
    </Applications>

    加入专案参考这样在Host App被安装的时候才会一并加入App Service。利用Windows.ApplicationModel.Package.Current.Id.FamilyName在Host App拿到package family name,准备交给Client App。
    3在 Client App 利用 AppServiceConnection 呼叫 App Service:

    private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        AppServiceConnection connection = new AppServiceConnection();
        connection.AppServiceName = "com.pou.MyApService";
        connection.PackageFamilyName = "f9842749-e4c8-4c15-bac8-bc018db1b2ea_s1mb6h805jdtj";
    
        var status = await connection.OpenAsync();
    
        if (status != AppServiceConnectionStatus.Success)
        {
            Debug.WriteLine("Failed to connect");
            return;
        }
    
        var message = new ValueSet();
        message.Add("cmd", "Query");
        message.Add("id", "1234");
    
        AppServiceResponse response = await connection.SendMessageAsync(message);
        string result = "";
    
        if (response.Status == AppServiceResponseStatus.Success)
        {
            if (response.Message["status"] as string == "OK")
            {
                result = response.Message["name"] as string;
            }
        }
    }

    上面介绍的App Service 是比较一般的用法, 把App Service 放到Background Task 的架构。

    • 把App Service 合并到App.xaml.cs 里面,作为Same Process:

    AppServiceConnection允许其他App叫醒在背景中自己的App并传入指令。它与上方的out-of-process最大不同有两个:

    1Package.manifest 宣告 <uap:Extension Category="windows.appService"> 不用 Entry Point,改用 OnBackgroundActivated()。

    <Package>
      <Applications>
          <Application>
              <Extensions>
                  <uap:Extension Category="windows.appService">
                      <uap:AppService Name="com.pou.MyApService" />
                  </uap:Extension>
              </Extensions>
          </Application>
      </Applications>

    2在App.xaml.cs加入OnBackgroundActivated()的处理逻辑。

    sealed partial class App : Application
    {
        private AppServiceConnection appServiceConnection;
        private BackgroundTaskDeferral appServiceDeferral;
    
        protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
        {
            base.OnBackgroundActivated(args);
    
            AppServiceTriggerDetails appService = args.TaskInstance.TriggerDetails as AppServiceTriggerDetails;
    
            if (appService ==null)
            {
                return;
            }
    
            args.TaskInstance.Canceled += OnAppServicesCanceled;
    
            // appServiceDeferral 與 appServiceConnection 需要變成公用變數
            // 因爲其他時間需要用到,已維持連線的一致性
            appServiceDeferral = args.TaskInstance.GetDeferral();
            appServiceConnection = appService.AppServiceConnection;
    
            appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived;
            appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
        }
    
        private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            // 當 App Service 收到請求時,該 method 就會被觸發
    
            // 先要求取得 取得 deferral 拉長生命周期
            var requestDeferral = args.GetDeferral();
    
            ValueSet message = args.Request.Message;
    
            string cmd = message["cmd"] as string;
            string id = message["id"] as string;
    
            ValueSet responseMsg = new ValueSet();
    
            switch (cmd)
            {
                case "Query":
                    responseMsg.Add("id", "123456");
                    responseMsg.Add("name", "pou");
                    responseMsg.Add("status", "OK");
                    var result = await args.Request.SendResponseAsync(responseMsg);
                    break;
            }
    
            requestDeferral.Complete();
        }
    
        private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
        {
            appServiceDeferral?.Complete();
            appServiceConnection?.Dispose();
        }
    
        private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            appServiceDeferral?.Complete();
            appServiceConnection?.Dispose();
        }
    }

    要支援in-process model就是这样简单,而且让原本的App Service逻辑回到App本身,让逻辑更干净。OnBackgroundActivated()负责处理App Service的启用,并储存Deferral保持服务的生命周期,详细可以参考Windows 10通用Windows平台(UWP) app周期。

  • 相关阅读:
    Oracle TRCA 工具 说明
    Oracle TTS ORA39322: Cannot use transportable tablespace with different timezone version 说明
    Oracle 传输表空间(Transportable Tablespaces) 示例(二) 跨操作系统迁移表空间(endianness格式不同)
    易于在各手机平台移植的设计(转)
    Symbian 学习资源
    项目经理修炼手册
    ZIP 算法详解 (转!)
    google Android OS 学习资源、资料和笔记汇总(要看的)
    小白兔的求职遭遇
    数据结构和算法学习笔记(1)
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14204597.html
Copyright © 2011-2022 走看看