Using custom fonts on iOS (iPhone iPad)

This is a quick walk-through on using a font other than those supplied by Apple on an iOS device.

For reference purposes, you can find out what fonts are available to you “out of the box” by checking out this comprehensive list:
http://iosfonts.com/

I’m going to be using Bebas for my example, a great font created by Dharma Type. You can pick it up here: http://www.dafont.com/bebas.font or use a font of your own choice. It’s important to note you should check a font’s license before you use it in an app you intend to distribute in the app store.

If your font’s not installed on your Mac, go ahead and install it. Before we get too deep into coding and while you’re in or around Font Book let’s go ahead and get the PostScript name of your font. You can do this by selecting your font from the list inside of Font Book and pressing Command + I to toggle the font information. The right side of the window will look like this:

The PostScript name is listed on the top, with Bebas, the PostScript name is simple… it’s Bebas but most are more complicated. Take the PTSans family for example: PTSans-Regular to PTSans-CaptionBold. Keep this PostScript name handy as we’ll reference it later.

Moving on let’s get the ttf file into an Xcode project.

I started with a Single View Application template, go ahead and get that going as normal. Inside my Supporting Files folder I’m going to create a group named “Fonts”. I’m going to drag BEBAS___.TTF into that directory and make sure “Copy items into destination group’s folder (if needed)” is checked. Click finish.

Next, open your app’s plist. Right click and add a row, we’re going to add the key “Fonts provided by application” which is an array of the ttf font files. Toggle that down and for Item 0 add BEBAS___.TTF.

Now you need to head over to your project’s build phases tab. Click to the “Copy Bundle Resources” and click the + icon to add a new item and choose BEBAS___.TTF.

Now, when your window looks like this, you’re ready to use the font in the application:

I put some simple code to create a UILabel in my viewDidLoad method like this:

    UILabel *bebasFlavoredLabel = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 320, 44)];
    bebasFlavoredLabel.text = @"Bebas on iPhone";
    [bebasFlavoredLabel setFont: [UIFont fontWithName:@"Bebas" size:15]];

    [self.view addSubview: bebasFlavoredLabel];

On line 3 you see where we use [UIFont fontWithName:@"Bebas" size:15]. The name you use there is the PostScript name you found at the beginning. Go ahead and run:

Viola! Your font is ready to be used as you wish!

Post-Release Development Bundle Identifiers and Display Names

So you’ve released version 1.0 and it’s in the App Store but you’ve noticed a few bugs and there are still those features you were holding out until 1.0.1. You tweak some code and test on your device but now you’ve lost the current release version because they both have the same bundle identifier. Sometimes …most of the time, as a developer it’s important for you to have both the current release version AND the current beta version on your device. Project’s aren’t configured like this out of the box but it is certainly possible to make this happen without manually changing the bundle identifier every time by way of User Defined Build Settings and variables.

If you take a look at your Application’s plist, you’ll see your bundle name, and bundle identifier along with other information about your app. You’ve probably seen a few fields that include variables that look like this: ${PRODUCT_NAME} or ${EXECUTABLE_NAME}. We’re going to use that system to change the bundle identifier and the bundle display name dependent on the build-type (Debug, Release, Ad Hoc, etc).

To get started, open up your Application Target and click the Build Settings tab:

Once you have this open, click the “Add Build Setting” button in the lower right corner:

Then click “Add User-Defined Setting”. You’ll see XCode adds a section named “User-Defined” and a new setting for you to type in. Type in BUNDLE_DISPLAY_NAME_SUFFIX and hit enter. We’re going to use this as a string to append to our bundle display name (the name of the app that shows on the springboard). Now you should see this:

You can enter in whatever value you like for debug, a few common or recommended ones are “Beta”, “B”, ß but you can use whatever you want. Don’t enter a value in for release as we don’t want to append anything when we build for release as that build should be headed for the app store.

Next, let’s add another User Defined Setting and called this one BUNDLE_IDENTIFIER_SUFFIX. For this you can, again, enter any value you like for Debug. This is appended to the bundle identifier and since an iOS requires unique bundle identifiers this beta version of the app needs one different than the release version. I usually use ‘.dev’ for this field but you could use something like ‘.beta’ or whatever you’d like. So now your settings should look similar to this:

Now that we have the variables set let’s go to the application’s plist and use them. In the bundle display name field simply append ${BUNDLE_DISPLAY_NAME_SUFFIX} to whatever is already there. Move on to the Bundle identifier field and add ${BUNDLE_IDENTIFIER_SUFFIX} and append that to the existing data there. When complete, you’ll see something like this:

Now you’re set. When you build for Debug releases your app will be named with your appended string as well as your bundle identifier. You’ll be able to keep the current release from the app store installed as well as your development build build XCode or TestFlight!

Lock screen “Now Playing” with MPNowPlayingInfoCenter

Note: Example project is available here

One of the great additions iOS 5 brought us is the ability to display meta data about currently playing tracks on the lock screen. This is a great convenience to users and a must if your app has background audio playing. I know I use this to great extent, especially when driving. Best of all, it’s actually quite simple to get going.

For the sake of this tutorial, we’re going to be focusing mainly on the MPNowPlayingInfoCenter and not much on how to play streaming audio. If you have questions, as always, please feel free to leave a comment. I, as I’ve stated in the past, am still fairly new to the iOS/Objective-C world so if you see something that makes you say ‘UR DOING IT WRONG!’, please let me know. If you’d like to review the details of MPNowPlayingInfoCenter, you can read the Apple documentation.

To get started, create a new project. I created one using the single view template but feel free to do whatever you’d like. Once you’ve created the project there are a few things we need to do to get the project setup. By default, simply playing audio won’t persist if the application leaves the foreground. We need to tell iOS we’d like to play background audio. To get started doing this, open up your application’s info.plist file and add a new row: “Required background modes” (UIBackgroundModes). This creates an array with Item 0 change the value to “App plays audio” (audio). I’ve got a screen shot of what this should look like:

Next, there are a few frameworks we need to link to our project:

  1. AVFoundation.framework
  2. MediaPlayer.framework
You can do this by click on your project, and selecting the Target and swiveling down “Link Binary with Libraries”, click the + at the bottom and begin typing those names. Once you’re done, it should look like this:
Now we’re ready to start playing audio. In my view controller, I’ve created a simple IBOutlet UIButton called playButton and linked it in the nib. I’ve also attached an IBAction, playButtonPress to the button’s touch up inside event.

You can see those items in myViewController.h:


@interface ViewController : UIViewController {

IBOutlet UIButton *playButton;

}

@property (nonatomic, retain) IBOutlet UIButton *playButton;

-(IBAction)playButtonPress:(id)sender;

Next I’m going to import the MPMoviePlayerController header to add a player to my view controller class:

#import <MediaPlayer/MPMoviePlayerController.h>

To add the player controller we’ll add these lines to the ViewController.h:

MPMoviePlayerController *audioPlayer;

and

@property (nonatomic, retain) MPMoviePlayerController *audioPlayer;

Swing over to your ViewController.m file and we’re going to add a few more headers:

#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPMediaItem.h>
#import <AVFoundation/AVFoundation.h>

And we’ll synthesize our playButton and audioPlayer:

@synthesize playButton, audioPlayer;

In viewDidLoad we’ll initialize our audio session and audioPlayer and pre-load it with content from the web. We’re going to use Oliver Drobnik’s Cocoanetics podcast as our audio feed for this tutorial. Oliver has an awesome podcast packed with great info for iOS developers, you can find out more about it at http://cocoanetics.com.


[[AVAudioSession sharedInstance] setDelegate: self];

NSError *myErr;

// Initialize the AVAudioSession here.
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
    // Handle the error here.
    NSLog(@"Audio Session error %@, %@", myErr, [myErr userInfo]);
}
else{
    // Since there were no errors initializing the session, we'll allow begin receiving remote control events
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}

    //initialize our audio player
    audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"http://www.cocoanetics.com/files/Cocoanetics_031.mp3"]];
    
    [audioPlayer setShouldAutoplay:NO];
    [audioPlayer setControlStyle: MPMovieControlStyleEmbedded];
    audioPlayer.view.hidden = YES;
    
    [audioPlayer prepareToPlay];

It’s important we have line 12 as this is what tells iOS we want to receive any remote control events from the lock screen (i.e. backward, play, pause, forward). I’ve found that without that line your information will never display (here’s a link to my Stack Overflow question chronicling my journey to that discovery).

Moving onward, next we need to create our action that actually plays the audio and posts the information to the lock screen:


- (IBAction)playButtonPress:(id)sender {
    
    [audioPlayer play];
    
    Class playingInfoCenter = NSClassFromString(@"MPNowPlayingInfoCenter");
    
    if (playingInfoCenter) {

        
        NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
        
       
        MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imagedNamed:@"AlbumArt"]];
        
        [songInfo setObject:@"Audio Title" forKey:MPMediaItemPropertyTitle];
        [songInfo setObject:@"Audio Author" forKey:MPMediaItemPropertyArtist];
        [songInfo setObject:@"Audio Album" forKey:MPMediaItemPropertyAlbumTitle];
        [songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
        [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];


    }
}

Let’s go through this line by line starting with line 5. Lines 5 & 7 of our code make sure the class MPNowPlayingInfoCenter exists since this functionality was just added in iOS 5. Next, we create an NSMutableDictionary called songInfo that will contain the information for the lock screen. Next we create an MPMediaItemArtwork item that will store the image. We set our information on lines 13-16. These are the properties that display on the lock screen. Something to keep in mind is there are several 3rd party peripherals that interact with the iPhone/iPod that play music that might pull this information. There are a few additional properties you can assign that may be accessed by other devices and you can read about those in the Apple docs. Last and certainly not least, the magic happens with line 17 as we add the information to the lock screen! Viola!

Icon already includes gloss effects but still glossy!

When we released Namely for iPhone, the first few days the app was in the store, the icon was glossy. This was not our intention. When you view the app in the store, it had the gloss effects automatically applied by Apple but once you installed it, the icon displayed on the springboard without the gloss effect (as intended). This was pretty annoying.

We had UIPrerenderedIcon (or ‘Icon already includes gloss effect’) in our info.plist but it still was having this issue with the app store. I did a bit of research and found that some people used jpg instead of png when uploading their 512×512 icon to the app store. You can only edit your icon when you’re app is in some sort of approval or waiting for approval status, not when it’s actively available in the store. I had a few changes I wanted to push in an update so I came up with 1.0.1 and uploaded it to the store. I changed to the jpg and still had gloss!

I got to looking around in the plist and realized that the UIPrerenderedIcon was nested inside of “Icon files (iOS 5) >> Primary Icon >> Icon already includes gloss effect”. So I put simply moved it out into the root of the plist and rebuilt. Submitted to the app store and viola! no more gloss.

My guess is because this key was nested the store didn’t see it so it put the gloss effects on as if the key were not there.