Monday, April 8, 2013

iOS In-App Purchases

This is hopefully a concise getting started with in-app purchases article. Five Lakes Studio has had a fair amount of success with leveraging in-app purchases, and I wanted to share some of the lessons we have learned along the way and also share some code to help make basic in-app purchases a little easier.  This article focuses on non-consumable purchases with built-in product (app) delivery.

Setting Up Your Account


In order to use in-app purchases you have to complete several steps.  A good guide to how to do this is  TN2259 Adding In-App Purchase to your iOS and Mac Applications.   I would recommend taking some time and reading it thoroughly.

One of the key things you need to do is make sure your app has a specific AppId such com.appleseedinc.MyGreatApp.   If your current AppId is using wildcards (".*") you will need to replace it with a fixed AppId and regenerate and reapply the provisioning profiles.  This is because in-app purchases can't be shared across multiple apps.

Creating Test Accounts


You will also need a test account.  These can be created using your iTunes Connect account.




In order to test with the test account, you will need to logout of your current iTunes AppStore account.  You can do that in the "Settings" app under "iTunes & App Stores".


However, don't try to login with the test account through the Settings app.  The test account is only valid in the sandbox environment.  In order to use it, you enter it from within you app when you initiate the in-app purchase.  It will then ask you to login and then you can use the test account you just created.  Once you do this, you can logout of the test account through the Settings app.

Setting up In-App Purchases


You setup the items you want to be purchasable via iTunesConnect.  


This includes picking the type of in-app purchase, it's product id used to reference the purchase from within you app, pricing, and finally the actual text displayed to the user during the purchase process.

This article focuses on Non-consumable In-App Purchases.  These type of purchases only need to be purchased once by users. They do not expire or decrease with use and they can be restored.

Purchasable items need to be approved by apple, and they must include a screenshot.  When you define a new release of an app you can pick which new in-app purchases are available in the app.

It's App Time


Now it's time to start doing work in the app.  At this point, you should have your AppId provision profile set, a test account setup, and one or more non-consumable purchases configured in the App Store through iTunesConnect.  The StoreKit is used to communicate between your app and the AppStore.


The simplest type of in-app workflow to implement is for built in product delivery.  The workflow looks like:


The other workflow is a server based authentication workflow which is significantly more complicated and isn't a focus for this article.

I have made available a class called FLOStoreManager that helps manage the built in product deliver workflow and is part of the Five Lakes Studio Open Library project on GitHub.

FLSOpenLibrary


I'm happy to make FLOStoreManager available under the MIT license as part of the Five Lakes Studio Open Library on GitHub.  The FLOStoreManager class does most of the work to manage the in-app purchase process.   I suggest you download it and at least use it as an example.  

NOTE: The FLOStoreManager makes reference to featureId which is equivalent to to the App Store productIdentifier.

There are 3 main parts to the in product delivery process: Download, Present, and Purchase.

Downloading Purchasing Information


The in-app product definitions are stored on the App Store and must be download to the app before presenting or trying to purchase the item.  This is a download of the product information or meta-data such as product price.   Apple enforces this through the App review process so don't try to skip this step even if you think you can just embed all the meta-data in the app.  Apple still requires your to download and honor this information as it exists in iTunesConnect.

The product definitions contain information such as product description and price. In order to fetch the product definitions, the app needs to know the product ids in advance.  There is no method to query the product ids from the App Store.  This means the App needs to know the product ids by either hard coding them or by other means such as downloading them from a server.

The SKProductsRequest class is used to fetch the product definitions for a set of feature id's.  The FLOStoreManager wraps this in a handy method called startAsyncFetchOfProductForFeatureList.

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSSet *featureSet  = [[NSSet alloc] initWithArray:@[@"ProductId1", @"ProductId2"]];
    [[FLOStoreManager defaultManager] startAsyncFetchOfProductForFeatureList:featureSet];
}

This implementation also does some handy work for you automatically:
  • Auto retry on failed attempts
  • Sends an NSNotification (kFeatureListReady) when the feature list has been successfully retrieved.
  • If the feature list has already been retrieved and matches the given feature then it will only try and update the list once a day.   This is handy since it is called in applicationDidBecomeActive which may get called multiple times as users enter and leave the app.
  • Keeps track of the "registered" features and the product information associated with them
I usually request the product information during applicationDidBecomeActive so it will be downloaded and available as soon as is possible so the purchasable items can be presented to users.

    Present Purchasable Items


    It's up to you to decide how to present the in-app purchases to your users.  However, the App Store uses UIAlert messages which you can not control other then through some text customization.  These customizations are done through iTunesConnect when defining the in-app purchase.

    Picross HD - Daily Puzzle Pack In-App Purchase
    You also shouldn't present purchases for items whose purchasing information hasn't been downloaded.  Apple can reject your app if you try to do that.

    One of the things you are going to want to know from the server is the price of the item.  This can vary based on the country and also can be changed in iTunesConnect.  FLOStoreManager has a handy routine to allow you to retrieve the localized price of the product formatted in a nice string.

    NSString *price = [[FLOStoreManager defaultManager] formattedPriceForFeatureId:@"ProductId1"];
    

    You will also want to take into account some other factors in the UI such as:
    • The act of purchasing an item is done asynchronously so you will probably want something to indicate when a purchasing is in progress,
    • You will need to handle the notifications when the purchase either completed or failed. 

    Purchase


    The SKPaymentQueue is used to initiate a purchase.   It's easy to initiate a purchase, but it does require some tricky handling of the payment queue.  FLOStoreManager tries to make this really easy.  You just call startAsyncPurchaseOfFeature to begin the purchase:

    [[FLOStoreManager defaultManager] startAsyncPurchaseOfFeature:@"ProductId1"];
    

    Once the request is completed, one of two NSNotifications will be sent:
    • kFeaturePurchased is sent if the purchase is successful. The notification object with be the featureId NSString
    • kFeaturePurchasedFailed is sent if the purchase failed.  The notification object with be the featureId NSString
    FLOStoreManager also keeps track of which product ids (features) are in the process of being purchased.  This is handy when updating or displaying a view and you need to know if something is being purchased.


    if( [[FLOStoreManager defaultManager] isFeatureBeingPurchased:@"ProductId1"] )
    {
        // The feature is in the process of being purchased
    }
    
    if( [[FLOStoreManager defaultManager] isAnyFeatureBeingPurchased] )
    {
        // Some feature is being purchased, we don't care which one
    }
    

    One of the limitations with FLOStoreManager is that it doesn't try to do purchase receipt validation. There is a vulnerability in iOS 5.1 and earlier related to in-app receipt validation.   It is not a simple topic to validate a receipt.  Apple has a handy article that talks through the "In-App Purchase Receipt Validation on iOS".  If people are willing to go through the hassle to hack my app to save a buck or two then so be it, I don't think they would be willing to pay for it anyway.  Perhaps some day they will change there ways.

    You will also need to handle the condition of a purchase request that gets completed after the user has left your app.  In order to handle this case, one of the first things the app should do is setup the  SKPaymentQueue in application:didFinishLaunchingWithOptions by adding an observer.  This needs to be done so the app can receive payment notifications from the AppStore.  This is all taken care of by FLOStoreManager just by getting the defaultManager.

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [FLOStoreManager defaultManager];  // Allows us to receive AppStore notification
    }
    

    Once the user starts purchasing items, how do you track what has been purchased?

    Purchase Tracking


    It is up to the app to figure out how to store and keep track of purchased items.  The StoreKit does provide a method called restoreCompletedTransactions which is available as part of SKPaymentQueue  to restore non-consumable purchases.  However, it requires that the user provide their authentication to the Apple Store.  So it's usually called in response to an explicit action by the user to restore purchases.

    FLOStoreManager exposes the ability to restore purchases through its own restoreCompletedTransactions method.  Using  FLOStoreManager also has the added benefit of sending kFeaturePurchased notifications for items that where purchased and needed to be restored.  It will also send a kPurchaseRestoredCompleted notification after all items have been restored.

    The other big advantage of FLOStoreManager is it has a built in mechanism to keep track of non-consumable purchases.  It uses the built-in keychain to keep track of purchases.  The nice thing about the keychain is that it persists across deletes of the app.  You can also instantly query FLOStoreManager to see what has been purchased.

    if( [[FLOStoreManager defaultManager] isPurchased:@"ProductId1"] )
    {
        // The feature has been purchased
    }
    

    Conclusion


    Wow you made it this far.  This turned out to be a wee bit longer then expected, but I hope you found it useful.

    Please feel free to contribute to the FLS Open Library.  I wasn't planning on making this open source so it wasn't designed to be general use, but I think it provides a good start and example.  It also contains a lot more functionality then discussed here including an extension to handle consumable purchases.

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your in-app purchase experiences.

    Thanks for reading and be sure to visit us at Five Lakes Studio.

    References


    https://github.com/FiveLakesStudio/FLSOpenLibraryIOS.git
    TN2259 Adding In-App Purchase to your iOS and Mac Applications
    In-App Purchase Programming Guide
    In-App Purchase Receipt Validation on iOS
    iPhone Tutorial – In-App Purchases By Mugunth Kumar


    Sunday, April 7, 2013

    Quick Tip: How to show source code in the blog

    I have been trying different solutions for showing source code in my blog.  This has been a little harder by the fact I'm trying to show Objective-C.  I have finally found just the trick. It's http://hilite.me/ by Alexander Kojevnikov.  It has a very simple copy/paste interface that just works.  You can also do some customizations and pick between may different styles.

    Using it is as simple as:
    1. Paste your source code
    2. Hit Highlight
    3. Copy and paste the HTML


    You can also customize the embedded css style information and pick the language.  I added a font size style to the css "font-size:small;" and here is what it looks like:

    - (void)alertViewCancel:(UIAlertView *)alertView
    {
        if( m_alertBlock != nil )
        {        
            m_alertBlock( kAlertViewCanceled );
            m_alertBlock = nil;        
        }    
    }
    

    The nice thing about this solution is that everything needed is embedded in the HTML block so there is no setup required on the blog itself.

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear if this was useful and what you do to show source code on the web.

    Thanks for reading and be sure to visit us at Five Lakes Studio.

    Wednesday, March 13, 2013

    Cocoa Debugging Tip


    I'm attending my local Ann Arbor CocoaHeads meeting tomorrow, and the topic is
    Objective Tips.  So I thought I would share a tip.

    What do you do when you get a crash due to an uncaught exception such as:

    2013-03-13 13:30:10.186 Picross[43233:1303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AppDelegate crash]: unrecognized selector sent to instance 0xc04de10'*** First throw call stack:
    (0x355b012 0x32ffe7e 0x35e64bd 0x354abbc 0x354a94e 0x3313663 0x12f54 0x3f0153f 0x3f13014 0x3f042e8 0x3f04450 0x926b5e12 0x9269dcca)
    libc++abi.dylib: terminate called throwing an exception

    This can get really frustrating as you need to figure out where in your code it crashed.  Debugger to the rescue.  In the call stack, you can find the first "low" value.  This usually represents your code.  Then you just do a symbol lookup on that value.  Such as the following when using LLDB.
    im loo -a 0x12f54
     This does a image lookup which gives a nice dump including the file and line number of the offending code:

    Address: Picross[0x00012f54] (Picross.__TEXT.__text + 67540)
    Summary: Picross`__57-[AppDelegate application:didFinishLaunchingWithOptions:]_block_invoke112 + 52 at AppDelegate.m:216

    You can see from this dump that the offending code was at line 216 in the AppDelegate.m and was from a block where I was calling a selector that didn't exist.


    I also find this GDB to LLDB guide to be a handy reference of the commands available in LLDB.

    I hope this short quick tip was helpful.  Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your experiences with the debugger or any tips you might have.


    Monday, October 22, 2012

    GameCenter Turn Based Matches


    We have been looking and doing a major overall to Euchre HD.  In particular, we are looking at
    leveraging GameCenter's turn based games.  Right now we use basic Game Center matchs, but there lots of good benefits with being able to leverage the turn based capabilities.  The two big benefits we want are:

    • Support for "live" and "non-live" matches (turn based)
    • Support for Timeouts
    • Improved Game Center match UI

    A really good example to get started with Game Center Turn Based match's is Beginning Turn-Based Gaming with iOS 5 by Jacob Gundersen.  Some API's have been changed in iOS 6, but it is still a really good tutorial.

    This was my first real experience working with the Turn Based API, and I wish I would have know the following going into the project.

    Passing Turn To Yourself

    It turns out that a match participant may "pass" the turn (baton) to themselves.  I had assumed that wouldn't be allowed, but it turns out the API does allow it, and it definitely simplified some of my game play logic.

    The only catch is that other players won't be notified of the changes to the Game State when you pass the game baton to yourself.

    Participant Timeout (new in iOS 6)

    I thought that when a player timed out their participant matchOutcome would get set to GKTurnBasedMatchOutcomeTimeExpired.  However, it turns out you have to determine this condition yourself and set the appropriate matchOutcome for the participant.

    Another interesting case is when a participant is in a matching state.  The timeout isn't applied against that unmatched participant.

    Changes to Authentication

    iOS 6 depreciated the old authenticateWithCompletionHandler and replaced it with GKLocalPlayer.localPlayer.authenticateHandler. They changed the block callback a bit, but other then that it looked equivalent. However, the authenticateHandler in iOS 6 won't present the login view if the user cancels it. I realize game center will auto lockout an app after 3 cancel attempts, but I'm talking about just 2 attempts. If they cancel the login, they have to leave the app and come back before Game Center will present the login even through the authenticateHandler is getting set again. I was able to workaround the issue by continuing to use the depreciated authenticateWithCompletionHandler.

    The reason this is important for Euchre HD is that it requires Game Center for multi-player. The app tries to authenticate to game center on launch, but if the user cancels we don't ask them at launch again so they won't get nagged. What we do is show a Game Center Login button if they aren't logged in when they select multi-player.

    Number of Players in a Match (Updated 11/1/2012)

    One problem we have found is that if you have a variable number of players and then start a match with "auto-match", Game Center will start the match with the "minimum" number of players.  It does this even if the Game Center match-making UI is showing auto-match spaces for more then the minimum number of players.

    Let me try and explain this a bit better. One thing we do in Euchre HD is to allow people to pick the number of human players they want in a match.  They can pick from 2 to 4 humans.  Euchre is of course a 4 person game, but we fill in the remaining spots with computer players.

    Game Center provides a really nice interface for forming a multi-player game.  Here is an example, that shows a 2-4 player game.


    The play can add or remove players players as long as they stay within the defined min/max limits.


    However, if the player selects "Play Now" and "Auto-match" is selected a match will only be formed with the minimum number of players.  In the above example, even through 3 players are being shown as Auto-match, Game Center will only start a 2 player match.

    Here is the example code showing how the request is created.

        GKMatchRequest *request = [[GKMatchRequest alloc] init];
        request.minPlayers = 2;   
        request.maxPlayers = 4;
        request.playersToInvite = playersToInvite;
        request.playerGroup = 0;
        request.defaultNumberOfPlayers = 4;
    As anyone else encounter this issues?  Any good suggestions on how to handle it?  I would rather not write my own custom matchmaking interface.


    Conclusion

    Overall, turn based Game Center is a huge help in building multi-player games.  I was still surprised about how many special cases have to be handled and how much testing is needed.  I guess multi-player is just hard.  :)

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your experiences Game Center.  I hope this was helpful.

    Thanks for reading and be sure to visit us at Five Lakes Studio.







    Friday, August 31, 2012

    NSMutableArray Weak References


    I had the need to store non-retained objects to prevent a retain lock loop.  I found a couple of different ways to do this.  I started by trying to implement a derived version of NSMutableArray.  There is a nice example by Mike Ash on how to do implement a NSMutableArray.  It would be fairly easy to modify his example to remove the retain/release pieces.  However, I was a bit nervous when it came to testing the code and my changes.  While he has a test in place, the test wouldn't work if the objects weren't retained.

    So I kept looking and found a great example on Stack Overflow by Mark Powell that takes advantage of Core Foundation's Mutable array.


    I haven't done much with Core Foundation services, but I have to say that it's amazing how easy this was to do.  I modified the example above to work with ARC so there is a __bridge cast for the returned CGArrayCreateMutable. I put this along with my changes in a small class and header file which can be downloaded at Download NSArrayWeakReference Source.

    I hope you found this helpful.

    - Tod

    Monday, August 27, 2012

    Japanese App Store Withholding

    I learned an interesting lesson this weekend.  I was reviewing our AppStore financial results and I noticed an interesting entry:



    After a little bit of research, I learned Apple withholds a 20% tax on Japanese sales.  In order to eliminate this tax, you need to file some tax forms with the Japanese government and US government.   Apple helps with this process by providing and submitting the forms.

    David Smith has a nice article on "Understanding Japanese App Store Withholding" that goes into more detail.

    I filled out the forms this weekend (8/26/2012), and I will report back on when it takes effect.  I would love to hear about year experiences with this process.


    Monday, August 13, 2012

    Subversion to Git

    A couple weeks ago Ken and I decided to make the plunge from Subversion to Git.  The main catalyst for this was some Hype generated files I wanted to check into Subversion.  Unfortunately, every time you generate the HTML for a Hype project it blows away the folder structure, which removes the .svn folder and gets subversion all confused.  I understand there are newer versions of Subversion that resolve that issue, but I decided to just do the switchover to Git given that's where it seems most people are going today.

    Picking a Hosting Provider


    Given Ken and I work together on projects we need a version control hosting provider. We currently use Beanstalk for subversion, and we have been very pleased with them.  However, I decided to take a look at the available options.  I took a serious look at GitHub and Bitbucket.  I opted to go with GibHub for our main git repository.  I really liked its interface and how it links your personal account to your corporate account.  Plus it has a big user following.  Several reviews I read also talked about GitHub being more performant and a step ahead of Bitbucket.  However, that info could be a bit dated by now.

    We opted for GitHub's $25 per month plan for 10 private repositories.  However, I also created a Bitbucket account as they have free unlimited private repositories.  I'm using bitbucket to host paid for 3rd party assets, and I'm using GitHub for our source.

    GUI Tools


    While lots of people use the command line to manage Git, I prefer having some nice GUI tools for my day to day work.  There are several tools out there, but I ended up going with SourceTree.  It seems to be the most complete tool for managing subversion repositories.  I also used GitHub's tool for awhile to get up and started, but SourceTree feels like a more complete and powerful solution.

    Migration


    I decided not to do a full history migration from Subversion to Git.  I opted to just migrate the latest revision.  We are a small shop, and it sounded like more trouble then it was worth to preserve the entire history.

    I still made a big mistake though.  I just took all our source and added it to Git, just like it was setup in subversion.  We have over 1.5 GB of source including game assets such as images, sounds, and puzzle data.  This is when I learned that GitHub doesn't recommend repositories over 1GB.

    I learned firsthand how painfully slow it was to pull down a new large repository, and I was also worried that we would get flagged by GitHub for having too large of a repository.  I also found I would occasionally get an error downloading the new repository and would have to start over.

    The solution was to breakup the old subversion repository into several smaller repositories and submodules.  I haven't had any issues with these smaller repositories.

    Submodules


    I decided to break up the old single subversion repository into several smaller repositories.  Each iOS app we make has its own GIT repository, and we use submobiles for shared components.


    This is an example of the submodules used for Hashi, a new App we are working on.


    What's nice about using submodules is that the parent project references an explicit revision of the submodule.  So if a submodule is updated in a different project, it won't break the current project.  This allows you the time to upgrade the project at your own connivence.

    One thing we learned is that you have to be a little careful when adding a submodule to your project through SourceTree.  By default SourceTree was adding the user's login to the submodules URL. This of course causes issues for other people trying to work with the submodule.


    You just need to remove the user's login from the URL.  If you forget, you can manually change the .git/config to reference the correct submodule URL.

    Conclusion


    It took me a weekend or two before I started to understand Git.  I'm still far from an expert, but I am getting more comfortable with it.  One of the sites that really helped was from Mark Lodato and his Visual Git Reference.  Stuart Ellis also has a really nice basic getting started guide to using Git.  And finally the must read Git Reference on Branching and Merging.

    Please feel free to follow me on twitter at @fivelakesstudio. I would love to hear about your experiences on using or switching to Git. Let me know if you found this useful.

    Thanks for reading and be sure to visit us at Five Lakes Studio.