It’s taken me a little longer than expected to get around to it – but if you load up Tube Notify on your iPhone now (no update to the application is required) you’ll see the DLR status has now appeared. Sorry it’s taken so long!
Apple Opens Up In App Purchasing for Free Apps
This is fantastic news!
Apple has just sent out an e-mail to registered iPhone developers informing them that In App Purchasing, previously restricted to paid applications, is now also permitted in free applications.
The only issue is that setting up in app purchase can be a pain. The pay off is worth it however as apps are less likely to be pirated as the extra components are downloaded after the app is installed from the app store as part of the bolt on purchase.
Roll on more usage of this feature.
Apple Opens Up In App Purchasing for Free iPhone Applications – Mac Rumors.
Getting a user’s phone number on the iPhone
There’s a few questions about whether this should be allowed, or not. I’m of the mindset that, providing it is detailed in the license agreement for the software, it’s ok. Yes yes, no one reads them – but is that the vendor’s problem?
Anyway, taken from Ars Technica is this little gem:
CFShow([[NSUserDefaults standardUserDefaults] objectForKey:@"SBFormattedPhoneNumber"]);
You can also browse quite a bit more of this dict.:
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/.GlobalPreferences.plist"]; NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; CFShow(dict);
Enjoy… But use responsibly.
iPhone 3GS – Twice the speed – Half the quality
When the 3GS came out, I bought an iPhone 3G. What!? Why on Earth would I do that as a developer? Simple…
I wanted to make sure I got my hands on the machine that had the smallest amount of RAM and the slower CPU. All developers should really do the same. The problem with the 3GS, just like the Pentium processor when it first appeared, and the advent of DDR/DDR2 and DDR3 – it makes developers lazy.
When I started out doing software development, you had CPUs measured in Hz and RAM measured in Bytes. You had to make sure you used the system wisely to make sure your application ran properly. That meant optimising your code and ensuring you didn’t have any leaks in the code.
Fast forward to the modern day. Who cares if my application uses that extra 1 Megabyte of RAM? Well I do. RAM and CPU are precious resources and that is so true on small UNIX devices such as the iPhone. You’re competing against other processes such as the Phone.app, Messaging, iPod and Safari which all run in the background.
On the older 2G/3G devices, this leaves you with <10MB of RAM. On the 3GS you get left with 70+MB! What should you code for? Well the fact that there are still so many 2G/3G devices out there, your iPhone application MUST work in the <10MB scenario. You can’t get lazy just because you’re debugging in the simulator or on the 3GS where you have ample resources.
To get maximum exposure for a non-game app, I put the following rules in place for myself:
- Must use < 10MB of RAM
- CPU usage should be as close to 0 and not over 30% during loading
- Any network traffic should be compressed and minimal so that GPRS transfers are still feasible
- Don’t use splash screens, use the Apple guidelines for the startup PNG file (i.e. your UI!)
Is that so unreasonable? Ok, so if you need RAM, the iPhone can kill things in the background, granted – but that slows YOUR application down while it does it. Also, when the user presses the Home button to leave, the wizzy animation doesn’t work.
You’re making a first impression on your user that just, maybe, paid money for your application. Being slow to start, or even appearing slow to start, is going to get you lots 1 star reviews very quickly. Hardly fantastic marketing is it? There are lots of examples of this all over the App Store – including some of the ‘Top Paid’ apps. They end up recommending people reboot their phone before using their app!? What? Really? That’s insane.
Optimise, debug, make sure you use asynchronous network communications and most of all, test your application on a SLOWER device. Keep those iPhone 3G devices to hand and use them as your primary debug phones.
Started testing new Tube Notify version
I’ve been working to deal with the ever growing information that Transport for London (Tfl) like to provide the daily commuter with. Part of this is changing how the information is downloaded from the server and part of this is small and subtle UI changes.
The first of these is to ensure that all colour information is downloaded from the server instead of making use of hard coded colours in the application itself. This seems obvious, but time constraints the first time around forbid this happening.
So now, the version I am testing has the colours coming directly from the server. It’s working very well and doesn’t slow the application down at all.
It also means that I can now truly update the information given to the application without having to update the application itself – this is a massive bonus!
Soon after the next version of the application is approved, the DLR status information will be added. All done without having to resubmit any new version of the application to the AppStore. This provides the user with up to the date information without the two week wait.
I felt this was a worthwhile design choice, and something that a number of iPhone applications don’t do. I don’t like the idea of buying an application that has to be updated just because the style of something in the data it relies upon changes. This just causes frustration.
The other change I have done is to reduce the font size. Silly? Maybe. The issue at the moment is that the amount of engineering works leading up the 2012 olympics means that Tfl are having to put a lot more information on their posts over the weekend around things like Bus services. This is useful to the user, so I wanted to make sure I included as much as possible. Initially, only the first paragraph was shown.
Now, the server side gets as much as it can onto the small display the iPhone provides. That’s great, but the font size on the original version was massive. In fact, it was 17pt! I’ve now reduced it to 12pt, which is still readable, as you can see from the screenshot on the right.
The other thing I have done is to make the UITextView that is used to display the data scrollable. So shortly after release on the AppStore, I intend to change the server side to really pump out all the information (carriage returns and all) to the user so they get the best experience and can quickly get at the information.
I’m still really glad of the feedback I have been getting thanks to the freebie version I pumped out for 48 hours. The latest download statistic I have from Apple puts it at over 300 copies were grabbed for free over the weekend. That’s fantastic! If only Push Notifications could be free – I’d offer it for free, forever.
Updated Tube Notify server side code
In preparation for version 1.2 of Tube Status Push Notifications (Tube Notify) – I have updated the Django application that serves up the data to the app. and it’s push notifications.
The changes are:
- Colors are now downloaded with the data, this will allow the next version of the application to use server side data rather than hard coded in the client. This means that any future lines added/changed will not need a new version of the application
- DLR update code added in preparation for 1.2 – Because of the Colors being hard coded, the client currently can’t cope with the DLR/Overground lines. The next release will be able to and therefore I have written some code to collate the DLR service status.
I’m not overly sure if people want Overground information. I just always assume it’s not working – as it never seems to be.
Either way, now I can finish the testing of 1.2 and get it submitted for approval. Fun fun fun!
Well surprise surprise – when an App is free – people download!
Over the last 48 hours, I offered Tube Notify for free on the App Store. I did this for one reason and one reason only. One has to spend money to make money. In this case, I wanted to get feedback on the app. The problem with the App Store is you can’t offer time limited demos to potential customers. Instead they make their purchase decision based on other factors. The main one being… Feedback.
150 people took advantage of the fact the app was free – that’s pretty good considering the fact that it’s no longer on the front page of the Travel Section. Out of that, I got 4 feedback reports and I now have a listed average! That average being 3/5. Can’t really grumble with that – so if you got the app for free and gave feedback, thank you.
Now to get to work on the next update for it…
Tube Notify hits the iPhone App Store
After 11 days of waiting, my first ever App hits iTunes. Regular readers of my posts (there are some, really) will have noticed what it was all about after seeing my Push on the iPhone post which covered doing Apple Push Notifications using Django on the server side. I did get around to pushing up a nice page on github to cover it and you can find that over at the django-iphone-push page.
The app is called “Tube Status Push Notifications” and it is… available in the App Store for the small price of 59p. It would have been free, but paying for the server infrastructure that runs it means that I have to recoup at least some of the costs. You can find out more about the app over on the Tube Notify page.
During the approval process I was a bit put off by the fact that Tube Deluxe managed to get push notifications out the door first. I wrote this app while push notifications were quite new. I also did it as a learning exercise writing an application I wanted. When Tube Deluxe 4.0 came out, I did give it a go. It has some things better, some things worse. Here, however, is the main thing – Tube Notify takes < 10 seconds to load up, even on GPRS (the little round dot at the top). I built the app for speed on loading, no one wants to wait to read information.
So, in short, a different application that serves a different purpose. I didn’t write it to make a lot of money, I wrote it to learn the iPhone SDK and for myself. I then gave it to others to test for a few weeks and then here we are! I hope others enjoy using it in the field as much as I do!
Push on the iPhone
I have recently started doing development on the iPhone. It’s great fun. I am particularly interested in the Push aspect of this. I’m also a big fan of Python.
There’s a number of RESTful things that can be done with Ruby on Rails. However, the whole ‘packaged application’ thing is quite new to that framework. To Django, it’s the staple diet of how to get things done. So I’m currently part way through a generic application for Django for sending APN (Apple Push Notification) requests as well as dealing with the feedback connection.
Currently I have the push side working quite well. Just a warning, this is my first stab at this and it requires Python 2.6, or the relevant backports for ssl and json installed on 2.5.
from django.db import models
from django.conf import settings
from socket import socket
import datetime
import struct
import ssl
import binascii
import json
class iPhone(models.Model):
"""
Represents an iPhone used to push
udid - the iPhone Unique Push Identifier (64 chars of hex)
last_notified_at - when was a notification last sent to the phone
test_phone - is this a phone that should be included in test runs
notes - just a small notes field so that we can put in things like "Lee's iPhone"
failed_phone - Have we had feedback about this phone? If so, flag it.
"""
udid = models.CharField(blank=False, max_length=64)
last_notified_at = models.DateTimeField(blank=True, default=datetime.datetime.now)
test_phone = models.BooleanField(default=False)
notes = models.CharField(blank=True, max_length=100)
failed_phone = models.BooleanField(default=False)
class Admin:
list_display = ('',)
search_fields = ('',)
def send_message(self, alert, badge=0, sound="chime", sandbox=True,
custom_params={}, action_loc_key=None, loc_key=None,
loc_args=[], passed_socket=None):
"""
Send a message to an iPhone using the APN server, returns whether
it was successful or not.
alert - The message you want to send
badge - Numeric badge number you wish to show, 0 will clear it
sound - chime is shorter than default! Replace with None/"" for no sound
sandbox - Are you sending to the sandbox or the live server
custom_params - A dict of custom params you want to send
action_loc_key - As per APN docs
loc_key - As per APN docs
loc_args - As per APN docs, make sure you use a list
passed_socket - Rather than open/close a socket, use an already open one
This requires IPHONE_APN_PUSH_CERT in settings.py to be the full
path to the cert/pk .pem file.
"""
aps_payload = {}
alert_payload = alert
if action_loc_key or loc_key or loc_args:
alert_payload = {'body' : alert}
if action_loc_key:
alert_payload['action-loc-key'] = action_loc_key
if loc_key:
alert_payload['loc-key'] = loc_key
if loc_args:
alert_payload['loc-args'] = loc_args
aps_payload['alert'] = alert_payload
if badge:
aps_payload['badge'] = badge
if sound:
aps_payload['sound'] = sound
payload = custom_params
payload['aps'] = aps_payload
s_payload = json.dumps(payload, separators=(',',':'))
fmt = "!cH32sH%ds" % len(s_payload)
command = '\x00'
msg = struct.pack(fmt, command, 32, binascii.unhexlify(self.udid), len(s_payload), s_payload)
if passed_socket:
passed_socket.write(msg)
else:
host_name = 'gateway.sandbox.push.apple.com' if sandbox else 'gateway.push.apple.com'
s = socket()
c = ssl.wrap_socket(s,
ssl_version=ssl.PROTOCOL_SSLv3,
certfile=settings.IPHONE_APN_PUSH_CERT)
c.connect((host_name, 2195))
c.write(msg)
c.close()
return True
def __unicode__(self):
return u"iPhone %s" % self.udidSo how do we use it? Well rather easy. First you need to set up your certificates with Apple. You’ll need to set up a specific AppID and provisioning profile for your application (i.e. you can’t use *).
The guide on Apple’s site covers how to do this. Python needs it in a combined PEM format to work. Other sites claim you have to export from Keychain Access and that you’ll need to convert both to .pem. I only had to convert the private key:
openssl pkcs12 -in pkey.p12 -out pkey.pem -nodes -clcerts cat cert.pem pkey.pem > iphone_ck.pem
I then altered my settings.py to have the new entry I added:
IPHONE_APN_PUSH_CERT = os.path.join(PROJECT_ROOT, "iphone_ck.pem")
Note the full path. I always have this at the top of settings.py to make my like easier:
import os PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
Now, it’s just case of making your iPhone app register with push and getting a unique ID. You have to use your real phone to do this. If you’re in a hurry and just want to test it out you can cheat and just pop this in applicationDidFinishLaunching delegate:
// Register for push notifications [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
Then you probably want this to get the ID out into the console:
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
// Registration was successful so we'll
// set up our device token etc.
deviceToken = devToken;
NSLog(@"devToken=%@",deviceToken);
self.registered = YES;
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
// This is expected on the emulator so that's fine
NSLog(@"Error in registration. Error: %@", err);
}Then you’ll be good to go! Run the app on the phone and the console will output the ID. Created an iPhone object and send a message. Job done.



