뛰어난 라이브 타일 환경 만들기(2부)

Windows 8 앱 개발자 블로그

Windows 8 엔지니어링 팀에서 제공하는 Windows 8용 Metro 스타일 앱 개발의 이해

뛰어난 라이브 타일 환경 만들기(2부)

  • Comments 0

이 글의 1부에서 타일 업데이트를 디자인하고 라이브 타일에 표시할 콘텐츠에 적합한 템플릿을 선택하는 방법에 대해 배웠습니다. 와이드 기본 타일로 앱을 설정했으니 이제 타일을 업데이트할 준비가 다 되었습니다. 지금부터는 코드를 직접 살펴보도록 하겠습니다. 우선 웹 서비스 코드가 어떻게 되어 있는지를 비롯해 Contoso Food Trucks 앱 타일에 폴링을 설정하는 방법부터 알아보겠습니다. 그런 다음 앱에 보조 타일을 추가하고 Windows 8 SDK 앱 타일 및 배지 샘플에 제공된 NotificationsExtension 라이브러리를 사용하여 업데이트하겠습니다. 자, 이제 시작해 보도록 하죠.

알림 전달 방법 선택

1부에서 타일을 어떻게 표시할 것인지를 정했으니 타일을 언제 업데이트할 것인지를 생각해 보아야 합니다.

앱에서 타일을 업데이트할 수 있는 방법은 4가지가 있습니다(개발자 센터에서 알림 전달 방법 선택 참조). 앱은 타일을 업데이트하는 데 로컬 알림을 사용할 수 있으며 앱이 실행되는 동안 정보가 변경되는 경우 유용합니다. 앱은 타일과 알림 업데이트 일정을 예약하여 정확한 시간에 실행되도록 할 수 있습니다. 또한 앱은 푸시 또는 폴링 타일 알림을 사용하여 앱이 실행되지 않는 동안 클라우드에서 타일을 업데이트하도록 할 수 있습니다. 폴링은 빈도가 낮은 브로드캐스트 콘텐츠에 적합합니다. 푸시는 바로 도착해야 하는 알림 메시지 전송 또는 개별 사용자를 대상으로 하는 타일 업데이트에 적합합니다. 이 글에서는 폴링 업데이트와 로컬 업데이트에 초점을 맞추어 설명합니다.

근처에 있는 푸드 트럭에 대한 폴링

우리가 사용하는 앱에는 타일을 업데이트하기 위한 두 가지 정보가 있습니다. 가장 중요한 것은 사용자가 설정한 기본 점심 위치 근처에 있는 푸드 트럭입니다. 사용자는 앱이 실행 중일 때 앱에서 기본 점심 위치를 설정합니다. 타일 업데이트에 이 기본 위치를 사용하며 사용자가 해당 위치 근처에 있는 푸드 트럭에 대해 알 수 있도록 합니다. 여기에 나와 있는 이미지에는 이 글의 1부에서 설명한 앱의 타일이 표시되어 있습니다. 이제 이러한 타일이 앱 타일에 표시되도록 폴링을 사용하는 방법에 대해 살펴보겠습니다.

다음 내용이 들어 있는 와이드 직사각형 타일 근처에 있는 Food Trucks / Nom Nom Barbecue Truck / Sushi Truck / Macaroni Makin' Wagon    다음 내용이 들어 있는 정사각형 타일 근처 / Nom Nom / Sushi Truck

푸드 트럭은 일반적으로 하루 종일 혹은 점심 시간 동안 한곳에 머물러 있습니다. 푸드 트럭의 위치가 자주 바뀌지 않기 때문에 타일을 실시간으로 업데이트할 필요가 없습니다. 이러한 점 때문에 분초를 다투는 알림에 더 유용하게 사용되는 푸시 알림을 제외할 수 있습니다. 하지만 이 데이터를 하루에 한 번 이상 업데이트하려고 하므로 변경 사항에 대해 웹 서비스를 폴링하는 주기적 알림을 사용하는 것이 가장 좋습니다.

클라이언트 구현: 근처에 있는 푸드 트럭에 대한 폴링

주기적 알림을 설정하기 위한 클라이언트 쪽 구현은 코드 몇 줄만 사용하면 됩니다. 사용자가 앱을 실행하거나 이 앱으로 전환할 때마다 TileUpdater.startPeriodicUpdate를 호출합니다. 이렇게 하면 바로 폴링되도록 URI가 API로 전달되어 앱을 실행하거나 전환할 때마다 타일이 업데이트됩니다. 이는 API 호출이 클라우드 서비스 URI로 바로 도달하여 타일을 업데이트하기 때문입니다. 이 동작은 디버깅에 매우 유용합니다. 다음 폴링 간격을 기다리지 않고도 클라우드 서비스의 폴링을 테스트할 수 있기 때문입니다.

어떤 URI를 startPeriodicUpdate API에 제공할 것인지가 진짜 문제입니다. 저는 클라우드 서비스가 특정 위치에 대한 정보로 타일을 업데이트하도록 하려고 합니다. 사용자의 위치 정보를 보호하기 위해 서비스에 사용자의 정확한 위치를 전송하지 않으려고 합니다. 그 대신 앱 내에서 사용자가 제공하는 우편 번호로 위치를 식별합니다.

웹 서비스로 우편 번호를 전달하기 위해 폴링 URI의 끝에 쿼리 문자열을 연결하여 클라우드 서비스에서 타일에 넣을 위치를 알 수 있도록 합니다.

http://www.contoso.com/foodtrucks/tile.xml?zipcode=98052

웹 서비스에서는 이 URI의 HTTP GET에 대한 응답으로 URI에 대해 제공된 우편 번호의 서식 있는 타일 알림 XML을 반환합니다. URI 문자열에 하드 코드된 우편 번호가 있는 폴링을 설정하기 위한 코드는 다음과 같습니다.

JavaScript:

// update the tile poll URI
var notifications = Windows.UI.Notifications;
var polledUri = new Windows.Foundation.Uri("http://www.contoso.com/foodtrucks/tile.xml?zipcode=98052");
var recurrence = notifications.PeriodicUpdateRecurrence.hour;
var tileUpdater = notifications.TileUpdateManager.createTileUpdaterForApplication();
tileUpdater.startPeriodicUpdate(polledUri, recurrence);

C#:

// update the tile poll URI
using Windows.UI.Notifications;
Uri polledUri = new Uri("http://www.contoso.com/foodtrucks/tile.xml?zipcode=98052");
PeriodicUpdateRecurrence recurrence = PeriodicUpdateRecurrence.Hour;
TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(polledUri, recurrence);

푸드 트럭이 하루 종일 움직일 수 있기 때문에 타일을 자주 업데이트하려고 합니다. 우리 앱에서는 백엔드 서비스의 부하와 타일에 대한 정보의 최신성 간의 균형을 유지하도록 업데이트 간격을 1시간으로 합니다.

startPeriodicUpdate API를 한 번 호출하면 타일은 앱이 실행되고 있지 않은 경우에도 1시간에 한 번씩 업데이트합니다. 폴링할 URI를 변경하려는 경우 다른 URI로 API를 다시 호출하기만 하면 됩니다. 예를 들어 사용자가 기본 위치를 다른 우편 번호로 변경하는 경우 startPeriodicUpdate를 다시 호출하여 올바른 우편 번호로 URI를 업데이트합니다. 사용자가 기본 위치를 지우거나 타일 업데이트를 중지하려는 경우 stopPeriodicUpdate API를 호출하여 주기적 업데이트를 중지할 수 있습니다.

startPeriodicUpdate API를 사용하는 방법에 대한 자세한 내용은 개발자 센터의 푸시 및 주기적 알림 클라이언트 쪽 샘플타일에 대한 주기적 알림을 설정하는 방법을 참조하십시오.

서버 구현: 근처에 있는 푸드 트럭에 대한 폴링

거의 대부분의 서비스 기술로 폴링된 타일의 서버 쪽을 구현할 수 있습니다. 여기서 예제 PHP 및 ASP.NET 코드를 살펴보겠습니다.

웹 서비스가 폴링되면 HTTP GET 요청에 타일 XML 스키마에 맞는 XML로 응답해야 합니다. HTTPS를 사용하여 웹 서비스가 선을 통해 전송된 콘텐츠를 보호할 수 있도록 할 수도 있습니다. 쿠키는 지원되지 않습니다. 서비스가 요청에 응답하는 데 필요한 모든 정보는 URI의 일부로 포함되어야 합니다. 이러한 이유로 앱은 우편 번호를 전달하는 데 쿼리 문자열을 사용합니다.

다음에 살펴볼 PHP 코드에서는 웹 서비스 데이터베이스의 액세스를 무시합니다. 실제 작동 코드에서는 get_trucks_from_database() 함수에서 반환하는 트럭 변수에 웹 서비스가 특정 우편 번호에 대한 타일 템플릿을 작성하는 데 필요한 모든 정보가 포함됩니다. 저는 이 서비스 예제 코드를 약간 단순화하여 서비스가 반환하는 XML에 집중하도록 했습니다. 실제 웹 서비스 배포는 성능, 확장성, 보안 및 유지 가능한 더 많은 아키텍처를 고려하게 됩니다.

PHP:

<?php

//
// set default query string parameters
// process query string and set parameters
//
if($_GET['zipcode']){
$zipcode = $_GET['zipcode'];
}
else{
$zipcode = 'default';
}

//
// get item info from our database
// - this is placeholder code that you need to replace in a real implementation
// - the return value is a multidimensional array of the long and short strings
// to place in the tile template
//
$trucks = get_trucks_from_database($zipcode);

?>
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'?>
<tile>
<visual>
<binding template="TileWideText01">
<text id="1">Food Trucks Near You</text>
<text id="2"><?php echo $trucks[0][0]?></text>
<text id="3"><?php echo $trucks[0][1]?></text>
<text id="4"><?php echo $trucks[0][2]?></text>
</binding>
<binding template="TileSquareText03">
<text id="1">Near You</text>
<text id="2"><?php echo $trucks[1][0]?></text>
<text id="3"><?php echo $trucks[1][1]?></text>
</binding>
</visual>
</tile>

다음 코드 예제는 방금 살펴본 PHP 코드와 동일합니다. 이 ASP.NET 웹 페이지 예제는 타일 서비스를 빠르게 구현하는 방법을 보여 줍니다. 여러분은 완벽하게 기능하는 ASP.NET 서비스에서 새로운 ASP.NET 웹 API를 사용하고자 할 수 있습니다. ASP.NET 웹 API는 이와 같은 HTTP 서비스를 위해 특별히 구현됩니다. ASP.NET 웹 API에 대한 자세한 내용은 http://www.asp.net/web-api를 참조하십시오.

ASP.NET:

@{
//
// set default query string parameters
// process query string and set parameters
//
var zipcode = Request["zipcode"] ?? "default";
//
// get item info from our database
// - this is placeholder code that you need to replace in a real implementation
// - the return value is a multidimensional array of the long and short strings
// to place in the tile template
var trucks = get_trucks_from_database(zipcode);

}<?xml version="1.0" encoding="utf-8" ?>'?>
<tile>
<visual>
<binding template="TileWideText01">
<text id="1">Food Trucks Near You</text>
<text id="2">@trucks[0,0]</text>
<text id="2">@trucks[0,1]</text>
</binding>
<binding template="TileSquareText03">
<text id="1">Near You</text>
<text id="2">@trucks[1,0]</text>
<text id="2">@trucks[1,1]</text>
</binding>
</visual>
</tile>

즐겨 찾는 푸드 트럭

이제까지 앱에서 기본 타일에 표시하는 콘텐츠에 대해 살펴봤습니다. 하지만 사용자가 시작 화면에 타일을 두고 특정 푸드 트럭을 추적하고자 할 때가 있습니다. 우리 앱에서는 앱 바를 사용하여 사용자가 특정 푸드 트럭을 시작 화면에 고정할 수 있도록 합니다. 이렇게 고정된 타일을 보조 타일이라고 합니다. 사용자가 보조 타일을 고정하면 해당 타일로 알림을 전송하여 특정 푸드 트럭에 대한 정보로 해당 타일을 업데이트합니다.

푸드 트럭 타일 고정

타일을 고정하면 앱은 시작 화면의 앱에 있는 특정 콘텐츠에 대한 직접 액세스를 사용자에게 제공할 수 있습니다. 보조 타일은 사용자가 고정한 푸드 트럭을 처리하는 앱의 일부로 앱을 직접 실행하도록 하는 데 사용할 수 있습니다.

고정된 타일은 앱 내에서만 만들 수 있습니다. 사용자는 앱 바를 호출하여 타일을 고정할 수 있게 됩니다. 앱 바에는 기본적인 압정 아이콘이 포함되어 있어 사용자가 뷰에 콘텐츠를 고정할 수 있음을 나타냅니다.

사용자가 핀 단추를 탭하면 고정할 타일의 미리 보기를 표시하는 플라이아웃이 나타납니다.

Nom Nom Barbecue Truck의 그림과 단추가 있는 플라이아웃: 시작 화면에 고정

우리가 해야 할 일:

  1. '시작 화면에 고정' 및 '시작 화면에서 제거' 작업에 대한 핀 아이콘을 포함하여 앱에 앱 바 추가
  2. 앱 바 고정/제거 단추 클릭에 대한 이벤트 처리기 구현
  3. 고정/제거 작업에 대한 응답으로 새 타일을 고정하도록 앱별 논리 추가

앱 바를 만드는 처음 두 단계는 살펴보지 않을 것이기 때문에 타일을 고정하는 데 집중할 수 있습니다. 다음에서 앱 바를 구현하는 방법에 대한 세부 정보를 찾아볼 수 있습니다.

3단계에서는 앱에서 몇 가지 속성을 설정하여 보조 타일을 만듭니다.

JavaScript:

// Keep track of your secondary tiles with a unique ID   
var nomNomTile = "SecondaryTile.NomNom";

// Set properties on the tile
var logo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-Logo.png");
var smallLogo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-SmallLogo.png");
var wideLogo = new Windows.Foundation.Uri("ms-appx:///images/NomNomTruck-WideLogo.png");
var TileActivationArguments = "TruckName=NomNom";

// Create the secondary tile
var tile = new Windows.UI.StartScreen.SecondaryTile(nomNomTile,
"Nom Nom",
"Nom Nom Barbecue Truck",
TileActivationArguments,
Windows.UI.StartScreen.TileOptions.sh
owNameOnWideLogo,
logo,
wideLogo);

tile.foregroundText = Windows.UI.StartScreen.ForegroundText.light;
tile.smallLogo = smallLogo;

// Request the user’s permission to create the secondary tile
// - we return the promise here, assuming that this code is embedded
// in a larger function.
// See the Windows 8 SDK Secondary Tiles sample for more info:
// http://code.msdn.microsoft.com/windowsapps/Secondary-Tiles-Sample-edf2a178
return new WinJS.Promise(function (complete, error, progress) {
tile.requestCreateAsync().then(function (isCreated) {
if (isCreated) {
complete(true);
} else {
complete(false);
}
});
});

C#:
// Keep track of your secondary tiles with a unique ID   
const string nomNomTile = "SecondaryTile.NomNom";

// Set properties on the tile
Uri logo = new Uri("ms-appx:///images/NomNomTruck-Logo.png");
Uri smallLogo = new Uri("ms-appx:///images/NomNomTruck-SmallLogo.png");
Uri wideLogo = new Uri("ms-appx:///images/NomNomTruck-WideLogo.png");
string tileActivationArguments = "TruckName=NomNom";

// Create the secondary tile object
SecondaryTile secondaryTile = new SecondaryTile(nomNomTile,
"Nom Nom",
"Nom Nom Barbecue Truck",
tileActivationArguments,
Windows.UI.StartScreen.TileOptions.ShowNa
meOnWideLogo,
logo,
wideLogo);

secondaryTile.ForegroundText = Windows.UI.StartScreen.ForegroundText.Light;
secondaryTile.SmallLogo = smallLogo;

// Request the user’s permission to create the secondary tile
// - this code assumes that this code was called within an event handler which has
// a ‘sender’ parameter.
// See the Windows 8 SDK Secondary Tiles sample for more info:
// http://code.msdn.microsoft.com/windowsapps/Secondary-Tiles-Sample-edf2a178
await secondaryTile.RequestCreateForSelectionAsync(MainPage.GetElementRect((FrameworkElement)se
nder), Windows.UI.Popups.Placement.Right);

보조 타일을 고정하는 방법에 대한 자세한 내용은 보조 타일에 대한 지침 및 검사 목록보조 타일 Consumer Preview 샘플을 참조하십시오.

고정된 타일 업데이트에 로컬 알림 사용

고정된 타일은 시작 화면에서 업데이트하기 위한 앱의 추가 타일입니다. 이 타일의 업데이트는 앱의 기본 타일에서의 업데이트와 다른 점이 없습니다. 이 앱에서는 클라우드 업데이트 방식 중 하나를 사용하는 대신 로컬 알림 API를 사용하여 앱이 실행되고 있는 동안 보조 타일을 업데이트합니다. 로컬 알림의 작동 방식을 보여 주기 위해 로컬 알림을 여기에 표시합니다. 이와 비슷한 방식으로 클라우드에서 업데이트할 수 있습니다. 이 앱은 폴링 시나리오도 쉽게 구현할 수 있습니다.

이 섹션의 코드에서는 Windows 8 SDK 앱 타일 및 배지 샘플에 포함된 NotificationsExtensions 라이브러리를 사용합니다. 앱 프로젝트에 이 라이브러리를 포함하여 로컬에서 손쉽게 타일을 업데이트하도록 할 수 있습니다. 라이브러리는 JavaScript, C# 및 C++ 앱 내에서 XML을 처리하지 않도록 할 수 있는 Windows 타일 업데이트 API 상위 개체 모델을 제공합니다. 또한 IntelliSense를 제공하여 손쉽게 개발할 수도 있습니다.

로컬 알림 API를 사용하여 앱이 실행 중일 때 언제든 타일을 업데이트할 수 있습니다. 저는 고정된 푸드 트럭 타일에서 사용자가 이 앱을 실행할 때마다 특정 푸드 트럭에서 제공하는 혜택으로 타일을 업데이트하도록 하려고 합니다.

보조 타일 열거

앱이 실행되고 있지 않은 경우 사용자가 시작 화면에서 보조 타일을 제거할 수 있기 때문에 앱 실행 시 가장 먼저 수행해야 하는 작업은 현재 고정된 보조 타일이 있는지를 살펴보는 것입니다. 열거된 각 타일에는 타일을 고유하게 식별하는 tileId가 포함되어 있습니다. 앱은 생성될 때 tileId를 설정하기 때문에 ID를 사용하여 우리가 찾는 각 타일의 업데이트 방법을 확인할 수 있습니다. 방법은 다음과 같습니다.

JavaScript:

// Get secondary tile ids
Windows.UI.StartScreen.SecondaryTile.findAllAsync().done(function (tiles) {
if (tiles) {
tiles.forEach(function (tile) {
switch (tile.tileId) {
case nomNomTile:
updateNomNomTruck();
break;
// add cases for all the food trucks this app supports
default:
break;
}
});
}
});

C#:

// Get secondary tile ids
IReadOnlyList<SecondaryTile> tilelist = await
Windows.UI.StartScreen.SecondaryTile.FindAllAsync();

foreach (var tile in tilelist)
{
switch (tile.TileId)
{
case nomNomTile:
updateNomNomTruck();
break;
// add cases for all the food trucks this app supports
default:
break;
}
}

로컬 업데이트

각각의 고정된 푸드 트럭 타일에서 특정일의 트럭 위치에 대한 최신 정보로 타일을 업데이트합니다. 로컬 업데이트를 사용하여 기본 타일을 업데이트하는 경우 API의 기본 작업으로 호출 앱의 기본 타일을 업데이트하기 때문에 보조 타일을 먼저 열거할 필요가 없습니다. 다시 내용을 떠올릴 수 있도록 1부에서 보았던 앱의 타일을 표시했습니다.

그릴 위의 고기 이미지, 트럭 로고 및 업데이트된 텍스트: Nom Nom Barbecue Truck, Washer Ave 및 3번가, 3시까지그릴 위 고기 이미지, 트럭 로고 및 업데이트된 텍스트: Nom Nom @ Washer Ave 및 3번가, 3시까지

열거에서 호출했던 함수는 다음과 같습니다. 이 열거는 실제로 보조 타일에 알림을 전송합니다.

JavaScript:      

function updateNomNomTruck() {
// Business logic for retrieving Nom Nom BBQ truck deals
// ...
var result = "Washer Ave and 3rd until 3";

// We can send a notification only for a tile that is pinned.
// Lets make sure the tile is pinned before we try to send the notification.
if (Windows.UI.StartScreen.SecondaryTile.exists(nomNomTile)) {

// Construct the wide template
var wideTile =
NotificationsExtensions.TileContent.TileContentFactory.createTileWideImageAndText02();
wideTile.image.src = "http://www.contoso.com/foodtrucks/nomnombbq.png";
wideTile.textCaption1.text = "Nom Nom Barbecue Truck";
wideTile.textCaption2.text = result;

// Construct the square template
var squareTile =
NotificationsExtensions.TileContent.TileContentFactory.createTileSquarePeekImageAndText04
();
squareTile.image.src = "http://www.contoso.com/foodtrucks/nomnombbq.png";
squareTile.textBodyWrap.text = "Nom Nom @ " + result;

// Attach the square template to the notification
wideTile.squareContent = squareTile;

// send the notification to the secondary tile
Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForSecondaryTile(nomNomTi
le).update(wideTile.createNotification());
}
}

C#:   

private void updateNomNomTruck()
{
// Business logic for retrieving Nom Nom BBQ truck deals
// ...
string result = "Washer Ave and 3rd until 3";

// We can send a notification only for a tile that is pinned.
// Lets make sure the tile is pinned before we try to send the notification.
if (Windows.UI.StartScreen.SecondaryTile.Exists(nomNomTile))
{

// Construct the wide template
NotificationsExtensions.TileContent.ITileWideImageAndText02 wideTile =
NotificationsExtensions.TileContent.TileContentFactory.CreateTileWideImageAndText02();
wideTile.Image.Src = "http://www.contoso.com/foodtrucks/nomnombbq.png";
wideTile.TextCaption1.Text = "Nom Nom Barbecue Truck";
wideTile.TextCaption2.Text = result;

// Construct the square template
NotificationsExtensions.TileContent.ITileSquarePeekImageAndText04 squareTile =
NotificationsExtensions.TileContent.TileContentFactory.CreateTileSquarePeekImageAndText04();
squareTile.Image.Src = "http://www.contoso.com/foodtrucks/nomnombbq.png";
squareTile.TextBodyWrap.Text = "Nom Nom @ " + result;

// Attach the square template to the notification
wideTile.SquareContent = squareTile;

// Send the notification to the secondary tile
Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForSecondaryTile(nomNomTi
le).Update(wideTile.CreateNotification());
}
}

NotificationsExtensions 라이브러리를 사용하기 때문에 로컬 코드에서 XML을 처리할 필요가 없습니다. 대신 NotificationsExtensions에서 제공하는 개체 모델을 사용하여 각 알림 템플릿의 다른 속성을 확인하는 데 IntelliSense를 사용할 수 있습니다.

타일 업데이트에 대한 XML은 다음과 같습니다.

<?xml version="1.0" encoding="utf-8" ?>
<tile>
<visual>
<binding template="TileWideImageAndText02">
<image id="1" src="http://www.contoso.com/foodtrucks/nomnombbq.png"/>
<text id="1">Nom Nom Barbecue Truck</text>
<text id="1">Washer Ave and 3rd until 3</text>
</binding>
<binding template="TileSquarePeekImageAndText04">
<image id="1" src=" http://www.contoso.com/foodtrucks/nomnombbq-square.png"/>
<text id="1">Nom Nom @ Washer Ave and 3rd until 3</text>
</binding>
</visual>
</tile>

NotificationsExtensions 라이브러리를 사용하는 경우 IntelliSense를 사용하여 로컬 타일 업데이트를 더욱 빠르게 할 수 있는 타일 템플릿에 대한 속성을 확인할 수 있습니다. JavaScript, C# 및 C++ 프로젝트에서 NotificationsExtensions의 유용성을 확인하시기 바랍니다.

결론

사용자들이 타일에서 재미있거나 흥미로운 점을 발견하면 이를 알아보기 위해 여러분의 앱을 실행하게 될 확률이 높아집니다. 이 글이 여러분이 라이브 타일을 추가하는 방법과 앱의 강점을 잘 나타낼 수 있는 방법에 대한 실마리를 제공했기를 바랍니다. 알림에 대해 더 알아보고 싶은 경우 개발자 센터의 타일 및 알림 개요알림 전달 방법 선택을 참조하십시오.

- Windows 프로그램 관리자, Kevin Michael Woley

이 글은 여러 사람의 도움으로 작성되었습니다. 도움을 주신 Tyler Donahue, Daniel Oliver 그리고 Jon Galloway에게 감사드립니다.

  • Loading...
Leave a Comment
  • Please add 8 and 2 and type the answer here:
  • Post