[技術探討] WIN10 APP Service初探

WIN10 APP Service

自Windows 10正式推出後,不僅帶給使用著一個全新的體驗,對我們來開發人員來說,更關注的則是Windows APP的進化。整體而言,Windows 10 APP(以下簡稱為WIN10 APP) 還是延續著Windows 8.1 APP(以下簡稱為WIN8.1 APP)的開發架構,更將整合手持裝置與PC端APP統整為通用應用程式,並增加且擴充更多的函式庫,因此原本有WIN8.1 APP開發經驗的人員不會覺得太陌生。本篇即針對當中一項新的資料傳遞模型-App Service做初步介紹及示範,而在提到App Service前可以追溯到App與App之間的溝通,看看這個概念如何從WIN8.1APP演化而來。

WIN8.1 APP TO APP

在WIN 8.1 APP的開發中,有時會需要啟動其他APP或是執行某個檔案,通常會使用LaunchUriAsync搭配URI/Protocol的方式來達到呼叫其他APP,或是以LaunchFileAsync來開啟檔案(可搭配FileExtension)。

Launcher.LaunchUriAsync(new Uri(“sampleapp:?ID=aea6“));

Launcher.LaunchFileAsync(file);

另外一種情境是, APP之間想要做資料傳遞,在WIN8.1也可以做到,也就是分享的概念,中間資料是透過DataPackage來做為傳遞,只要APP中有支援資料的分享,就可以接收來源APP傳遞的資料,是一種單向的資料分享。

WIN 10 APP TO APP

即使演進到了WIN10 APP的開發工作,Launcher依然是叫用其他應用程式或檔案的不二方法,同樣也透過URI/Protocol,但呼叫實作上略有不同,例如想要啟動某個APP時,可以這樣做:

var options = new LauncherOptions();

options.TargetApplicationPackageFamilyName =  “24919.InstapaperIt”;

var launchUri = new Uri(“instapaper:?AddUrl=http%3A%2F%2Fbing.com”);

await Launcher.LaunchUriAsync(launchUri, options);

 

這當中透露出一個訊息,WIN10 APP將PackageFamilyName夠作為APP的唯一的識別名稱,這樣可以很正確而直接的呼叫目標APP,實務上可以透過APP註冊至Store中以取得。

另一個好處是,當前裝置若未安裝此目標APP時,會藉由Store並以該呼叫目標APP之PackageFamilyName作為識別並將使用者導覽至該APP之安裝畫面。

另外在APP間檔案的傳遞上,WIN10也有了新的設計方式-FILE TOKEN,這樣的方式讓我們僅需要告知目標APP檔案的FILE TOKEN,目標APP就能夠透過TOKEN直接取得該檔案,而不必大費周章地想辦法傳遞整個檔案,畢竟都是在同一台裝置上的資源,像是這樣:

var token = SharedStorageAccessManager.AddFile (gpxFile);

ValueSet inputData = new ValueSet();

inputData.Add(“Token”, token);

var launchUri = new Uri(“instapaper:?AddUrl=http%3A%2F%2Fbing.com”);

await Launcher.LaunchUriAsync(launchUri, options, inputData);

APP SERVICE

最後進入這次的主題-APP SERVICE,雖然我們在WIN8.1APP中已經可以達到訊息的傳遞,但往往有時我們需要的不只是單向傳遞資料或命令,因此開始衍伸了請別的APP來處理工作的需要,APP SERVICE便是處理這類問題的最佳選擇。

有過開發WEB經驗的人,相信對WEB SERVICE不會陌生,因為往往有需要透過傳遞要求與資料至WEB SERVICE並將結果送回呼叫端。APP SERVICE概念即如同WEB SERVICE,只是APP SERVICE是執行於裝置上,提供裝置中的其他APP進行呼叫。

SERVICE SIDE

APP SERVICE本身也是一個APP,因此也具有前端的特性,但一定會包含一個背景程式來執行任務,只要收到來自其他APP(CLIENT)的連線請求,便會啟動這個背景程式來完成工作。

 

首先我們要將APP宣告為APP SERVICE,並且設定連線呼叫成功後程式的進入點,以及指定APP SERVICE的名稱。

以上可至該專案的package.appxmanifest進行設定:

<Applications>
<Application Id=App

<Extensions>
<uap:Extension Category=windows.appService
EntryPoint=AppServicesDemoTask.MyBackgroundTask>
<uap:AppService Name=”MyAppService/>
</uap:Extension>
</Extensions>
</Application>
</Applications>

 

然後方才指定之進入點的類別會繼承IBackgrundTask介面並且實作,此時我們會先宣告相關物件及事件如下:

BackgroundTaskDeferral

IBackgroundTaskInstance.Canceled (任務中止)

AppServiceConnection.RequestReceived (接收連線請求)

public sealed class MyBackgroundTask : IBackgroundTask

{

private BackgroundTaskDeferral backgroundTaskDeferral;

private AppServiceConnection appServiceconnection;

 

public void Run(IBackgroundTaskInstance taskInstance)

{

this.backgroundTaskDeferral = taskInstance.GetDeferral();

taskInstance.Canceled += OnTaskCanceled;

var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;

appServiceconnection = details.AppServiceConnection;

appServiceconnection.RequestReceived += OnRequestReceived;

RequestReceived事件中可進行接收到資料後的處理,並透過AppServiceRequestReceivedEventArgs.Request.Message取得呼叫端送來的資料,連線中無論接收或是傳回的資料,都是使用ValueSet封裝資料並來進行交換, AppServiceRequestReceivedEventArgs.Request.SendResponseAsync()則是最後負責將結果(ValueSet)傳回至呼叫端,至此以完成一次APP Service的呼叫。

private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)

{

var messageDeferral = args.GetDeferral();

ValueSet message = args.Request.Message;

ValueSet returnData = new ValueSet();

 

string command = message[“Command”] as string;

switch (command)

{

case ” Command1″:

{

returnData.Add(“Result”, “ResultA”);

returnData.Add(“Status”, “OK”);

break;

}

case ” Command2″:

{

returnData.Add(“Result”, “ResultB”);

returnData.Add(“Status”, “OK”);

break;

}

}

await args.Request.SendResponseAsync(returnData);

messageDeferral.Complete();

}

CLIENT SIDE

接著介紹CLIENT端APP的呼叫方式,首先建立連線是首要工作,為避免所有SERVICE都能任意呼叫,前面介紹過一項很重要的參數設定,也就是PackageFamilyName,在這時候會需要派上用場,並且搭配在APP Service設定之AppServiceName,指定於AppServiceConnection物件PackageFamilyName與AppServiceName之屬性,然後使用OpenAsync()開啟與APP SERVICE間的連線,並以該方法回傳之AppServiceConnectionStatus來判斷連線狀態是否成功。  再來當連線建立後,當然就是要把我們要傳送至APP SERVICE的資料打包並送出,這邊當然還是以Key-Value的組合加入至ValueSet中。並以SendMessageAsync()將資料送出並得到APP SERVICE回傳之結果。

private AppServiceConnection inventoryService;

if (this.inventoryService == null)

{

this.inventoryService = new AppServiceConnection();

this.inventoryService.AppServiceName = “MyAppService”;

this.inventoryService.PackageFamilyName = “(APP Service’s PackageFamilyName)”;

 

var status = await this.inventoryService.OpenAsync();

if (status != AppServiceConnectionStatus.Success)

{

return;

}

}

 

var message = new ValueSet();

message.Add(“Command”, “Commamd1”);

AppServiceResponse response = await this.inventoryService.SendMessageAsync(message);

 

string result = “”;

if (response.Status == AppServiceResponseStatus.Success)

{

if (response.Message[“Status”] as string == “OK”)

{

result = response.Message[“Result”] as string;

}

}

以上就是App Service端與App Client端的運行結構與呼叫方式,基本在使用上並不困難。並且我們已經透過AppServiceName與PackageFamilyName來限制呼叫端,以至於不會讓任何App都能自由的呼叫App Service,不過我們能在App Service中設定所謂白名單,透過指定App的PackageFamilyName,來過濾特定的App能夠呼叫並且建立連線。

 

最後提供一個開發時對於App Service的偵錯技巧,先到App Service的專案屬性中,在偵錯標籤中勾選「不啟動,但在我的程式碼啟動時進行偵錯」,接著於背景任務中設定中斷點,然後對該專案選擇偵錯 > 開始新執行個體。之後啟動部屬在裝置上的Client App然後執行App Service的呼叫,便可進入到Service設定的中斷點以進行偵錯。

 

伴隨Windows 10的誕生,催生了詮力科技PowerNAS Windows版本,因此在未來Windows App應用的重要性更顯得重要,如本篇介紹之App Service,即可提供一個整合性的NAS App服務端,提供其他PowerNAS Client App呼叫並且取得資料甚至執行命令。讓原先App的應用不再只是單打獨鬥,而更加強了App間的互動與協調性。

 

Reference:

https://msdn.microsoft.com/zh-tw/library/windows/apps/mt187314.aspx

http://www.microsoftvirtualacademy.com/training-courses/a-developers-guide-to-windows-10


發佈留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料