Agario Portal — Now in Apple Store

agario_3

Agar.io is a fun, multiplayer, online game which you can play at http://agar.io

It has some mobile functionality, but for playing on the iPhone or iPad there are few glaring issues:

  1. To control, you must tap in the direction you want to go; this behavior is laggy and overall unplayable
  2. There is a button to split, however there is no button to eject mass, an important behavior for playing the game
  3. There is no ability to bring up the menu and change options
  4. On the iPhone, the main menu is hard to use because it’s sizing seems to be “not quite right” making it impossible in some resolutions to set your name.

There are also other “Agar.io” style games in the App store, but none of them have the full features, multiplayer aspects, or mechanics that we love about the real deal.

To solve these things, I wrote Agario Portal – Currently available in the App Store which solves these problems – a custom “browser” for playing Agar.io with a few benefits:

  • A joystick for better control
  • Buttons for both split and eject mass
  • Button to bring up main menu
  • Better format for main menu allowing user to see the whole thing.

Screenshots:

iPad Screenshot

iPhone Screenshot

Stupid bot creatures

Turned on image captcha.  I apologize to real people.  I do not apologize to the bots.

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

WordPress Themes