Posts tagged: iPhone

Support iOS 4 devices while building with the iOS 6 SDK

Apple has released iOS 6.0 SDK alongside the iPhone 5.  It comes with a number of changes (and deprecations) from previous SDK’s.  We still needed to support iOS 4 in our product (backwards compatibility), but had a large number of customers clamoring for iPhone 5 support (full screen).  Apple rejects any applications that are submitted with support for iPhone 5 that aren’t built with the iOS 6 SDK, so it was necessary to do a few tricks to support both iOS 4 and the new iPhone 5.

First our product has “Treat all errors as warnings” enabled, this meant that a number of deprecated functions that have been used all over the place (dismissModal, presentModal, etc…) are now throwing warnings and those warnings are treated as errors.  So it was necessary to add a build flag to the build settings in X-Code to not warn about deprecations (Under build settings change “Warn about Deprecated Functions” to no), this ignored all the errors that were related.  This was necessary because we couldn’t remove these errors from the code, as for most of the deprecated functions, there are no replacements until iOS 5, so if iOS 4 support is desired, we have to continue to use the old deprecated methods.

Next, the minimum target had to be changed to iOS 4.3 (Goodbye iPhone 3G support) but we still have support for other devices running 4.3 =< and iPhone 3GS > (Here is a matrix).

Finally, apple changed the way rotation works, and it was necessary to “hotwire” all of our existing rotation code into the new code.  shouldAutorotateToInterfaceOrientation: is the old way of checking rotation, and would be called (even when compiled with iOS 6 SDK) on any device that was running iOS < 6.  However this method would not be called for iOS 6 devices, instead it would look for the shouldAutorotate and supportedInterfaceOrientations methods, and extract it from there.  Rather then go through the 100+ view controllers we have with custom implementations for shouldAutorotateToInterfaceOrientation: I created a #define that would insert itself into the code for shouldAutorotateToInterfaceOrientation, and define the two new methods (should Autorotate and supportedInterfaceOrientations) so that they would query the old method and return an updated result.

I placed the following code in our Prefix file:

#ifdef __IPHONE_6_0 // Only do the rotation fix if we are building with iOS 6 API
@protocol DeprecatedRotationSupported
@optional
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toOrientation;
- (BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
@end

#define shouldAutorotateToInterface_fixed shouldAutorotate \
{ \
    UIViewController  *selfTyped = (UIViewController  *) self; \
\
    if(![self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) \
        return NO; \
    int optionCount = 0; \
    for(UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait; orientation <= UIDeviceOrientationLandscapeLeft; orientation++) \
    { \
        if(![selfTyped shouldAutorotateToInterfaceOrientation:orientation]) continue; \
        if(optionCount==1) return YES; \
        optionCount++; \
    } \
    return NO; \
} \
\
- (NSUInteger)supportedInterfaceOrientations \
{ \
    UIViewController  *selfTyped = (UIViewController  *) self; \
\
    if(![self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) return UIInterfaceOrientationMaskPortrait; \
    \
    NSUInteger supported = 0; \
    \
    if([selfTyped shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) supported |= UIInterfaceOrientationMaskPortrait; \
    if([selfTyped shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) supported |= UIInterfaceOrientationMaskLandscapeLeft; \
    if([selfTyped shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) supported |= UIInterfaceOrientationMaskLandscapeRight; \
    if([selfTyped shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) supported |= UIInterfaceOrientationMaskPortraitUpsideDown; \
    return supported;  \
} \
\
- (BOOL)shouldAutorotateToInterfaceOrientation
#else // We are building with the older API, leave shouldAutorotateToInterfaceOrientation alone.
#define shouldAutorotateToInterface_fixed shouldAutorotateToInterfaceOrientation
#endif // __IPHONE_6_0

Then, I did a replace all for shouldAutorotateToInterfaceOrientation: with shouldAutorotateToInterface_fixed: like below:

- (BOOL)shouldAutorotateToInterface_fixed:(UIInterfaceOrientation)toInterfaceOrientation

Also, make sure if you are using addSubview to add your main view to the window that you use setRootViewController instead.

Share

iOS Security vulnerability allows keycapture and screengrabs without users knowledge

It is possible to do screen captures of foreground applications while your application is in the background, without the user notified. These can be strung together to create video, or analyzed to identify keyboard presses (key capture). The functionality to do this is present in the app store application “Display Recorder” but could be hidden in ANY application. Pretty concerning.

Display recorder was a tool that was made by Ryan Pietrich (http://rpetri.ch/) to allow the user to easily record iPhone activity, useful for demonstration videos, sharing bugs, etc.  It relied on a public, but later private API that allows applications to capture the contents of the screen.

Recently, another developer has taken Ryan’s idea (and marketing) and released a version (unrelated to Ryan) and remarkably, the Apple review team allowed it in to the store.  Might be a good idea to download it, if you have legit uses for an application like this, however it does feel a little greasy giving $2 to whoever posted it originally.. (which as best as I can tell a Vietamese company named Bugun Soft, with an otherwise unremarkable track record)

But that’s not what I’m really writing about.  Because the ability to take snapshots (and video) from an application in the background, without the users knowledge or consent (Note: Display recorder is controlled by the user, but there is no Apple based controls that require that level), is a major security problem.  Users passwords, email, and other private information can be put at risk.  Either because a developer could sneak this functionality into their product, and surreptitiously send data to a remote server, or someone with brief access to your phone could install the application on your device, start the recording, and later retrieve it.  Here is a sample video I took with Display Recorder, two things to note:

  • Display Recorder is nice enough to stick up a red band at the top to inform you that the recording is taking place (this is due to the microphone recording part, which isn’t needed for screen grabbing)
  • However, when an audio source is tried to be used (like when I try to play a voicemail), the band goes away, and the video recording continues
  • Notice how keyboard presses are highlighted, allowing you to see what is typed

I hope that Apple finds a way to deal with this such that the security risk is eliminated, and we can still have the kind of utility and function that is desired in the first place (screen recordings are incredibly useful).

Here is an example of how this could be used:

  1. Create an application or use an existing application as your base that does something harmless (basically a trojan)
  2. Whenever the application is launched and put into background, for the next 10 minutes, capture screenshots (using legitimate or Private API, as it seems that reviewers don’t always catch the usage)
  3. Upload those videos / captures / etc to whatever server you like
  4. Enjoy reading users e-mail and looking at their passwords.
  5. As an added bonus, they could analyze the video for specific icons from keyboard presses, and parse out the actual passwords for uploading (to reduce the upload footprint).

This represents a major security threat that could be present in ANY application, not just Display Recorder, however display recorder is just the first that makes it obvious what can be done.

Share

Converting iPhone applications from pay to in app purchases

I have a product on the store called PirateWalla, and based on the nature of the application (More users would probably mean a worse experience for existing users) it was desirable to make it a more premium product (I priced it at 4.99, even though I probably would have made better profit at .99 by selling higher volumes).  The current users of the application are dedicated and active, regularly submitting feedback, asking for new features, and enjoying the app.  However, having a high application cost also meant that whenever a user paid for the application and it wasn’t exactly what they expected they would give it bad reviews.

 

With the new version of this application, I wanted to switch to an in-app purchase model, making the application free to download and try, but charging for the key desired functionality.  However, Apple doesn’t allow you to migrate existing customers to this model very easily.

Can’t just make the switch, because there is no way to give existing customers the new in-app purchase feature for free (App cost = $0 then feature cost will be $4.99 which will work for new customers but existing customers who already bought the app would now have to buy the feature)

Can’t create another application, as it would be confusing to users, and would make it so that there is now two applications to update.

So finally, I’ve decided on a phased upgrade.  First I’ll release the in-app purchase, requiring users to purchase the new functionality at a lower price (.99), while leaving the price of the app the same.  So that existing customers can buy the feature before the price goes up.  Then, once most users have had a chance to upgrade, I’ll drop the apps price to free, and adjust the price of the feature.

I feel bad about taking this route, as it’s not really fair to the existing customers.  So to make up for it, I revamped a whole section of the application, adding new functionality and improving on existing, so that they will be getting something for their .99.

So if you are an existing PirateWalla user, and don’t want to pay me another dime, I understand.  Don’t upgrade past 2.9, and your application will continue to function as normal.

If you’d like the new features and functionality however, please upgrade and buy the “item location” feature as soon as possible, as I won’t leave it at .99 forever.  There are more features to come, and some of them will benefit from having a broader user base (Teaser – Game Center integration, with high scores and achievements!)

Share

When does layoutSubviews get called?

It’s important to optimize any UIView layoutSubviews method you create, as it can be frequently called, and has the potential for creating recursion (triggering a setNeedsLayout from layoutSubviews can create a loop that will grossly affect your apps performance). Layout subviews is called once per run loop on any view that has had setNeedsLayout or setNeedsDisplayWithRect: called on it. So in addition to any time you manually call these methods, it can be useful to know when the UI framework calls setNeedsLayout/setNeedsDisplay as this will trigger layoutSubviews.

For this purpose, I will define a few view relationships:

  • View1 – UIView class, root view for examples
  • View1.1 – UIScrollView class, subview of View1
  • View1.1.1 – UIView class, subview of View1.1 (No autoresize mask)
  • View1.1.2 – UIView class, another subview of View1.1 (Autoresize mask – flexible width)

I then ran the following tests.  An X means the view was layed out

From this I surmise the following:

  • init does not cause layoutSubviews to be called (duh)
  • addSubview causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target view
  • setFrame intelligently calls layoutSubviews on the view having it’s frame set only if the size parameter of the frame is different
  • scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and it’s superview
  • rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
  • removeFromSuperview – layoutSubviews is called on superview only (not show in table)

Hopefully this is helpful information for you as well.

Share

Blocks Rock – A Cocoa Asynchronous NSURLConnection block example

So I heard that blocks were one of the new features of 4.1 and I decided to give it a try. And it’s awesome! Within half an hour I’d solved a problem that I’d had to make much more complicated implementations to solve previously, and I’m so excited I decided I’d share the code.

Problem: NSURLConnection asynchronous connections are ugly. If you want to have one controller make multiple different calls you have to make unique delegates for each call or have some convoluted way for the connection manager to tell one delegate from another. It’s a real mess.

Solution: BLOCKS!

Step 1: Create NSURLConnection block extension that allows for calling async methods from class API like you would sync method.


//
//  NSURLConnection-block.h
//
//  Created by Kevin Lohman on 9/12/10.
//  Copyright 2010 Logic High Software. All rights reserved.
//  Free to use in your code commercial or otherwise, as long as you leave this comment block in
// http://blog.logichigh.com/2010/09/12/cocoa-blocks/

#import 

@interface NSURLConnection (block)
#pragma mark Class API Extensions
+ (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_;
@end

and

#import "NSURLConnection-block.h"

@implementation NSURLConnection (block)

#pragma mark API
+ (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_
{
	[NSThread detachNewThreadSelector:@selector(backgroundSync:) toTarget:[NSURLConnection class]
						   withObject:[NSDictionary dictionaryWithObjectsAndKeys:
									   request,@"request",
									   successBlock_,@"success",
									   failureBlock_,@"failure",
									   nil]];
}

#pragma mark Private
+ (void)backgroundSync:(NSDictionary *)dictionary
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	void(^success)(NSData *,NSURLResponse *) = [dictionary objectForKey:@"success"];
	void(^failure)(NSData *,NSError *) = [dictionary objectForKey:@"failure"];
	NSURLRequest *request = [dictionary objectForKey:@"request"];
	NSURLResponse *response = nil;
	NSError *error = nil;
	NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
	if(error)
	{
		failure(data,error);
	}
	else
	{
		success(data,response);
	}
	[pool release];
}


@end

Now just import your new class and make your async call! AWESOME!

	[NSURLConnection asyncRequest:request
						  success:^(NSData *data, NSURLResponse *response) {
							  NSLog(@"Success!");
						  }
						  failure:^(NSData *data, NSError *error) {
							  NSLog(@"Error! %@",[error localizedDescription]);
						  }];
Share

Validating an e-mail address

Question: How do I verify if a string of characters is a valid e-mail address?

First, you can only be sure about the second half of the e-mail address (the domain), as (in order to protect the anonymity of their users) many e-mail servers don’t give immediate responses when checked to see if the first part of the e-mail address is valid (although some will send a bounce notification at a later date, once an e-mail has been attempted).

Second, you can only TRULY verify if the domain address is accurate if the testing application has internet access.

So, without making a DNS call (or before), you can’t be absolutely sure that the user or the domain actually exists, and can never be sure if the user (and therefore the email) is an actual e-mail address.

But you can check to see if the format is valid using a regular expression. And this is where things get REALLY tricky, as how restrictive you want to be in your filtering depends on you, and while there is a defined standard, simply adhering to that standard may exclude e-mail addresses that are in use.

It seems that the most common regular expression that is suggest on the web is the following:

^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$

This will cover ALMOST all e-mail address you will run into, and will exclude obnoxious e-mails like badpirate@gmail.com.nospam

However, it will exclude a few e-mail addresses that are in use (but are probably being excluded and having trouble in lots of places:

  • kevin@yesthistldexists.museum – Yes .museum is a valid Top Level Domain
  • kevin@kevin@logichigh.com – Yes the current e-mail RFC doesn’t allow this type of e-mail address HOWEVER older RFC’s did, and so there may be some folks still using this format (and not being able to use this format in lots of other places)
  • ??@??web.jp – International characters in domains and user names are already being normalized to ascii friendly code by browsers and e-mail clients, so they are being used regularly, however if you are checking before that normalization occurs, these sorts of e-mail addresses will get tossed

Therefore, I’ve also written a super lax e-mail format checker that will catch all scenarios. This reg ex would probably be best used if you plan on checking to see if the domain exists after checking to see if the format loosely matches SOME format that COULD be in use :)

^.+@.+\.[A-Za-z]{2}[A-Za-z]*$

Finally, if you’d like to implement this in cocoa code:

BOOL NSStringIsValidEmail(NSString *checkString)
{
	NString *stricterFilterString = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; 
	NSString *laxString = @".+@.+\.[A-Za-z]{2}[A-Za-z]*";
	NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
	NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
	return [emailTest evaluateWithObject:checkString];
}
Share

PirateWalla iPhone

Coming soon!

Arrr… For the truly compulsive GoWalla user.  This here application will perform an ever growing spiral search from your current location and will find any booty (items) you have not collected yet in all nearby locations.  Yarr.. and it can be fine tuned to even help you lower the issue numbers of your existing collected items.
Why would you want to do all of this?  Because you are compulsive.  And gotta have them all.
Why am I charging $5??

  1. This tool is incredibly effective at helping you find rare items.  Rare items that I might also need.  Rare items that other users of the application would just as soon hope that YOU never find.  By making it cost as much as a draft beer, I can assure that only the devoted pirates find the treasure.
  2. The Gowalla API be a shifty one.  Gowalla changes the way their backend works ALL THE TIME, and with NO WARNING.  I could do this application for free… but the upkeep would soon make it not worth the effort to update, and it would be a free broken application.  By charging a few bucks, I can make it worth my time to deal with the GoWalla headache.
  3. I’m a pirate.  Yarr.  Need dub-loons to buy rum.
Share

Malama Card Application

Just finished another iPhone Application, and you can find it in the Apple Store for free starting today!  Start getting great savings around Hawaii using this Malama Card Application built for Kamehameha Schools.  And keep your ears open for more great applications from Logic High Software!


Fast Tube by Casper

Share

Beta Testers Needed

Hey everybody, I’ve got a new geo-location based game coming out very soon that I’d like to beta test a little bit before it’s launch.

Specifically I’m looking for iPhone 2G, 3G and 3GS owners, preferably in the Oahu area as the game is multi-player and depends on having friends to battle with, however if you have a few friends who are also iPhone owners and want to test it out in your area then that is dandy as well.

Sign up for the beta tester mailing list to be a tester

Share

AT&T, I'd rather be tied with a tether than a leash!

Sign the petitionSlashdot it

The new iPhone 3GS was announced today, and many of it’s new features were confirmed by Apple.  And AT&T won’t be supporting some of these new features, I’d like to explain what, why, and what we as consumers can do to prevent it. One of these great new features is tethering, and will be offered in many countries by a variety of carriers, but… AT&T wasn’t even stated as being one of the companies PLANNING a launch.  WHY?  Your network supports it, the phone now supports it… Another one of these great new features was MMS, and while it is being offered on “Twenty-nine carriers in 76 countries” guess which country isn’t going to be one of them? AT&T is the only carrier of the iPhone in the US, and despite offering it for many of their other video/photo capable phones, iPhones have been left out and forced to use a very awkward and painful system to view their MMS’s (Open SMS, copy down long random user name and long random password, and then, because the link isn’t even often properly clickable, copy down the link, manually enter link into iPhone or computer browser, and at the corresponding web page manually enter both the long user name and the long password.  If there were no typo’s in this process you’ll get a crappy miniturized version of the original content sent to you).  Can’t blame Apple, the phone demonstrated it was quite capable of displaying photos and videos, even with the old model.  And now that sending MMS is integrated into the new operating system, there remains no excuse whatsoever.  But AT&T is in no hurry, stating no support until late summer because… drumroll: They have to remove the Opt-Out codes for all the iPhones in the system. So they have a little toggling to do in their database.  Should this process take 2-4 months?  No.  But it will.  Because there is no market pressure for them to do so.  AT&T set it up that way.

Contracts

What about all the screaming customers?  Don’t they represent market pressure?  Not really.  First lets look at the group, currently the only AT&T customers who are holding phones that can support MMS, and will support tethering who won’t be able to use these features are iPhone users.  Blackberry users on AT&T are currently enjoying BOTH of these features.  So the only customers screaming are iPhone users.  And AT&T has us 2 ways:

  1. Contract – Most iPhone users are in a 2 year contract, that isn’t up and won’t be up for a while, additionally new hardware purchases, lost broken phones (no insurance offered), price plan changes, etc. all extend your contract.  It’s a zero sum game.
  2. Hardware – for those of us who dutifully make sure not to change our price plan, own the oldest iPhone hardware, and refuse cheaper upgrade plans, the contract can’t hold us.  But AT&T’s current exclusivity agreement for the iPhone can.  Sure you can hack your phone, and put it on T-mobile, but you won’t find MMS or tethering there because they can’t officially support it until the agreement runs out.  You’ve made a large investment in the cost of your phone, in money, applications, learning curve, etc, and this inertia is enough to keep most customers with AT&T.  Until the features and screaming make it so we’re better off going through the hastle of switching carriers, buying another phone and learning it.  They’ve got us.

Monopoly Power

A quick economics lesson: So, AT&T has a large group of customers (iPhone users) who have a large barrier to exit (the requirements for excercising monopoly power) as well as lack of available substitutes (for many of us iPhone users, there is no substitute).  These ingredients allow for the excersing of monopoly power.  What does this mean exactly?  In a perfectly competitive economy every business is forced to take the price of the market and keep their features comparible in order to be competitive.  This price is where the marginal cost (the cost of producing one more unit of product) is equivalent to the marginal profit for selling that unit (What the consumers are willing to pay), this ratio provides no excess profit to the corporation, and leaves all that extra value with the consumer.  Maybe you were willing to pay more, but because of competition you didn’t have to. Monopoly power (whether a true monopoly or a partial monopoly) allows companies to move closer to their ideal selling location, the point at which marginal profit (The profit made for selling an additional unit) is greatest.  They may sell less units, but at a higher price and a more economic cost / revenue ratio.  The consumers end up paying much more, and they lose the advantage they have in a competitive environment.  At the moment, while AT&T would gain customers and remain profitable if they had more reasonable price plans (like not charging extra for SMS, or better data prices) they have no incentive to (from a purely profit standpoint) as they can make MORE money by charging their existing customers more. The same holds true for features.  New features, like MMS / Tethering cost money to implement, and while doing so might bring them more customers (and likely they would still remain profitable), their number crunchers have clearly decided that the costs won’t outweight the profits. Basically, there is a slider, you can choose straight profit $$$ or you can give some of your profit back to the customer in exchange for loyalty and market share.

Comparative Profit Margins

Comparative Profit Margins

Here is a list of the major wireless companies and their operating margins.  In a particular market the players with a higher percentage here are either operating much more efficiently then their competitors, or are taking more customer surplus (good will).  Looking at these figures you might guess that AT&T has the largest subscriber base, when actually Verizon does.  Verizon also happens to rank up near the top in customer satisfaction among us carriers.  T-Mobile, which also has a really high profit margin is the other company that ranks up with Verizon on customer satisfaction, but their relative user base is also much smaller then AT&T. So AT&T charges more money, serves less customers, or has a lower customer satisfaction rating then it’s competitors.  It’s their business model.  And it’s raking in some great profits.  But it doesn’t have to be that way.

Alternative

It’s probably too late to save the iPhone exclusivity, Apple does not have a history of tolerating poor service from it’s partners, and based on the zingers during todays Keynote, they won’t be likely to re-up the exclusive contract.  But AT&T can still bring it back.  By providing a more customer friendly model, the services that the customers (and partners) are demanding, and they’ll keep most of us, but commitment needs to be shown.  Not just a rollout at the expected late date, but an immediate, public and effective effort (even if costly) to surprise us all with a simultaneous feature release date.  The positive press, customer loyalty returned, and in the long term, profits will outweigh any other business plan.

Action

Please tell AT&T that when the option comes to leave, you’ll be walking.  But also, let them know that if they commit themselves to improving the customer experience that you will stay.  By doing so we may affect change.

Sign the petitionSlashdot it

Share

WordPress Themes