Script to get errors and logs out of xCode prebuild action

In response to an issue that came up on stack overflow – http://stackoverflow.com/a/18477820/285694

log_prebuild.sh

Run your script in your prebuild action using this script.

#!/bin/sh

# log_prebuild.sh
#
# Created by Kevin Lohman on 8/27/13.
#

#### Default Setup
scriptName=${BASH_SOURCE[0]##*/}
echoerr() { echo "Error - $scriptName - $@" 1>&2; exit 1; }
if [ -z $SOURCE_ROOT ]; then
outputFolder="$( cd "$( dirname "${SOURCE_ROOT}" )"/build && pwd )"
else
outputFolder="${SOURCE_ROOT}/build"
fi
stopOnError=""
unset scriptPath

##### Parse Parameters
while true ; do
case "$1" in
-v) echo "### Verbose mode enabled -v"; set -x; shift;;
--output) outputFolder=`python -c 'import os,sys;print os.path.realpath(sys.argv[1])' $2`; shift 2;;
"") break;;
*) if [ -z scriptPath ]; then
echo "Unknown flag: $1"; echoerr "usage: $scriptName [-v] [--output destinationFolder] scriptPath"
else
scriptPath=`python -c 'import os,sys;print os.path.realpath(sys.argv[1])' $1`
fi; shift;;
esac
done

if [ -z scriptPath ]; then
echoerr "Script path parameter needs to be set" > "$outputFolder/prebuild_error.log"
fi

if [ -f "$outputFolder"/prebuild_error.log ]; then
rm "$outputFolder"/prebuild_error.log
fi

echo "### Prebuild Logging Script Launching - $scriptPath" > "$outputFolder"/prebuild.log

$scriptPath >> "$outputFolder"/prebuild.log 2> "$outputFolder"/prebuild_error.log

enforcePrebuildFailures.sh

This script should be placed in a Run Script build phase for your target (ideally before compile)

#!/bin/sh

# enforcePrebuildFailures.sh
#
#
# Created by Kevin Lohman on 8/27/13.
#

prebuildLog="$SOURCE_ROOT"/build/prebuild.log
errorLog="$SOURCE_ROOT"/build/prebuild_error.log

if [ -s $prebuildLog ]; then echo "#### PRE-BUILD Output"; cat $prebuildLog; rm $prebuildLog; fi
if [ -s $errorLog ]; then echo "#### PRE-BUILD Error" 1>&2; cat $errorLog; rm $errorLog exit 1; fi

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.

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.

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!)

NSURL cheat sheet

There are lots of various parts of NSURL that you can access through methods, and the documentation on what exactly is included in each of those parts is sparse.  So I have here a cheat sheet that I created that I hope will be useful to others as well:

Based on:

http://user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

absoluteString

http://user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

absoluteURL

http://user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

fragment
anchor

host
www.test.com

lastPathComponent
someapi.php

parameterString
oneparam;twoparam

password
password

path
/somefolder/someapi.php

pathComponents
NSArray – (“/”,somefolder,”someapi.php”)

pathExtension
php

port
80

query
somekey=someValue&anotherkey=anotherValue

relativePath
/somefolder/someapi.php

relativeString

http://user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

resourceSpecifier
//user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

scheme
http

standardizedURL

http://user:password@www.test.com:80/somefolder/someapi.php;oneparam;twoparam?somekey=someValue&anotherkey=anotherValue#anchor

user
user

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.

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]);
						  }];

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];
}

Quantum Entanglement

One of the hardest things for a skeptic to accept about the Christian Faith is that it seems to go against reality.  What kind of god would allow war, famine, infant mortality, rape, cancer, or suffering?  While there is much beauty in this world, it seems to have an element of Chaos.


I’ll first say that I’m not a believer.  Just a thinker and a rambler.  I’m always chewing on life’s gristle.  And every now and then I get to a meaty bit, and I compulsively chew through it.


That’s what happened to me tonight.  I’ve got an idea in my head that has taken hold and I’ve found that without constraining myself to a single train of thought, the way that only writing something down can do for me, I’m flowing in 800 directions and never reach my intended destination.


Tonight, the meaty bit is Fate.


Imagine you’re God.  But not just any god, you are The God.  Omnipotent, Omniscient, OmniOmni.  Maybe you’ve created races.  You can create anything.  You can see the entire course of history, and from the direction the atoms right now are headed, you can envision their entire future.  Like a well setup pool shot, the races you create do exactly what you choose to have them do.  Everything is good.  If there is strife, or suffering, it’s because you willed it.  This is fate.  You can do anything.  Which means, that no matter how you create the little people, they end up boring you.  The domino’s always fall exactly the way you intend, and since being all knowing means there is no chaos, nothing you can’t predict, nothing you can’t control, you get bored.


One time, someone asked me the question, “Can god create a boulder so big, that even he could not move it”.  I immediately thought this was a dumb question.  The hypothetical is that God is an all powerful being, and therefore, in creating a rock that he couldn’t move then he wouldn’t be all powerful, and if he can’t create the rock, then he also isn’t all powerful.  This is logically false, and is makes the mistake of assuming that an all powerful being, must stay that way.  God could easily create a rock that he couldn’t move (if he were All-Powerful), however the moment that he did, he would cease to be All-Powerful, and would become All-Powerful-Except-For-That-Damn-Rock.


What if…  You’re god.  You’re all powerful.  You’re bored of knowing the future, how the dominos will fall.  You can see eternity stretching out before you and rather then marveling you sigh.  It holds no surprises.


So you create a rock you can’t move.  You make a planet, you put things on it, and animals, and free-thinking creatures.  Creatures that while they may think freely, can only do so if you don’t have anything to do with their operation, because if you meddle, you will see their fate (all seeing right?).  And maybe, on that 7th day, you set the rules.  The rock you can’t move.  You close your eyes and create chaos.  And you wing it at the rock.


Now, floating there in the middle of space, is a rock.  One you can’t change, because in your all powerful position you’ve made it so you can’t change it.  You are now All-Powerful-Except-Can’t-Interfere-With-Chaotic-Blue-Ball God.  You can save the predictable stuff for other parts of the universe.  You’ve made it so your all-seeing has a blind spot for this little world.  You don’t know the directions the electrons are headed, you can’t tell what people will do.  And you can’t interfere.


And the people?  Maybe they don’t have complete freedom of choice (or they’d all choose to be rich and happy)… but they make their own choices instead of following some path you put them on, and their fate is determined by those choices (and the interactions around them).  And you cease to be bored.  You can watch every one of them in their day to day lives, like a “Grey’s Anatomy” ant farm.  You might make guesses as to what they’ll do next, but you can’t be sure.  You’ve prevented yourself from seeing that.  Suddenly, eternity seems much more interesting.  You are constantly surprised.


But there is a downside.  You have to watch your little ant farm suffer.  You’d have never set it up that way, but the dominos fall how they will.  Chaos has taken root on your little rock, and you are powerless to stop it.


But then… Dr. Sam Becket creates a machine that causes him to leap off the rock into your space.  Suddenly there is one of the creatures on the little blue ball that you can bend to your will, and by specifically putting him in to certain places and times, you can right the wrongs.  For 4 whole seasons you are able to relieve the suffering of your little ant farm, and “It is Good”.


Maybe I shouldn’t watch Quantum Leap before bedtime.

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.

WordPress Themes