Condividi tramite


Wallet & In App Purchase for Windows Phone 8

Two of the many highlighted features in Windows Phone 8 are Wallet and In-App Purchase options. In this post we will have an overview on these features and develop sample applications for demonstrating Deal, Membership Card, Payment Card, In-App Purchase features. You can find the source code of the sample Windows Phone projects mentioned in this blog at https://aka.ms/walletdemo. Once you compile and install these projects on the emulator you will have the screenshot of the applications’ list shown in figure 1. All these features are dependent on the digital Wallet that comes with Windows Phone 8 OS by default. Wallet functionality requires comprehensive security consideration on a mobile device. Some of these features are Trusted Boot and code signing, attack surface reduction, user consent and control, isolation, new Internet Explorer with SmartScreen, device encryption etc. You may find more security overview from this URL address.

1
Figure 1: Application list.

Apart from the existing start screen security, like setting a PIN on the lock screen, user can additionally set a PIN on the wallet. Without entering this PIN, Wallet features can’t be initiated. User can set a PIN on the wallet by following the menu shown in figure 2.

2
Figure 2: Setting a PIN on Wallet.

Some of the features that you can implement on Windows Phone 8 with sample scenarios are listed below.

Deals: Imagine that you start to use your favorite coffee shop’s Windows Phone App that you downloaded from Windows Phone App Store (In the attached sample code pack, this app is called “W Deals”). In addition to existing features etc. in the app, your coffee shop might send you a deal through the app according to:

  • Your birthday
  • Physical location (closer to a shop)
  • 1000th click on an item in the app
  • etc.

You can benefit from this digital deal item on your phone by using the barcode image or send the promocode by NFC etc.

Membership Card: Imagine that your favorite coffee shop gives you a digital membership card. In each coffee purchase (either online coffee capsule purchase or onsite purchase) you may earn loyalty points. Collecting this points, you can order additional goods from the shop. These points or promotions are delivered to you either by NFC tap or through the cloud etc.

Payment Card: Even more, your favorite coffee shop may give you a digital payment card where you can use it online or onsite to purchase products with prepaid balance and see all transactions that you made with this card.

In-App Purchase: Another sample is based on your favorite game app. Your game app creates a digital payment card with custom cash unit (i.e. Gold Coins, Galaxy Lira etc.) or real credit card can be used. You can purchase digital products such as game levels, avatars etc. with this card. These digital products can be defined and published through Windows Phone store by app developer.

If you are developing application that uses the wallet features, you must set the ID_CAP_WALLET capability under the Capabilities tab in WMAppManifest.xml file. Otherwise your app will crash in case it tries to access the wallet. Also if you are using In-App Payment feature (last sample project uses this feature) than you also have to set the ID_CAP_WALLET_PAYMENTINSTRUMENTS capability. Capabilities window is shown in figure 3.

3
Figure 3: Setting the capability feature of an application.

1.1. Deals

For developing applications that uses the deal feature, you have to add Microsoft.Phone.Wallet namespace inside the code page.

 using Microsoft.Phone.Wallet; 

Below code is used to add a digital Deal item into the Wallet. Your app may communicate with the company servers over cloud and install an appropriate deal into the wallet of the client’s phone.

  1: private async void btnAddDeal_Tap(object sender, System.Windows.Input.GestureEventArgs e)
  2: {
  3:     try
  4:     {
  5:         Deal DI = new Deal("ContosoDeal");
  6:  
  7:         DI.MerchantName = "Contoso Coffee Corp.";
  8:         DI.DisplayName = "Contoso Coffee";
  9:         DI.Description = "With the above barcode, wi… shops.";
  10:         DI.CustomerName = "This deal is offered for [Customer Name]";
  11:         DI.ExpirationDate = DateTime.Now.AddDays(15);
  12:         DI.IssuerName = "Issuer name of this deal is [Issuer Name]";
  13:         DI.IssuerWebsite = new Uri("https://www.issuerwebsite.contoso.com");
  14:         DI.NavigationUri = new Uri("/mainpage.xaml? …", UriKind.Relative);
  15:         DI.Notes = "Notes for the customer.";
  16:         DI.OfferWebsite = new Uri("https://www.offerwebsite.contoso.com");
  17:         DI.TermsAndConditions = "Terms and Conditions of the deal goes here.";
  18:         DI.Logo99x99 = GetBitmapSource("Assets/wallet_99x99.png");
  19:         DI.Logo159x159 = GetBitmapSource("Assets/wallet_159x159.png");
  20:         DI.Logo336x336 = GetBitmapSource("Assets/wallet_336x336.png");
  21:         DI.BarcodeImage = GetBitmapSource("Assets/wallet_barcode.png");
  22:  
  23:         await DI.SaveAsync();
  24:  
  25:         Windows.System.Launcher.LaunchUriAsync(new Uri("wallet://",UriKind.RelativeOrAbsolute));
  26:     }
  27:     catch (Exception ex)
  28:     {
  29:         MessageBox.Show("Error: " + ex.Message);
  30:     }
  31: }

In this code snippet, GetBitmapSource function loads an image from the app resource and return it as a BitmapSource typed data. In this sample code we store the images inside the app’s resources folder but you can dynamically download and set appropriate images from your company servers. For accessing the BitmapSource class following namespace should be added on your code page.

 using System.Windows.Media.Imaging;

Also the name that you set in the contractor of the Deal class is used as an identifier while you search an item in the wallet. Below code uses ContosoDeal identifier to refer this specific deal.

 Deal DI = new Deal("ContosoDeal");

MerchantName, Logo336x336, BarcodeImage etc. properties that are used in the above code are some of the members of the deal class. Once you set the values of these members, they will be visible as a digital property of the Deal in the wallet. For demonstration purposes we have used static images and predefined values in this code sample. You can dynamically set appropriate values.

Also the below line of code is used to automatically launch the Wallet after installing a Deal inside it.

 Windows.System.Launcher.LaunchUriAsync(new Uri("wallet://",UriKind.RelativeOrAbsolute));

Below are the screenshots from the deal item installed on the wallet. You can see the visual correspondence of the values that we set in the sample code above.

4a 4b 4c4d 4e
Figure 4.a.b.c.d.e (from left to right): a) Sample Application b) Installed deal item in the wallet c-d) About page of the deal item e) Details page of the deal item.

If the customer opens the Deal from the Wallet and tap the “open app” link shown in figure 4.c, application that installed this deal will be launched with specified custom parameters. This parameters are programmatically determined during the installation or updated with a wallet agent (will be mentioned later) that is periodically launched by OS. With this agent you can communicate with servers on the cloud etc. with various scenarios.

i.e. You can send promocode that is associated with this deal through the coffee shop’s app and consume the deal through the app by transferring the code from phone to cashier’s device by NFC, over Internet etc. scenarios. Communication between the phone app and the deal item in the wallet will be through this parameter submission.

Data Transfer between a wallet item and the owning application:

Like in the Deal item, other digital items in the wallet can also transfer data to the owner app that creates the item. In case of the Deal item, you can set the NavigationUri member of the class with the data to be transferred.

 DI.NavigationUri = new Uri("/mainpage.xaml?par1=val1;par2=val2;…", UriKind.Relative);

In the above sample code, if the user taps the “open app” link as shown in figure 4.c, app that created the Deal item will be launched and mainpage.xaml windows will be opened. Finally “par1=val1;par2=val2;…” values will be passed to this window. By this way you can open not only the mainpage.xaml window but any window that exist in the app by passing any value to it. Inside the target Windows’s code page, you can retrieve and parse the transferred data as shown below:

  1: protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
  2: {
  3:     base.OnNavigatedTo(e);
  4:  
  5:     string value = "";
  6:  
  7:     if (NavigationContext.QueryString.TryGetValue("ParameterName", out value))
  8:     System.Windows.MessageBox.Show("ParameterName=" + value, "Received", MessageBoxButton.OK);
  9: }
1.2. Membership Card

Adding items such as Membership, Payment cards etc. requires an access to AddWalletItemTask class. So first of all we need to add the following namespaces in to our code page.

 

 using Microsoft.Phone.Wallet; 
using Microsoft.Phone.Tasks;

After adding this namespaces, create a static instance of the AddWalletItemTask class for further use and add an event handler to catch any success or failure notifications coming from this instance.

  1: public MainPage()
  2: {
  3:     InitializeComponent();
  4:  
  5:     AWIT.Completed += AWIT_Completed;
  6: }
  7:  
  8: static AddWalletItemTask AWIT = new AddWalletItemTask();
  9:  
  10: async void AWIT_Completed(object sender, AddWalletItemResult e)
  11: {
  12:     if (e.TaskResult == TaskResult.OK)
  13:     {
  14:         MessageBox.Show(e.Item.DisplayName + " operation successful.");
  15:  
  16:         // open the wallet
  17:         await Windows.System.Launcher.LaunchUriAsync(new Uri("wallet://", UriKind.RelativeOrAbsolute));
  18:     }
  19:     else
  20:     {
  21:         MessageBox.Show(e.Item.DisplayName + " Error: " + e.Error.Message);
  22:     }
  23: }

AWIT_Completed method that we implemented will be called whenever a digital item is installed to the wallet. So inside this method we can check and inform the user as if the installation operation is successful or not.

 

5a 5b 5c
Figure 5.a.b.c: Membership card installed into the wallet.

For adding a Membership Card, an instance from WalletTransactionItem class need to be created. Providing a unique string identifier as a parameter to the constructor of this class will let you a direct access to the specific item installed in the wallet.

Below code creates a WalletTransactionItem and sets some of the members of this item with static sample data.

  1: void AddMembershipCardToWallet(MemberDetails member, PublisherDetails publisher)
  2: {
  3:     try
  4:     {
  5:         WalletTransactionItem wtiMember;
  6:         wtiMember = new WalletTransactionItem("CoffeeContosoMembershipCard");
  7:         wtiMember.IssuerName = publisher.Name;
  8:         wtiMember.DisplayName = publisher.Name + " Membership Card.";
  9:         wtiMember.IssuerPhone.Business = publisher.TelNo;
  10:         wtiMember.CustomerName = member.Name;
  11:         wtiMember.AccountNumber = member.MembershipNumber;
  12:         wtiMember.BillingPhone = member.TelNo;
  13:         wtiMember.IssuerWebsite = new Uri(publisher.WebSite);
  14:         wtiMember.DisplayAvailableBalance = "1000 Cont Lira";
  15:         wtiMember.NavigationUri = new Uri("/mainpage.xaml?ParameterName=[ParameterValue] for wallet to app communication.", UriKind.Relative);
  16:  
  17:         wtiMember.Logo99x99 = GetBitmapSource("Assets/wallet_99x99.png");
  18:         wtiMember.Logo159x159 = GetBitmapSource("Assets/wallet_159x159.png");
  19:         wtiMember.Logo336x336 = GetBitmapSource("Assets/wallet_336x336.png");
  20:         wtiMember.BarcodeImage = GetBitmapSource("Assets/wallet_barcode.png");
  21:  
  22:         AWIT.Item = wtiMember;
  23:         AWIT.Show();
  24:     }
  25:     catch (Exception ex)
  26:     {
  27:         MessageBox.Show("Error: " + ex.Message);
  28:     }
  29: }

In the above code snippet MemberDetails and PublisherDetails are user defined classes to hold and pass the card member and publisher details within a single object.

Following code sets the AddWalletItemTask type object that we statically created at the main class’s initialization and shows the “Add to Wallet” Membership Card item (WalletTransactionItem) to the user.

 AWIT.Item = wtiMember;
AWIT.Show();

Because of security reasons, it is not possible to directly insert an item to the wallet. First you have to get a confirmation from the user (figure 5.) than if the user accepts, it will be installed to the wallet. If the user set a PIN to the wallet than user will be asked to enter the PIN to unlock the wallet before the installation.

6
Figure 6: Confirmation window to add an item into the wallet.

All these operations are performed through WalletTransactionItem.

Programming Agents to synchronize your digital item details:

In windows phone 8, it is possible to implement digital agents which are periodically called by OS independent from the associated application’s lifetime. Even the application is not running, OS will run the piece of code implemented in the agent. Because of battery lifetime considerations, time intervals to call this agents are not very short.

To add an agent into your application, first you have to create a separate agent project and add generated DLL from this agent as a reference to the project of your main application. To create an agent project in Visual Studio, you select “Windows Phone Class Library” template under Windows Phone project templates. Replace the content of the generated code file with the following lines of code.

  1: using Microsoft.Phone.Wallet;
  2:  
  3: namespace WAgents
  4: {
  5:     public class WAgent : WalletAgent
  6:     {
  7:         private static volatile bool _classInitialized;
  8:  
  9:         public WAgent()
  10:         {
  11:             if (!_classInitialized)
  12:             {
  13:                 _classInitialized = true;
  14:                 // Subscribe to the managed exception handler
  15:                 Deployment.Current.Dispatcher.BeginInvoke(delegate
  16:                 {
  17:                     Application.Current.UnhandledException += ScheduledAgent_UnhandledException;
  18:                 });
  19:             }
  20:         }
  21:  
  22:         // Code to execute on Unhandled Exceptions
  23:         private void ScheduledAgent_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
  24:         {
  25:             if (System.Diagnostics.Debugger.IsAttached)
  26:             {
  27:                 // An unhandled exception has occurred; break into the debugger
  28:                 System.Diagnostics.Debugger.Break();
  29:             }
  30:         }
  31:  
  32:         protected override async void OnRefreshData(RefreshDataEventArgs args)
  33:         {
  34:             // Check if the customers birthday etc…
  35:             // …
  36:  
  37:             foreach (WalletItem item in args.Items)
  38:             {
  39:                 WalletTransactionItem WTI = item as WalletTransactionItem;
  40:                 if (WTI != null)
  41:                 {
  42:                     if (WTI.Id == "CoffeeContosoMembershipCard")
  43:                     {
  44:                         WTI.Message = "Happy birthday, we have a suprise for you. Tap for details.";
  45:                         WTI.MessageNavigationUri = new Uri("/mainpage.xaml?ParameterName=[ParameterValue] for wallet agent to app communication.", UriKind.Relative);
  46:  
  47:                         //WTI.SetUserAttentionRequiredNotification(true);
  48:  
  49:                         await WTI.SaveAsync();
  50:                     }
  51:                 }
  52:             }
  53:  
  54:             //base.OnRefreshData(args);
  55:             NotifyComplete();
  56:         }
  57:     }
  58: }

When the agent is invoked by the OS, codes under OnRefreshData method will be executed. Here you can communicate with your server on the cloud to see if there is a promotion, deal etc. specific to the customer that owns the associated digital wallet item. In the above code example, we check if today is customer’s birthday. If yes, we add a special notification near the digital item’s icon (see figure 5.b) by giving piece of information. If the customer tap’s over this notification, associated application will be launched with the parameters specified by the following code in the agent.

 WTI.MessageNavigationUri = new Uri("/mainpage.xaml?Param...", UriKind.Relative);

Class, namespace, Project names that you are using in the agent code is very important for referencing of the agent in the main application.

To associate the agent in the main application, open the WMAppManifest.xml file in the main app project. Update the <Tasks> node with the following code.

  1: <Tasks>
  2:       <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
  3:       <ExtendedTask Name="BackgroundTask">
  4:         <BackgroundServiceAgent Specifier="WalletAgent" Name="WalletAgent" Source="WalletAgent" Type="WAgents.WAgent" />
  5:       </ExtendedTask>
  6: </Tasks>

If you are using different namespace, class etc. names, update the BackgroundServiceAgent node in the above code appropriately. If you fail to write correct information, you will get something like “file not found” error when the agent is invoked etc.

Finally don’t forget to add the agent in to the references of the main application as shown in figure 7.

7
Figure 7: Add WalletAgent project as a reference to the main project MembershipCards.

1.3. Payment Card

Programming logic behind the Payment Cards are similar to the one in Membership Cards mentioned in the previous section. In addition you have Credit Limit, Available Credit, and Transactions like features in this digital item. Instead of using WalletTransactionItem, for payment cards PaymentInstrument class has to be used. Depending on the card type (Credit, Debit, Credit&Debit, and INICIS), PaymentInstrumentKinds property of the object in the following line of code has to be set with appropriate value.

 PI.PaymentInstrumentKinds = PaymentInstrumentKinds.Credit;

Like in the Membership Card, you add the item into the Wallet with PaymentInstrument object. Again the user authorization (Figure 8.b) is mandatory to add the card into the wallet.

  1: void AddPaymentCardToWallet(MemberDetails member, PublisherDetails publisher)
  2: {
  3:     try
  4:     {
  5:         PaymentInstrument PI;
  6:         PI = new PaymentInstrument("Contoso Credit Account");
  7:         PI.PaymentInstrumentKinds = PaymentInstrumentKinds.Credit;
  8:         PI.IssuerName = publisher.Name;
  9:         PI.DisplayName = publisher.Name + " Payment Card";
  10:         PI.IssuerPhone.Business = publisher.TelNo;
  11:         PI.CustomerName = member.Name;
  12:         PI.AccountNumber = member.MembershipNumber;
  13:         PI.BillingPhone = member.TelNo;
  14:         PI.IssuerWebsite = new Uri(publisher.WebSite);
  15:         PI.ExpirationDate = member.ExpirationDate;
  16:         PI.NavigationUri = new Uri("/mainpage.xaml?ParameterName=[ParameterValue] for wallet to app communication.", UriKind.Relative);
  17:  
  18:         PI.DisplayCreditLimit = member.CreditLimit.ToString();
  19:         PI.DisplayAvailableCredit = member.AvailableLimit.ToString();
  20:  
  21:         PI.Logo99x99 = GetBitmapSource("Assets/wallet_99x99.png");
  22:         PI.Logo159x159 = GetBitmapSource("Assets/wallet_159x159.png");
  23:         PI.Logo336x336 = GetBitmapSource("Assets/wallet_336x336.png");
  24:                                                 
  25:         AWIT.Item = PI;
  26:         AWIT.Show();
  27:     }
  28:     catch (Exception ex)
  29:     {
  30:         MessageBox.Show("Error: " + ex.Message);
  31:     }
  32: }

8a 8b 8c8d 8e 8f 8g 8h 8i
Figure 8.a.b.c.d.e.f.g.h.i (from left to right): a) Sample Application b-c) Confirmation message to install the payment card d-f) Details of the payment card installed in Wallet. g) After pressıng “Create a Random Transaction” button in the app. h-i) List of transactions and their details in the wallet.

After having the card in the wallet, it is possible to create transactions through this card.

With the below code snippet it is possible to create a transaction and update the credit details etc. on the Payment Card.

  1: Random RandomPayment = new Random();
  2:  
  3: async private void btnCreatePaymentTrans_Tap(object sender, System.Windows.Input.GestureEventArgs e)
  4: {
  5:     // Find the payment instrument to use 
  6:     PaymentInstrument PI;
  7:     PI = Wallet.FindItem("Contoso Credit Account") as PaymentInstrument;
  8:  
  9:     if (PI == null)
  10:     {
  11:         MessageBox.Show("Payment Card [Credit Account] not found in the wallet.");
  12:         return;
  13:     }
  14:  
  15:     // Create the transaction
  16:     WalletTransaction transaction = new WalletTransaction();
  17:  
  18:     transaction.DisplayAmount = RandomPayment.Next(50, 500).ToString();
  19:  
  20:     transaction.Description = "Random online payment";
  21:     transaction.TransactionDate = DateTime.Now;
  22:  
  23:     // Add the transaction to the wallet
  24:     PI.TransactionHistory.Add("Internet payment " + DateTime.Now, transaction);
  25:  
  26:     await PI.SaveAsync();
  27:  
  28:     MessageBox.Show("Succesfully made a random payment. Check your wallet to see the transactions.");
  29: }

If you are offering a custom Payment Card to your customer, you can integrate digital PaymentCard feature of Windows Phone 8 into your app and synchronize the credit amount, transactions etc. with the records on your server. You can use this i.e. prepaid digital card for buying items from your online or offsite stores through your app installed to the customer’s phone. Synchronization can be made through the agent mentioned in previous section or at the payment time.

2. In-App Purchase (IAP)

Have you tried the game “Dredd vs. Zombies” that is available for free on Windows Phone 8 Store? It is a nice application that perfectly utilizes the In-App purchase monetizing model in a free app. Dredd vs. Zombies is a fantastic game that you can buy levels, guns, achievements etc. by In-App purchase feature. If you haven’t tried yet, it is worth to try for the sake of understanding this topic in action.

With IAP you can sell digital items over Windows Phone Store. Yes, store has the required framework for defining and selling your digital items that are associated with your app. To benefit from IAP feature, first you have to develop and publish the IAP featured app on the store. For testing purposes you can initially publish your app as Beta which takes around 24 hours to pass the store certification. Within the same time you can also define In-App purchasable products on DevCenter which also requires certification process before being published on store.

In figure 9, dashboard of the “In App Purchase Demo” named application on DevCenter is shown.

9
Figure 9: App Dashboard on DevCenter (https://dev.windowsphone.com)

From your application’s dashboard, just switch to the “Products” page (see figure 10.) to see the digital items associated with that application. From this page, you can add new IAP items that are associated with your application. In figure 10, there are two sample items created for demo purposes. You can define two types of IAP item on the store. One is a durable, other is consumable. Durable items are the ones that your customer would buy one time and will use forever, i.e. game levels. Consumables are the ones that are used one time and the customer needs to purchase again for the second time use. i.e. bullets in Dredd game. You can set any price to IAP digital items and customers can make the payment with a credit card.

10
Figure 10: List of IAP products on the application’s dashboard.

In figure 12.a main screen of the sample IAP featured app is shown. If you tap the “Order First Consumable Product” button, items on the store that are associated with your app will be listed. When you upload an app to the store with IAP items, association between items and the app are built over the IDs defined in WMAppManifest.xml (see figure 11). If you change this IDs, association will be lost.

11
Figure 11: ProductID and PublisherID defined in WMAppManifest.xml.

For retrieving the list of associated items that exist in the store, following code is used.

 var ProdList = await CurrentApp.LoadListingInformationAsync();

For purchasing one of the listed digital items, following code can be used.

  1: private async void btnOrderProduct_Tap(object sender, System.Windows.Input.GestureEventArgs e)
  2: {
  3:     var ProdList = await CurrentApp.LoadListingInformationAsync();
  4:     var Prod = ProdList.ProductListings.FirstOrDefault(p => p.Value.ProductType == ProductType.Consumable);
  5:     var Receipt = await CurrentApp.RequestProductPurchaseAsync(Prod.Value.ProductId, true);
  6:     if (CurrentApp.LicenseInformation.ProductLicenses[Prod.Value.ProductId].IsActive)
  7:     {
  8:         // do someting with this license...
  9:  
  10:         // Notify the store that the application has delivered the IAP item to the user. 
  11:         CurrentApp.ReportProductFulfillment(Prod.Value.ProductId);
  12:     }
  13:  
  14:     MessageBox.Show(Receipt, "Fatura", MessageBoxButton.OK);
  15: }

It is developer’s responsibility to store the purchase and logging information. Developer can use the retrieved purchase information (see figure 12.c) to track the customer orders. To keep the log of purchase for further query, developer can create a transaction to store the purchase information on company server over cloud. If the communication between the app on customer phone and the servers on cloud is successful, developer can call the following line

 CurrentApp.ReportProductFulfillment(Prod.Value.ProductId);

to commit the transaction as there is no Internet connection failure etc.

12a 12b 12c
Figure 12.a.b.c: a) Sample application’s main window. b) Order confirmation page. c) License received from the store after calling RequestProductPurchaseAsync method.

Follow more at https://twitter.com/mustafakasap

Comments

  • Anonymous
    April 18, 2013
    The comment has been removed

  • Anonymous
    April 23, 2013
    HRESULT: 0x8032000F ERROR LoadListingInformationAsync call will use your Application ID (on Figüre 11) and fetches the digital items associated with that app on the store. I have uploaded this sample digital items as BETA on the store (not to add demo app listed on the store searches). Which means after 90 days, items will expire. I guess the reason is there is no items left on the store associated with that application ID. Just create new digital items as beta (within 24 hours, in my case less than an hour, they will be pubished) and call the LoadListingInformationAsync function again,

  • Anonymous
    May 16, 2013
    In-app Purchase i need detailed steps to build  IAP application in wp8