You are almost done implementing that brilliant “iPhone app idea” in your mind and cannot control your excitement for sharing your iPhone app with the world. But you know in your heart that, it is the programmer speaking within yourself.
The cold businessman/entrepreneur within you unfortunately knows, that there is a Beta testing period ahead where you will want to get at least 50-100 users to use your app, report bugs and suggest changes before you can even think of releasing the app to the AppStore.
The Problem :
The problem now is Apple has made it so difficult for you to do an Adhoc distribution for your app, it is nothing short of a nightmare. Let us start with a few things you would have to do for Ad-hoc dist :
- Find users of course, to test your app in Beta. These would ideally be non-technical users who represent a real audience, rather than you and your geeky friends doing the testing for you.
- Generate an AD-HOC cert from Apple developer portal, download it and sign your app with that
- Email all these non-techie users and ask them to send you their UDID (good luck with that!). Most probably they will think you are asking for their SSN !
- Add these UDIDs to the provisioning portal and download a new provisioning profile and update it in your project
- Make an AD-HOC build, create an .IPA file and email it to your beta testers.
- Get your beta testers to download the .IPA to their desktop, drag and drop it to their iTunes and sync their phone (again good luck with this! Nobody every syncs their iPhone to the desktop iTunes btw.)
- We tried to do this with Loqly (iTunes Link) and out of 80 users who were willing to help, 10 users replied with UDIDs and believe it or not, 2 users were able to install the app through iTunes.
- Now, imagine fixing a bug and sending out an update. In our case, only 1 person tried to update and his iTunes kept erroring out.
The Solution :
Enter the awesome folks at http://testflightapp.com. We discovered them when were on step 8 above. i.e our Beta testing was pretty much halted!! Testflightapp was in their Beta at that time. And they were God sent angels for us. Let us see how testflight helped us :
- Step#1 and #2 above – We had to take care of it ourselves of course.
- Step# 3 – You add a user’s email ID to testflight app and it automatically emails them and the moment they click accept/register on their iPhone, their UDID magically shows up in testflight app portal.
- Step#4,#5 – You still do it manually
- Step#6 – This is where the magic happens. The beta tester gets an email on his IOS device, he clicks the install button and bam! the app is installed.
- Once we integrated testflightapp.com, we got 70 users to do our beta testing for us.
Bottomline : As you may have noticed, there is nothing magical about testflightapp, since it just adds a layer on top of what Apple offers you. But the key is to notice that they have taken care of the main pain points. i.e Getting the users to Signup for beta, download the app and receive future updates.
If anyone of you are having trouble testing your IOS apps with fake locations. eg. I am in Dallas but I want to test how my app behaves in New York, Toronto, Australia, India, wherever…there is no magic solution built into Simulator for this. We ran into this same problem while developing Loqly – http://loqly.me. Here is the iTunes link:http://bit.ly/e5u4jv (it is free!) and this is how we solved it.
The Solution: (This is natively supported in IOS 5/XCode 4.2 simulator. Yipee! no more hacking)
The easiest way (may not be the most elegant way) to do this is as below. You can change it to any geolocation and when you run in simulator, it will fake the geolocation
@interface CLLocationManager (Simulator)
@implementation CLLocationManager (Simulator)
CLLocation *fake = [[[CLLocation alloc] initWithLatitude:45.523450 longitude:-122.678897] autorelease];
#endif // TARGET_IPHONE_SIMULATOR
I have added an HTTP sniffer on my network countless times and freely see passwords travelling back and forth between IOS apps and the servers where their APIs reside. I am sure you remember that Instagram took lot of flak when it was discovered that they were transmitting passwords in clear text across the network. The argument was that although there is zero value for anyone to hack your instagram credentials, but even the smartest of us tend to use the same login name and passwords for a lot of sites. And it doesn’t take a long time for a hacker to realize that and use your instagram login to hack your bank account or mint account or email account. SCARY !!!!!!
I am not going to detail how exactly to protect your API here but here is a quick thought on how to easily do it without SSL (call it poor man’s SSL). We have used an advanced form of encryption and rolling/expiring tokens to protect our API from prying eyes in Loqly. Here is the iTunes link:http://bit.ly/e5u4jv (it is free!)
- When you launch your app, contact your server to get a random key
- Every API call you make to the server from now on should send this key back to the server using any simple encryption algorithm. If nothing else, just base64 encode it. The server should then validate that every API call contains this key.
- Along with the above key send some token which will expire after X minutes. eg. 10 minutes
What will you get from this? If a hacker is sniffing your network and he sees the exact API call and copies it, guess what? He cannot make that call more than X minutes at which time the validity of that API call expires. Which means nobody can use DOS attacks to bring down your entire server.
But in the above sentence the hacker can use your API call for at least X minutes. Well, in that case send some random number(encrypted) with every API call. The server should then reject API calls with the same number in them (i.e copy /paste API URLs will not work for the hacker)
Also, think of rejecting API calls not originating from a certain USER_AGENT. i.e people trying to paste your API calls into your browsers should be slapped in their face if they are coming from Mozilla, IE, Safari, Chrome etc. Your IOS app can modify the USER_AGENT and insert its own value in there.
Also, try to HTTP POST these security keys to make it a little more difficult for the hacker to call your API. An HTTP GET call is as simple as copying and pasting it on the browser.
The Problem :
You are a good programmer who likes to know what the code is doing before copying and pasting it from the internet. You always write efficient code and your code never leaks memory. You use instruments and profiling to profile your leaks, zombies, allocations etc.
But shit happens! And no matter how hard you try and how good your testing team is, your app will eventually crash. I have seen all sorts of good apps crashing. Google App, Loopt, Facebook, Heytell, Instagram to name a few which have crashed on me. I am a power user though, which means I have around 70 apps easily running on my iPhone all the time. This causes apps to run out of memory and guess what..when you run out of memory–>BAD THINGS HAPPEN! = CRASH!
The Solution :
So, as a good developer, you should definitely build some error logging/reporting capabilities in your apps. Yes, Apple iTunes has the option to collect your crash logs and stuff. But hey! please leave a comment on this post; I am curious to know how many people use it.
At Loqly – http://bit.ly/e5u4jv, we use something called Hoptoad for error reporting for both our server side errors and IOS app errors. It is amazing that with a few lines of code how nicely Hoptoad takes care of everything for you. If your app crashes, the next time you run the app, Hoptoad presents this screen to the user, allowing him to send a crash report to you. The crash report has the standard stacktrace and it normally takes me 10 seconds to narrow down the culprit by looking at the report.
Yes, it is debatable if you want to admit on the user’s face that your app crashed last time. It is a little shameful yes, but hey who are we kidding here? Do you really think the user doesn’t realize that your app crashed, just because IOS simply closes your app and you don’t see the nasty Windows Dr. Watson message.
- Do not use a screenshot which shows your app running in an IPhone. App Store does not like images of their IPhone in the screenshots. They will reject it immediately. Just take a shot of your application ‘s screen only.
- Apple asks you to submit a Main Logo (512 * 512 px PNG) which shows up as the big preview in ITunes and a small logo (47 * 47 px) which should be included as part of your App Bundle. They are extremely particular about the sizes and your main logo should match the mini logo. I made the mistake of submitting two different pictures (with the same theme) but promptly got rejected.
- Make an application which at least in Apple’s eyes will serve some purpose to the public. I know that they rejected this app called “Pull my Finger” (and it farts) and it never made it to the App Store, because Apple said it serves no purpose. Although, with weird apps like Flashlight etc, I don’t know why some apps make it to the app store and some don’t.
- DO NOT use any undocumented APIs. This is a recipe for rejection right away. eg. UIProgressHUD is the most common API that people use to show hourglasses but get rejected right away.
- Do not write an app which provides competition to any built in IPhone apps. eg. Providing a much better Photos application will probably cause Apple to think that it is giving competition to their own photos app
- Do not write an app which provides functionality which is “unofficial”. You must have heard of how the app which would allow you to tether you IPhone to your computer to share internet got rejected by App Store.
- Also, make sure your app complies with the UI guidelines. For eg. if it takes too long to load or shows an hourglass for too long, it will get rejected. Why? Because Apple doesn’t want its users to perceive that the IPhone is slow just because your app is slow.
- And PLEASE FOR GOD SAKE! Don’t do this (unless your are looking for media coverage) : http://www.pcworld.com/article/163717/baby_shaker_app_approved_then_removed.html
- If your app needs an internet connection, but does not notify the user if there is no internet connection present, it will get rejected. Gracefully handle lack of internet connection and notify the user. See this Post for how to do this
- With AT&T adding 200MB and 2GB caps to the previously unlimited data plan, Apple is very mindful of the amount of data your app transmits. I don’t write media streaming apps, so no advice there. But for a typical app supported by a backend webservice, use JSON or BJSON format instead of XML. Only pass data that is required and cache on the IOS device if possible. Three20 lib has a nice TTImage which will cache images on the device and will not request them again if they haven’t changed on the server.
When we first released Loqly (http://loqly.me) in Dec 2010, we had used UIProgressHUD to show please wait type hourglass messages to the user when the app was doing something in the background. UIProgressHUD is the same API which Apple internally uses in their apps to show the nice translucent hourglass.
Unfortunately, Appstore took 5 minutes to slap us with a rejection. Worst part is, I had been coding all night and submitted the app at 5AM in the morning in the hopes of getting at least 3-4 hour nap. But 5:10 AM, my iPhone gave me the new mail sound. And there it was…the dreaded rejection email !! I was so tired by that time that I let my team know about the rejection and just passed out.
Next day after doing some research, I came across MBProgressHUD by Jonathan George. It is an excellent replacement for UIProgressHUD and in fact has much more functionality. We just added Jonathan’s code and we were approved in no time!!
Lot of times people point out that they think that Loqly – http://bit.ly/e5u4j might be sucking out their battery life because it uses their iPhone’s GPS all the time. Unfortunately, Apple hasn’t done a good job of indicating what the small purple arrow at the top means.
Apple’s official documentation says this about conserving the user’s battery life :
“In iOS 4.0 and later, you can use the significant-change location service to receive location events. This service offers a significant power savings and provides accuracy that is good enough for most applications. It uses the device’s cellular radio to determine the user’s location and report changes in that location, allowing the system to manage power usage much more aggressively than it could otherwise. This service is also capable of waking up an application that is currently suspended or not running in order to deliver new location data. “
Loqly uses the same API which delivers us your location based on cell tower triangulation. i.e We don’t even use your GPS except the first time you download and run our application. The purple arrow just means that an application has accessed your location recently. Which is what Loqly is doing. We don’t keep checking your location. We just tell your IOS device to let us know when you have traveled more than 1/2 mile from your current location. And we leave it to IOS to use cell towers and tell us if you change your location.
Bottomline for developers :
In summary, if as a developer if you want to be conscientious and conserve the user’s battery life, use the significant location changes API “[CLLocationManger startMonitoringSignificantLocationChanges]” instead of ["CLLocationManager startUpdatingLocation]“
Of course, to get the initial “fix” you will HAVE to use CLLocationManager startUpdatingLocation but once you get the location, immediately call stopUpdatingLocation and switch to startMonitoringSignificantLocationChanges.
If you have anything to add to this article or don’t agree with me, kindly leave a comment below.
EDIT: 07/12/2011 – IOS5 beta 3 has some changes specific to location services. Check this out – Basically you will see a gray arrow now if an app has accessed your location in last 24 hours and a purple arrow if it is actively accessing your location.
EDIT: 09/07/2011 – The information in this article is accurate and can be confirmed by Apple’s official docs. But due to the low awareness of the general user, we were still getting constant feedback from users that the arrow should not be there when they close the app. So, we chose to turn off the arrow by simply powering off location services by calling “CLLocationManager::StopUpdatingLocation”. As a result of this the arrow simply stays off all the time even when you are actively using the app. What all you have to do to keep your users Happy :(