Visually Located

XAML and GIS

Increasing in app purchases in your Windows Phone apps

There are a few ways to increase the rate of in app purchases. One of these ways is to show a message prompt to the user explaining that an in app purchase is available and what the user can get from it. In a previous post I explained how to use Telerik’s RateApplicationReminder to increase reviews of your app. The RateApplicationReminder is great because it just works. No, really. No need for you to determine if you should show a reminder to rate the app. It handles all of the logic and it navigates the user to rate your app. Another benefit of the RateApplicationReminder is that it is built on a framework for showing reminders. This framework can be extended to create your own reminders.

The is a decent framework to build reminders on. It has one abstract method, GetDataFilePath. This is just a file name for the data that will be saved. It has two virtual methods that can be overridden, but the power is in the properties that it has

// Summary:
// Setting this property to True will display a checkbox in the reminder that
// will allow users to skip further notifications.
public bool AllowUsersToSkipFurtherReminders { get; set; }
//
// Summary:
// Gets or sets a value indicating whether further reminders will be skipped.
public bool AreFurtherRemindersSkipped { get; set; }
//
// Summary:
// Gets the last date when reminder was displayed.
public ReminderBase DateTime? LastReminderDisplayDate { get; }
//
// Summary:
// Gets the number of app runs after the last reminder was displayed.
public int NumberOfUsagesAfterLastReminder { get; internal set; }
//
// Summary:
// Gets the persisted data.
protected T PersistedData { get; }

These properties a big part of when and if you should show a reminder. The RateApplicationReminder has some additional properties that dictate how many times (or the time frame) the app should open before showing a reminder. These properties are great for an in app purchase reminder as well. We’ll start there for our reminder

/// <summary>
/// Gets or sets the number of application runs on which the reminders will be displayed.
/// </summary>
public int? RecurrencePerUsageCount { get; set; }
 
/// <summary>
/// Gets or sets the time period on which the reminders will be displayed.
/// </summary>
public TimeSpan? RecurrencePerTimePeriod { get; set; }
 
/// <summary>
/// Gets or sets the information that will be displayed in the message box.
/// </summary>
public MessageBoxInfoModel MessageBoxInfo { get; set; }

The MessageBoxInfo determines what text should be shown to the user when the reminder is shown.You’ll want to have some default values for this.

public InAppPurchaseReminder()
{
    MessageBoxInfo = new MessageBoxInfoModel
        {
            Buttons = MessageBoxButtons.YesNo,
            SkipFurtherRemindersMessage = "Do not show this reminder again",
            Title = "In App Purchase"
        };
}

The ReminderBase class has the method, ShowReminderMessage, to show the reminder. When this is called the reminder will be shown even if it should not be. To ensure that the reminder is only shown when it is suppose to, the RateApplicationReminder has a Notify method that you call instead. The Notify method is where it is determined if it should be shown or not.

/// <summary>
/// Notifies the user of the in app purchase.
/// </summary>
public void Notify()
{
    IncreaseUsageCount();
    if (ShouldShowReminder() == false) return;
 
    var args = new CancelEventArgs();
    OnShowing(args);
    if (args.Cancel) return;
 
    ShowReminderMessage(MessageBoxInfo);
}
 
private void IncreaseUsageCount()
{
    // If the reminder has been shown at least once, and we're tracking usage count
    if (LastReminderDisplayDate.HasValue && RecurrencePerUsageCount.HasValue &&
        RecurrencePerUsageCount.Value > 0)
    {
        PersistedData.NumberOfAppRunsAfterLastReminder++;
        SavePersistedData();
    }
}
 
private bool ShouldShowReminder()
{
    if (LastReminderDisplayDate.HasValue && AreFurtherRemindersSkipped) return false;
 
    // priorty on usage count, calculate first
    if (RecurrencePerUsageCount.HasValue)
    {
        var numUsage = LastReminderDisplayDate.HasValue
                           ? NumberOfUsagesAfterLastReminder
                           : ApplicationUsageHelper.ApplicationRunsCountTotal;
 
        if (numUsage >= RecurrencePerUsageCount) return true;
    }
    // if no usage count, or the value has not been met, try time period
    if (RecurrencePerTimePeriod.HasValue)
    {
        var timeSpan = DateTime.Now - (LastReminderDisplayDate.HasValue
                                           ? LastReminderDisplayDate.Value
                                           : ApplicationUsageHelper.InitialInstallationDate);
        if (timeSpan >= RecurrencePerTimePeriod.Value) return true;
    }
 
    return false;
}

The Notify method calls the OnShowing method to notify you code that the dialog is going to be shown. It also gives event listeners a chance to stop the reminder from showing. If everything works out well, it shows the dialog. Inside IncreaseUsageCount, we call the SavePersistedData method. This will save any information that is in the ReminderBaseDataModel that is part of the class. For this reminder, we incremented the NumberOfAppRunsAfterLastReminder property. When the SavePersistedData method is called, it calls into the GetDataFilePath so it knows where to write the file of information.

/// <summary>
/// Gets or sets the product ID for the reminder .
/// </summary>
public string ProductID { get; set; }
 
protected override string GetDataFilePath()
{
    if (ProductID == null)
        throw new InvalidOperationException("ProductID property not specified.");
 
    return string.Format("PurchaseReminder_{0}.xml", ProductID);
}

To save the file, we’ll use the product id of the in app purchase. This guarantees us a unique file name for the application. The last thing to do is to show the in app purchase to the user if they decide to hit the yes button. To do this we need to override the OnReminderMessageClosed method.

protected override async void OnReminderMessageClosed(ReminderClosedEventArgs args)
{
    base.OnReminderMessageClosed(args);
 
    if (args.MessageBoxEventArgs.Result != DialogResult.OK) return;
 
    // Show the in ap purchase to the user if they tapped the yes button
    try
    {
        await CurrentApp.RequestProductPurchaseAsync(ProductID, false);
 
        if (CurrentApp.LicenseInformation.ProductLicenses[ProductID].IsActive)
        {
            AreFurtherRemindersSkipped = true;
 
            // If the IAP is a durable do the following
            // CurrentApp.ReportProductFulfillment(ProductID);
 
           // TODO: Fire an event thgat states that the purchase was made.
        }
    }
    catch (Exception)
    {
    }
}

Using the reminder is pretty simple. Here is an example to remove ads.

var reminder = new InAppPurchaseReminder()
{
    AllowUsersToSkipFurtherReminders = true,
    ProductID = "RemoveAdProductID",
};
 
reminder.MessageBoxInfo.Content =
    "Did you know that you can remove the ads and help support this app? Would you like to remove the ads now?";
reminder.MessageBoxInfo.Title = "Remove ads?";
// show on every tenth open of the app
reminder.RecurrencePerUsageCount = 10;
reminder.Notify();

You can download the complete file here. Good luck!

Increasing app reviews with Telerik’s RateApplicationReminder

I have seen a few blog posts that explain how to prompt a user to rate your app after a few visits. These posts describe how to store a setting for how many times the app has been opened and whether the prompt has been shown. Some use a custom message box and some use the built in MessageBox. There have even been NuGet packages for this. I have to wonder, Why are you not using Telerik’s RateApplicationReminder? After all, if you do not have Telerik’s controls, you might be doing something wrong.

Telerik’s RateApplicationReminder is a great tool to have. It allows users to ignore further reminders. It allows you to specify if the reminder should not be shown any more if the user taps the yes button. The text it displays is fully customizable, including the buttons. It also allows you to show the reminder based on number of times the app has opened or days from the last reminder. Oh, and it helps increase app reviews.

The RateApplicationReminder is used in conjunction with the ApplicationUsageHelper. The ApplicationUsageHelper tracks how many times a user has opened the app on a certain version. It’s a simple tool to use, insert one line of cod in the Launching and Activated event of your Application.

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    ApplicationUsageHelper.Init("1.0.0");
}
 
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    ApplicationUsageHelper.OnApplicationActivated();
}

It is required to use the ApplicationUsageHelper. With this in place we can take advantage of RateApplicationReminder to prompt users to rate your app. When you create the reminder, specify how it should be shown (or not shown) based on user interaction and the content of the prompt.

var reminder = new RadRateApplicationReminder
    {
        // Show the checkbox to the user to not show again
        AllowUsersToSkipFurtherReminders = true,
        // Do not show again if they press yes
        SkipFurtherRemindersOnYesPressed = true
    };
reminder.MessageBoxInfo.Content = "Would you like to rate this awesome app?";

Once you specify how to handle user interaction, set when the reminder will be shown. You can specify to show the reminder by setting the RecurrencePerUsageCount property, the RecurrencePerTimePeriod property, or a combination of both. You never need to check if you should show the reminder. All you need to do is call the Notify method. Telerik handles if the reminder should be shown.

If the reminder has never been shown these properties are based on the number of times the app has been opened or when the app was first opened. These values of how many times and when the application was opened come from the ApplicationUsgaeHelper.

If the reminder has been shown, the RecurrencePerUsageCount property specifies how many times the Notify method should be called before the reminder is actually shown. The RecurrencePerTimePeriod property specifies a TimeSpan from the last time the reminder was shown. You can set both properties. When this happens the reminder will first see if the RecurrencePerUsageCount has been met, if it has not, it will then check if the time since the reminder was last shown is greater than sRecurrencePerTimePeriod.

I like to use both properties, but not at the same time. It’s possible that a user may open the app 10 times in a day and I do not want to prompt them all the time. To take advantage of both settings, I check if the reminder has been shown before. You can do this by checking the LastReminderDisplayDate. This is a nullable DateTime and will be null if the reminder has never been shown.

if (reminder.LastReminderDisplayDate.HasValue == false)
{
    // reminder has not been shown before, allow the APP to open five times
    // before showing the reminder
    reminder.RecurrencePerUsageCount = 5;
}
else
{
    // reminder has been shown, show once every three days
    reminder.RecurrencePerTimePeriod = TimeSpan.FromDays(3);
}

In the snippet above I specify that the first time the reminder should be shown is when the app has been opened five times. Afterwards, it will open every three days. The following prompts from the reminder are only if the user taped the no button and has not checked the option to ignore future reminders. Remember, all of this is handled for you. The last thing to do is “show” the reminder.

// only shows the reminder when/if it is suppose to!
reminder.Notify();

Remember, no code to check how many time the app has been opened. No code to save/check if future reminders are disabled. You code is very simple. When we put all the snippets together we get the following

var reminder = new RadRateApplicationReminder
    {
        // Show the checkbox to the user to not show again
        AllowUsersToSkipFurtherReminders = true,
        // Do not show again if they press yes
        SkipFurtherRemindersOnYesPressed = true
    };
reminder.MessageBoxInfo.Content = "Would you like to rate this awesome app?";
 
if (reminder.LastReminderDisplayDate.HasValue == false)
{
    // reminder has not been shown before, allow the APP to open five times
    // before showing the reminder
    reminder.RecurrencePerUsageCount = 5;
}
else
{
    // reminder has been shown, show once every three days
    reminder.RecurrencePerTimePeriod = TimeSpan.FromDays(3);
}
 
// only shows the reminder when/if it is suppose to!
reminder.Notify();

Why do you not have Telerik's Phone controls for yours Windows Phone dev?

If you are doing Windows Phone development and you do NOT have Telerik’s Windows Phone control toolkit you are doing something wrong. For the price of a Windows Phone Store developer account (when not discounted) you can join Nokia’s Premium Developer Program. I have been in the program for almost a year and I’ll be renewing my subscription. The Premium Developer Program gives you the following:

  • A Windows Phone Dev Center  account (normally priced at $99, currently $19). You get a token for one year of membership to the dev center. This token can be used at any time. If you already have an account, you can use the token when the account expires.
  • A free license for Telerik RadControls for Windows Phone. These controls and tools are priced at $99 per year (if you wish to receive updates). I have found this toolset to be very valuable. I have only used a few of the components, but it has well passed the $99 value.
  • 12 months of access to Buddy.com. This cloud solution gives you one year of access to 1 million API calls per month. Buddy.com values this at up to $1200.
  • Two tech support tickets with Nokia. a $198 value.

I have not used Buddy.com, but when Parse offers the same plan for free, I cannot say you get much value from the offered plan from Buddy.com. I have yet to use the tech support tickets so no value there. The price for a dev center account is normally $99. They currently have an offer (ending in about a week) that lowers the price to $19. Being in the program did save me the normal $99 cost to renew my dev center account. That alone made the Premium Developer Program worth the cost. The real value for me is the Telerik RadControls license. I plan on doing some posts on a few of their controls that I have used. I can easily say that this toolset, along with the free Windows Phone Dev center account makes the Nokia Premium Developer Program well worth it.

This toolset is a must have for any Windows Phone developer.

Disclaimer: I am not, and was not paid by Telerik nor Nokia for this post (but I wouldn’t mind if I do :).

My first days with Xamarin iOS

I recently started a project in which I wanted to create an iOS app using Xamarin. This project will require me to create a binding to a third party iOS SDK, overcome a complex corporate network and prove to myself that Xmarin is a stable platform for development. I’ve only just begun this adventure, and I have already had a fare share of roadblocks to overcome. Here is a short description of the adventure that I chose.

I was very fortunate to talk with Xamarin while at the Microsoft Build conference in June. I was invited to a private dinner and was able to speak with Anuj Bhatia, Erik Polzin, and Xamarin’s own CEO and cofounder, Nat Friedman. Every one of them had heard of Schneider Electric and were excited to hear about how Xamarin could help us out. I’m glad that I also had Daniel Rouleau along with me as he has been helping lead up the development effort of our latest mobile platform.

I’ve done a bit of research on Mono/Xamarin before. I attended a Mono meetup at last years (2012) Build conference but never played around with it. After talking with these guys I was jazzed to start playing. I downloaded and installed Xamarin Studio and the Xamarin plugin for Visual Studio. Let’s me honest here. No one wants to use Xamarin Studio when they have been using Visual Studio for many years. Xamarin knows this and charges more (three times more) for their Visual Studio plugin. Building iOS apps on a Windows machine requires a Mac for compiling and deploying. Fortunately, my team recently got a new Mac Mini.

This Mac was still in it’s box, so I was able to do the unboxing and setup of the device.

Disclaimer: I’m not a Mac person. I’m not an iPhone person. The last time I used a Mac was in college when all of the PCs were already being used.

This Mac would be setup in a room and put on our “non corporate” network. We have a somewhat complex network at my work. We have two internal networks and domains. Anything corporate is within one network while anything we use/purchase is on another network. Communication between these is not ideal. The unboxing and setup was pretty smooth. I did need help from a fellow developer to download xCode from iTunes as I do not have an account.

The install of Xamarin on the Mac went pretty smooth by following the documentation although the docs do need some updated screen shots as it seems their installer has been updated. There were some confusing points like whether I needed to setup a proxy on the machine or not. After the installation on the Mac I went to my machine and attempted to connect to the build host (my Mac Mini) but it failed to connect.

image

Turns out that the Mac, like normal PCs, must have a static route configured to allow for communication between our two networks. Unlike Windows machines, you cannot easily configure a static route. You must create a script that gets run every time the machine boots up and then run that script. Once I did that (and entered the IP address rather than the machine name) I was able to access the machine!

image

I was able to successfully create and deploy Xamarin’s “HelloWorld” app as well as their “Master-Detail” app. My next steps are building out the bindings for the ArcGIS iOS SDK. If anyone out there already has something, please let me know.