Introduction

This article describes a possible solution for the "app trial period problem (isolated storage)".

Background

A couple of weeks ago, I started and successfully submitted my first WP7 app. I built that app with a trial period of 5 days. I told a friend to download that app to review. Everything worked fine - even the "click to buy" appeared after 5 days. Well, he didn't buy it :-) but uninstalled it. Few days later, I found a bug and I told him to review that again. "Look at that!!!" The trial period was reset!

Well, I found out that if a user uninstalls an app, the isolated storage gets deleted too. So I started Googling for a solution. It took me a whole day but I found something even better than I needed.

Here is what I found: app-license.com provides a webservice based API to register your app together with a trial expiration date and a user id. Now, if the user reinstalls my app, I can make a service call to get the initial trial expiration date. Yeahh! Awesome. But that's not all: I wrote an email to app-license.com because I needed to know more about it. So, I found out that I even can allow my app-users to pay via PayPal. That's exactly what I need. And the fee for that is even cheaper than using Microsoft marketplace. After that, I sign up, rebuild my app and submitted it as an free, non-trial app to AppHub but it didn't get passed through. Microsoft could not test my app because I had 0 days of trial and all they could test was "purchasing". The next step was setting the trial to 3 days and it got passed! After 6 weeks, I had enough downloads and I got paid out... No problems since!

Using the Code

Using the app-license.com SDK v1 for WP7:

  1. First, register at app-license.com, go to myDashboard and register a new app/feature.
  2. You will get a GUID, user and password under "my apps"
  3. Download the SDK and unzip it.
  4. Add a reference to your main phone project.
  5. Add the necessary capabilities in WMAppManifest.xml (identity, networking)
  6. Open app.xaml.cs and paste the following code
  7. Copy the app/featureGuid, the alcUser and alcPassword in the code and you're done.
#region AppLicense.com
        //App-License.com---------------------------------------------------------------
        /* Note:
         * Add Capabilities in WMAppManifest.xml to
         * Capability Name="ID_CAP_IDENTITY_USER"
         * Capability Name="ID_CAP_NETWORKING"
         */

        static App()
        {
            AppLicenseManager.DebugSettings = 
		new AppLicense.SDK.V1.Sandbox.DebugServiceResonse()
            {
                IsPurchasedAfterCheck = false,
                IsPurchasedInitValue = false,
                IsRegistered = false,
                IsRegisteredAfterServiceRespone = true,
                IsTrialPeriodOver = true
            };
        }

        private AppLicense.SDK.V1.Views.StartView purchaseView = null;
        public AppLicense.SDK.V1.Views.StartView PurchaseView
        {
            get
            {
                if (purchaseView == null)
                    purchaseView = new AppLicense.SDK.V1.Views.StartView();
                return purchaseView;
            }
        }

        private static readonly string appGuid = "Look at myDashboard on App-License.Com";
        private static readonly string alcUser = "Look at myDashboard on App-License.Com";
        private static readonly string alcPassword = "Look at myDashboard on App-License.Com";
        private static readonly int trialInDays = 3; //min

        //Turn to false on LIVE Environment
        //You will not get redirected to a live purchase site
        private static readonly bool useAlcSandbox = true;


        private void alcManager_PropertyChanged
	(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            System.Diagnostics.Debugger.Break();
            //Change values in DebugSettings manually to test next steps
            //AppLicenseManager.DebugSettings.IsPurchasedAfterCheck = true;

            if (e.PropertyName == "IsPurchased" || e.PropertyName == "IsTrialPeriodOver")
            {
                if (AppLicenseManager.Instance.IsPurchased)
                {
                    //Ensure correct view
                    if (RootVisual != RootFrame)
                        this.RootVisual = RootFrame;
                }
                else if (AppLicenseManager.Instance.IsTrialPeriodOver)
                {
                    RootVisual = PurchaseView;
                }
            }
        }
        //App-License.com---------------------------------------------------------------END
        #endregion
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    AppLicenseManager.Instance.Init(appGuid, alcUser, alcPassword, trialInDays, useAlcSandbox);
    //check if previous installed
    AppLicenseManager.Instance.TryUpdateTrialExirationDate();
}

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    AppLicenseManager.Instance.Init(appGuid, alcUser, alcPassword, trialInDays, useAlcSandbox);
    AppLicenseManager.Instance.TryUpdateValuesFromServer();
}
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
    AppLicenseManager.Instance.PropertyChanged += 
	new System.ComponentModel.PropertyChangedEventHandler(alcManager_PropertyChanged);
    if (AppLicenseManager.Instance.IsTrialPeriodOver && 
			!AppLicenseManager.Instance.IsPurchased)
    {
        RootVisual = PurchaseView;
    }
    else if (RootVisual != RootFrame)
    {
        RootVisual = RootFrame;
    }

    // Remove this handler since it is no longer needed
    RootFrame.Navigated -= CompleteInitializePhoneApplication;
}

The method AppLicenseManager.Instance.TryUpdateTrialExirationDate() actually does the whole work. If you look at the source, you'll see that it tries to get the first time trial expiration date. If the date is not available, it will register this feature and store the date. When the trial period for the registered feature is over, the SDK automatically leads the user to the purchase view.

Testing Your Code

The SDK provides the ability to test your code. As long as you debug your code, you should set:

private static readonly bool useAlcSandbox = true; 

You can then use the AppLicenseManager.DebugSettings however you need to. You even get redirected to a sandbox purchasing site where you can simulate real purchasing.

Points of Interest

If you also want to use app-license... I made myself a checklist to remember:

  • Set min trial period to 3 days.
  • Set capabilities (identity, networking) in the manifest.
  • Ensure that environment is not sandbox.
  • Double-check my app guid, user and password.
  • Submit as free/non-trial app.

My next app will include two different categories which I'll try to license separately. I'll post it when I get it done.

One more thought: I personally use this SDK for WP7, but since it is webservice based, it should be possible to use it on all other platforms too.

History

  • 20th June, 2011: Initial post
推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"