Monday, April 9, 2012

Push Notifications and Urban Airship

I have been considering putting Push Notifications into Picross HD for some time now.  This weekend, I decided to take the plunge and give it a try.  I will try to cover some of the hiccups and things that I have been trying.

Why Push Notifications

Ken and I aren't very good at the marketing side of things, but everyone I talk with about marketing asks if we use push notifications.  I finally decided there must be something to this so let's give it a try.

There are a couple of uses for push notifications that I would like to try:
  1. Notify Picross HD users of new puzzle packs being available.  We plan on releasing one new puzzle pack a month, and we would like to notify users when they are available.
  2. Notify users about our other puzzle games.  This one makes me a bit nervous as I don't wont to spam our users, but I also think many Picross HD users would also enjoy some of our other puzzle games.  I'm figuring to give it a try and see what kind of response we get.
I would be interested in hearing what you use push notifications for or what you like or dislike about push notification uses.

Urban Airship

One thing about push notifications is that you need a service to bridge between you and Apple's push notifications servers.  I considered setting up my own server for this, but I decided to go with Urban Airship for now.  For the level of service I need, their service would be "free" and seemed to be the easiest way to get started with Push Notifications.

Getting Started

Urban Airship has a good getting started guide for push notification.  However, I do have a couple of tips.
Tip 1:  You will need to regenerate your provisioning profiles after you enable push notifications for your existing App Id.  If you don't, you will get an error when trying to registerForRemoteNotificationTypes as the provisioning profiles needs to be configured for push notifications.
Tip 2: The getting started guide walks through the steps of using a AirshipConfig.plist to switch between production and development for the notification servers.  I don't like this technique as it is too error prone.  It's too easy to forget how you have it configured.  They suggest using build scripts to manipulate this file, but I don't like that from a maintenance perspective plus I didn't find a quick example of how to do this.  Fortunately, you can do this programmatically instead of using the AirshipConfig.plist.  Here is an example of how taken from the Urban Airship forums (but modified a bit by me). 

- (void)setupUrbanAirshipPushNotificationsWithLaunchOptions:(NSDictionary *)launchOptions
{
    // Set passed in launch options
    NSMutableDictionary *takeOffOptions = [[NSMutableDictionary alloc] init];
    [takeOffOptions setValue:launchOptions forKey:UAirshipTakeOffOptionsLaunchOptionsKey];

    // Create and set dictionary for AirshipConfig values
    NSMutableDictionary *airshipConfigOptions = [[NSMutableDictionary alloc] init];
    [takeOffOptions setValue:airshipConfigOptions forKey:UAirshipTakeOffOptionsAirshipConfigKey];

    [airshipConfigOptions setValue:@"Application Key" forKey:@"DEVELOPMENT_APP_KEY"];
    [airshipConfigOptions setValue:@"Application Secret" forKey:@"DEVELOPMENT_APP_SECRET"];
    
    [airshipConfigOptions setValue:@"Application Key" forKey:@"PRODUCTION_APP_KEY"];
    [airshipConfigOptions setValue:@"Application Secret" forKey:@"PRODUCTION_APP_SECRET"];

    [UAirship setLogging:YES];

    #ifdef PRODUCTION_PUSH_NOTIFICATIONS
        [airshipConfigOptions setValue:@"YES" forKey:@"APP_STORE_OR_AD_HOC_BUILD"];
    #else
        #warning PUSH NOTIFICATIONS SET TO DEVELOPMENT
        [airshipConfigOptions setValue:@"NO" forKey:@"APP_STORE_OR_AD_HOC_BUILD"];
    #endif
    
    
    [UAirship takeOff:takeOffOptions];
    
    [[UAPush shared] setDelegate:self];
    [[UAPush shared] resetBadge];   //zero badge on startup
    [[UAPush shared] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
                                                         UIRemoteNotificationTypeSound |
                                                         UIRemoteNotificationTypeAlert)];
} 

This can be called from within application:didFinishLaunchingWithOptions.
Tip 3: In order to test notifications you can use the command line utility curl.  However, I ended up using an app called RESTed available on the Mac App Store.  Its UI could be a bit better, but I was able to edit the Push payload easier in RESTed then trying to do it on the command line.  I also found that with curl the payload didn't like being split on multiple lines using line continuations.
Tip 4: Add the application:didFailToRegisterForRemoteNotificationsWithError to your app delegate.  The guide doesn't instruct you to do this, but if something goes wrong during device registration, its very handle to have this method log the error information.

Processing Push Notifications

When processing push notifications it's up to the App to figure out what to do with the notifications (including showing them).  The UAPush class from Urban Airship helps manage push notifications by handling things like badges and parsing of push notifications.   Setting up UAPush is easy, as you can see in the example code above.

In order for UAPush to parse the notifications, you need to pass them to UAPush via its handleNotification:applicationState method.


This was taken from example code for the UAPush.  However, I modified it to remove the applicationState check.   application:didReceiveRemoteNotification can be called before the application has been made active.  However, I still want to display an alert even if we are becoming active.  From what I can tell the method only gets called while the application is being "launch" or "restored", it doesn't get called while the app is backgrounded.  However, if handleNotification:applicationState is called with an inactive state, it won't call its delegate parsing methods.  Which isn't what I wanted.  I want the App to display a notification if the notification is clicked on outside the app.

I still looking into understanding the implications of this, but I think for my purposes (of displaying an alert) it is fine.

Localization Implications

Picross HD is localized into 5 languages so when sending notifications, I would like them to be localized.  However, I haven't figured out how to send a localized push alert  (see "loc-key") without having the text pre-localized and stored in the application's Localizable.strings file(s).

While you can send custom push notifications that are localized, iOS won't know how to display them.  For notifications within the App that isn't an issue because the App has control of that, but when the app is in a background iOS can only display "toast" messages for types it knows about such as alerts.

This means you have to predetermine the messages you might want to send if you want them localized.  You can also supply message arguments to fill in placeholders in the message such as %@.  However, I don't believe the arguments are localized.

Conclusion

I'm still working on the implementation and trying to figure out the types of messages and workflows I want to do.  For example, if I do an announcement of a new puzzle pack some people may be on the old version that doesn't have that puzzle pack available and some may be on the new version that has the new puzzle pack.  In the first case, I may want to provide an option for the use to update to the latest version, in the later case I may want to take them to the new puzzle pack so they can try it out.

I hope this was useful.  Please try out Picross HD and our other puzzle games for iOS.

- Tod

Monday, March 26, 2012

Picross HD Localization - Part II

At a Mobile Mondays meeting in Ann Arbor, Michael Antaran founder of Marvel Apps, was talking about the benefits of localizing AppStore Apps.  That was enough to inspire me to give it a try.

In the first part, I explained that we decided to localize Picross HD into three languages: German, French, and Japanese along with some of the lessons we had learned.  Now that the localized versions have been in the AppStore for about a month, I thought it would be good to share the results along with some other interesting tidbits we learned.

German & French

We didn't see any positive impact to new user growth for localizing in German.


We did see a short term spike in new users for the French version, but after a few days it returned to its normal trends.



I expected to see bigger results for localizing Picross HD into German and French.  I would love to hear back on what other people have experienced when localizing into German and French.   Are these results typical?  Is English just not an issue in those countries for people using iOS devices for puzzle style gaming?

Japanese

We have had great growth in Japan sense we localized.  Japanese New User acquisition is allmost an order of magnitude greater then all other locals combined.  And it continues to grow.  I want to say thank you to all our new Japanese users.


Why the great growth?  Well for starters, I believe Picross as a game style is better know in Japan then it is in other parts of the world.  We also totally overhauled the Keywords for Japanese.  We used keywords that would be meaningfully for the Japanese people.  Even with all that, this totally exceeded my expectations.

iPhone vs iPad

Almost all of our games are Universal apps, and we usually see close to 50/50 spread across iPhone and iPad usage.  For example, in Germany about 55% of Picross HD sessions are run on an iPad.  However, in Japan that number is about 4%.  We where surprised about that difference.  What have other people seen for iPhone vs iPad usage of their apps in different locals?

What's Next

We want to continue to experiment with different locals.  The next version of Picross HD, which is pending Apple approval, will include support for Korean.  We took a similar approach to Korean as we did for Japanese by providing local specific keywords so that should be interesting.

We have also been working on some major updates to Picross HD given its new found growth.  All the puzzles in the next version will have unique solutions and be solvable by logic.  That should help address two of the big feedback items we received from our Japanese users.

We are also looking at how to make the iPhone version even better.   Much of our focus has been on the iPad version, but with this much usage on the iPhone we are going to have to pay even more attention to the iPhone version.

Be sure to give Picross HD a try and let us know what you think.  It's a free download. :)

Thanks,
Tod and Ken
Five Lakes Studio, LLC

Monday, February 27, 2012

Picross HD Localization

At a Mobile Mondays meeting in Ann Arbor, Michael Antaran founder of Marvel Apps, was talking about the benefits of localizing AppStore Apps.  That was enough to inspire me to give it a try.  I spent the last week localizing Picross HD, our best revenue generating App so far, and I thought I would share my experiences thus far.

Languages

Using some metrics and based on the appeal of Picross HD, the first thing I decided was to localize in 3 languages: German, French, and Japanese.


Contractors

We used odesk to find the people to do the localization and that has been a very good experience.  It was really easy to find people to do French and German.  It was a little harder finding someone to do a good job on Japanese. However, everyone we ended up working with was responsive, quick, affordable, offered good advice, and did an all around great job.  It took about a week to get all 3 translations completed.

How to Localize

Before I connected with the odesk people, I first needed to figure out how we wanted to approach the actual localization and how to get the strings extracted.  A great reference for this is on Ray Wenderlich's blog in a Localization article by Sean Berry.  I wanted to keep the localization really simple as I didn't want the odesk people to have to have special tools such as resource editors.  So I put all the strings into a few files I could send to them:
  • description.rtf - Containing the app store description
  • help.rtf - Text for the app help
  • Localizable.strings - App strings, Game Center Leader board Strings, and in-app store strings
I put some extra strings in the Localizable.strings even through they aren't directly used by the App such as the Game Center Strings and in-app store strings.  This just made it easier to communicate with odesk and gave me a good place to manage the strings over time.

I gathered strings from a few different places:
  • From XML puzzle files - Using a XSLT transform (this was a majority of the strings).  The name of each puzzle needed to be localized and we have over 400 puzzles in Picross HD.
  • From each XIB (resource) file - I did this manually.  I didn't want the contractors to have to deal with a resource editor so I just manually added the UILabel and UIButton text into the Localizable.strings file.
  • Look for hard coded strings in the app and added the NSLocalizedString(@"english text", nil) macro for each string needing translation.
Strings coming from a resource file won't automatically lookup their translation via Localizable.strings.  The resource files assume you will localize each resource file separately which I didn't want to do.  So I just added some simple code to the UIViewControllers of each xib that needed to be localized:

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Localize the labels in this view
    //
    for( id foundView in self.rateThisPuzzleButtonView.subviews )
    {
        if( [foundView isKindOfClass:[UILabel class]] )
        {
            UILabel *label = foundView;
            label.text = NSLocalizedString( label.text, nil );
        }
    }
}

In order to do the buttons, I decided to just do those manually as I didn't have that many buttons to do:
    [self.puzzleSuccessTryAgainButton setTitle:NSLocalizedString([self.puzzleSuccessTryAgainButton titleForState:UIControlStateNormal],nil) forState:UIControlStateNormal];
    [self.puzzleSuccessNextButton setTitle:NSLocalizedString([self.puzzleSuccessNextButton titleForState:UIControlStateNormal],nil) forState:UIControlStateNormal];

I also had to adjust the font and/or button sizes in order to accommodate the length of the German text.  This was a little tricky given how some of our buttons worked.  I ended up doing a StackOverflow posting once I figured out how to solve button text wrapping issues.

Lessons Learned

Doing three languages at once was a bit much for the first time trying to localize an app. It would have been better to start with just one language.  There where several mistakes I made that required me to add more work on the localization teams.  Every time I did this, I had to communicate  back with 3 different people and it was just more work then getting it right the first time.  The types of mistakes I made where:

  • When I sent the strings to the localization teams I didn't realize I was missing about 50 puzzles.  The XSLT transform I wrote missed some puzzles.
  • I should have sent screenshots to the localization team up front as they didn't have enough context to do some of the translations.  They ended up doing some redo work once I sent them the screenshots.
  • I often use images for the help screens, but I was missing the original layered image for one of the help screens.  I ended up spending a few hours recreating a help screen so I could replace the text easily.  Save your original layered artwork (especially if it has text in it).
  • Images with text == pain.  I knew this before, but zero thought had went into the idea we might localize this App when we first wrote it over a year ago.  To help this, I wrote some code to dynamically load a localized version of an image file based on the active language.
Overall, this was a very easy effort.  It only took about a week of my part-time schedule to go from nothing localized to having three languages and ready for posting to the AppStore.  Apple's tools and handling of fonts and languages works great.


Next Steps

This just got released to the AppStore so wish us luck.  I will report back when we know more how this experiment went.  Ken and I are hoping to see a noticeable uptick and we hope more people enjoy Picross HD in their native language.

Be sure to give Picross HD a try and let us know what you think.

Thanks,
Tod and Ken
Five Lakes Studio, LLC



Thursday, February 9, 2012

Michigan Swimmers Using English Channel Record Attempt to Raise Money for ALS Cure

Six Michigan women are training to break the world record for fastest two-way relay swim crossing of the English Channel to raise money to find a cure for ALS, or Lou Gehrig’s disease.

Michigan Swimmers Using English Channel Record Attempt to Raise Money for ALS Cure

Ken and I put together a special version of Kento to help support their effort and this good cause.



Monday, November 21, 2011

Game Art for the Artistically Challenged (Part 2)

Hello again, this is Ken Vadella blogging for Five Lakes Studio, LLC (FLS).

In my last article on the subject of Game Art I discussed the FLS strategy for acquiring artwork for our iOS projects. A reader of this posting (plicatibu) provided, what looks to be, a very valuable website for hiring artists to produce custom artwork at reasonable prices - thanks plicatibu. The site is called oDesk and though we have not tried to use it as of yet we plan to give it a shot in the near future. Check it out.

This month I would like to discuss the editing tools we use to turn our art findings into usable game components. Let me start with a small sidebar discussing how we choose tools for our efforts. The following list summarizes our evaluation technique. The list is in order of importance.

Costs
We don't want to spend an arm and a leg for image editing tools.

Features
A text editor with a limited feature set isn't very useful to us. Here are some of the items we look for in our image editing tools:
  • File Format Support - PNG, JPG, etc.
  • Layers - No layers, no tool. It's really that simple for us. We love layers for image editing and find it nearly impossible to live without this feature.
  • History - No undo/redo, why bother. See above.
  • Effects - Blurs, distortion, noise, embossing, etc.
Simplicity
What is simple to some is difficult for others. Tod and I are not new to image editing but we are also far from experts; this is not a task that we do everyday so we look for easy to use tools.

Availability
A product that runs on multiple platforms is a plus but not a show-stopper. We have access to many brands of computers that run many different operating systems. If a tool meets our other criteria then we won't rule it out just because it doesn't work on a Mac OS.

The Gold Standard
For us Adobe Photoshop CS5 is the gold standard of image editing but it does not fit the shoe string budget of a startup company like FLS. Don't get me wrong, if we didn't have alternatives we would pay the money and acquire copies of CS5. But, we do have alternatives that suit our needs very well and cost significantly less money to acquire.

The List
Without further ado, let's move to that list. These are the tools that we use for our image editing tasks. This list is arranged in order of preference as it relates to FLS.

My preferred application for image editing. This may be sacrilegious to some because it does not run on a Mac OS. But, as I mentioned above, we have access to many brands of computers running many different operating systems and this tool has a lot of positive attributes:
  • It's very easy to use.
  • It performs well.
  • It's very stable - we can't remember the last time it crashed.
  • It fits all of the criteria cited above with the exception of Availability.
  • It is 100% free. Yes, free.
Tod's preferred editor and for those on Mac OS. It exhibits many of the positives cited above for Paint.NET. Some other positive things that can be said about Pixelmator include:
  • Reasonable pricing. It's not free but you won't need to do much more than skip a restaurant dinner with your significant other to save enough money to buy a copy.
  • It performs well - it's fast; really fast.
  • It reads native Adobe Photoshop files relatively well - Paint.NET does not do this.
But it comes with some minuses as well:
  • It lacks basic drawing tools. This seems like a major oversight. I have heard that newer versions of Pixelmator will support drawing tools.
  • It lacks that ease of use inherent to Paint.NET. It's not difficult to use, but it isn't as easy to use as Paint.NET.
Still, it is a wonderful editor for the money.

Pixlr is an oddity in this list. It's not a product that you put on your machine and run. Rather, it runs in the context of a web browser. It works surprisingly well and is very full-featured. But, the whole edit-in-browser experience feels, somehow, too crammed for space and for this reason we tend to use it less than the other editors mentioned above. Still, it's free, cross-platform and powerful. What more could you really ask for?

The GIMP
You can say many positive things about GIMP:
  • It is very powerful.
  • It's free. Yes, free.
  • It's cross-platofrm.
It's everything that Paint.NET is and more. And yet, we don't use it that often. We use it less than any other editor in this article. Why? Because it's lacking in simplicity and user-friendliness. At least, we feel this way about it. Maybe we are just not that bright. Give it a try though, you might find otherwise.

Snagit
We also use Snagit to take screenshots and do basic image editing to help communicate with our customers and each other.  Snagit gets heavily used for support, it's so much easier and clearer sending a picture then a bunch of text.  Snagit does a great job of taking screenshots of the iOS simulator, saving and tagging them, and allowing awesome markup.  It is affordable and works on both Mac and PC.  I should say that Tod works at TechSmith the makers of Snagit.

Final Comments
That's it for this Blog entry. I hope you find one or more of these editors to your liking.

In a future Blog entry I will discuss some additional tools that we use to make our art assets even better. I'd also be interested in what image editors you use in your development efforts. It never hurts to evaluate new products recommended by others.

Thanks for reading.

Ken


PS (7/28/2016): One thing that was missing from this review was some web based photo editors.

One of the folks over at Canva asked that give them a shout out.  They have a basic free photo editor at https://photo-editor.canva.com and their full product is at https://www.canva.com.  Ken and I haven't used it yet in a real project yet, but it might be worth checking out.  Leave some feedback and let us know if you tried it out and if you liked it or not.

- Tod

Monday, November 7, 2011

Integrating Social Media - Epic Fail

I plan on returning to my multi-part series on creating a Star Rating System in a future post. This week, I wanted to take a small side detour and talk about how Ken and I have tried to integrate social media into our games.   Or perhaps I should say, how we have failed at it miserably.  I'm hoping someone will share some words of wisdom as there must be something fundamentally wrong with our approach thus far.


iOS 5 Twitter

With iOS5 Twitter integration, I thought it would be great to add twitter to Kento.  I created a little twitter helper class based on the iDevBlogADay article by Tony Ngo.  The class source is just two files and is available for download.

I added a twitter button to two places within Kento: on the main screen and when you solve a puzzle.

On the main screen, there is a tweet button that pre-fills in the number of tokens the player has won and a link to Kento.





When the player solves a puzzle, we place a tweet button in the upper left corner that pre-fills in some nice information about the puzzle along with a picture.














The version with twitter was released about two weeks ago and we have over 17,000 updates/downloads.  Can you guess how many times I have seen #KentoApp tweeted or received a tweet to @fivelakesstudio from Kento?  The answer is .......... ZERO, if you don't count my test ones.






A Previous Attempt

We tried integrating facebook into #Lost in Space with the same result: ZERO usage.  People just don't click on the facebook icon.



We show a little icon and some game text when the player tries to share their score through Facebook.




Conclusion

The puzzle star rating system we added continues to get great usage, but we have totally failed at engaging other types of social media such as Facebook or Twitter within our games.  We have also tried things such as HeyZap which has had better results then Facebook or Twitter, but it still doesn't have the level of engagement and usage we would like to see.  Has anybody had better luck at integrating social platforms?  I'm thinking that slapping a button in a UI just isn't the right way to do this type of social integration.

Thanks,
Tod






Sunday, November 6, 2011

UIAlert with Blocks

I wish Apple would make a version of UIAlert with blocks.  I have seen a fair number of simple examples on how to do this, but I have been unhappy with most of them.  Most use Categories on UIAlert, and I would rather not do that especially when the alert handler is also involved.

This very simple implementation uses a separate class to implement a UIAlert.  Here is how you use it:
    
TCAlert *alert = [[TCAlert alloc] initWithTitle:@"Reset Puzzles" 
                                        message:@"Reset ALL puzzles in this puzzle pack?"
                              cancelButtonTitle:@"Cancel" 
                              otherButtonTitles:@"Yes", nil];
   
[alert showAlertWithCompletionBlock:^(int buttonIndex)
                                    {
                                        NSLog( @"Hello I got it %d", buttonIndex );
                                        [alert release];
                                    }];
It is important that the alert object stay retained through the life of the Alert, but that is easy to do by releasing it in the block.  The block will retain the alert!  If the system closes the alert the completion block will be called with a buttonIndex of -1 (kAlertViewCanceled).

The code is just a small source and header file.  Please feel free to download it and let me know what you think.  I haven't switched over to ARC yet, so I'm not sure what would need to be changed to support ARC.  It would be great if someone would like to do that.

Thanks,
- Tod