25 Oct 2011

Greystripe iPad Banner Ads on AdWhirl

One of AdWhirl's many downsides is limited support for the iPad or tablet devices. House ads are limited to iPhone Portrait (Retina & non-retina), and iPhone Landscape. While AdWhirl will deliver iPad sized ads to the iPad for some networks, the AdWhirl adapter for Greystripe pushes iPhone sized ads to the iPad.

Fortunately, the GSAdEngine.h has defined a set of banner ad sizes that will make it easy for us modify our code to display iPad ads on the iPad.

1. Go into AdWhirlAdapterGreystripe.m

2. Navigate to the - (id)initWithAdWhirlDelegate:... method.

Within the @try block, the current code reads:

3. Change those three lines to this:

Greystripe provides several different ad sizes. I chose the kGSAdSizeIPadLeaderboard for my banner size because it made the most sense in my portrait apps with ads at the bottom. Here are the ad sizes you could substitute:

16 Sep 2011

Add Flurry AppCircle to AdWhirl

I have 3 Apps currently running AdWhirl: Hawaiian WordsHawaiian Names, and Animal Translate Lite.

AdWhirl gives me huge flexibility in switching between multiple Ad Networks (currently using iAd, AdMob, Greystripe, Millennial Media, and InMobi) and House Ads.

I decided that I want to promote my Apps through Flurry's AppCircle, but also earn revenue by advertising with AppCircle too. Since my 3 free Apps already serve ads, adding AppCircle shouldn't effect user experience.

Given the small amount of real estate on an iPhone screen, I wanted the AppCircle ads to display in the same location as the AdWhirl ads, and if possible, not interfere with one another.

I found an elegant solution in AdWhirl's "Custom Events". The remainder of the tutorial will assume that you have AdWhirl installed in an App, and that you have created an account with Flurry, downloaded the Flurry SDK, and created an application within Flurry (Flurry makes this very simple).

Once logged into AdWhirl, click on your App, then click "Add Custom Event" near the top left.

Screen_shot_2011-09-16_at_9

Create a name (I called mine "Flurry App Circle") that will be used within the AdWhirl control panel. Then create a function name (mine is "flurryAppCircle") which will be used in your code. This function name is very important.

Add the Flurry Analytics and Flurry AppCircle folders from the SDK you've downloaded to your Xcode project.

In your AppDelegate.m, add this code at the top:

#import "FlurryAnalytics.h"

#import "FlurryAppCircle.h"

 

Within your application:didFinishLaunchingWithOptions: method, add this code (substituting the Flurry ID generated:

 

[FlurryAppCircle setAppCircleEnabled:YES];

[FlurryAnalytics startSession:@"YOUR_KEY_HERE"];

 

Next, go to the View Controller.h file where your AdWhirlView is set up. Import FlurryAppCircle.h and FlurryAdDelegate.h, and make the view controller a FlurryAdDelegate. I've called my AdWhirlView "adView".

 

#import "FlurryAppCircle.h"

#import "FlurryAdDelegate.h"

 

@interface ViewController : UIViewController <AdWhirlDelegate, FlurryAdDelegate> {

 AdWhirlView *adView;

}

 

Finally, add a method with the same function name you used in your AdWhirl Custom Event setup. You can also add the FlurryAdDelegate method "dataUnavailable" that is called when AppCircle data is unavailable, in order to roll-over the ad banner to a different ad.

 

Create a UIView called "banner" with a Hook (see below), x and y locations at 0, and within your adView. You can also specify the orientation and other features defined in the AppCircle manual. We'll keep it simple for now.

 

If FlurryAppCircle transmits an ad, we find the size of the ad "adSize". We then create a newFrame based on the adSize and center it in the screen. This code will handle both iPhone and iPad sized Flurry ads. We then set the adView frame to our newFrame and redefine the frame of our banner. This step may seem unnecessary, but I've had Flurry ads delivered with an xLocation of -20 even despite defining the xLoc as 0. This is something Flurry should fix.

 

Finally, we replace the old ad with our new Flurry ad. If banner is nil, or if the FlurryAppCircle calls the dataUnavailable delegate method, we simply call [adView rollOver] to go to the next available Ad from another network.

 

 

The "Hook" name is used by Flurry to identify each individual ad banner. I would suggest using different names for each ad banner, so that you can differentiate which ad banners are more effective.

 

Voila! This worked perfectly for me. Comment if you have any questions!

 

If you want to accomplish the same thing in a TableView without covering the TableView contents with the ad, you will need to adjust the frame of the TableView at the same time. Below is the code which is a fairly simple addition to the above example, and can be used in the AdWhirl methods themselves to adjust the TableView when receiving non-Flurry Ads.

 

18 Apr 2011

Play Audio on the iPhone

I want to teach you how to play audio files on the iPhone by clicking a button. I will show you the correct way to handle memory management when playing an audio file (since this often is not addressed).

I will skip the uber-basics of creating an iPhone App since it has been done over and over. If you need to learn from square 1, I suggest reading iPhone and iPad Apps for Absolute Beginners.

First, create a project. I called mine Audio. Next, add the AVFoundation framework. Then, #import <AVFoundation/AVAudioPlayer.h> into your header file. Make your header file implement the <AVAudioPlayerDelegate>.

Create a pointer to an AVAudioPlayer object: AVAudioPlayer *audioPlayer;

Declare the property for the audioPlayer: @property (nonatomic, retain) AVAudioPlayer *audioPlayer;

Declare a method in the header file: - (void)playAudio;

Synthesize your audioPlayer in the .m file: @synthesize audioPlayer;

Be certain to release the audioPlayer in the dealloc method. It is a good idea to use the dealloc method to release any object that has been synthesized.

Finally, we implement the method for playAudio:

We create a NSString which specifies the file name “ha”, it’s type “m4a”, and location: in the main bundle. This is a sample sound from our Hawaiian Names & Hawaiian Words Apps.

The key to this tutorial is memory management, which is why we now create a new AVAudioPlayer pointer object called newAudio and initialize it with the contents of our soundPath (but in URL format as AVAudioPlayer requires).

We can then set audioPlayer equal to newAudio and release newAudio from memory (since it was allocated, we are responsible for releasing it).

Next, set the delegate of audioPlayer to this class (we added the AVAudioPlayerDelegate to the header).

Finally, play the sound.

In order for this App to work, you must connect a button or some other action to call the - (void)playAudio method. This is covered in the book I mentioned.

Why do we create audioPlayer, and not just newAudio? Because we would need to release newAudio somewhere within the method, and if we release it right after we play, the sound gets clipped. There are cases when we could release the AVAudioPlayer object after its BOOL property isPlaying is no longer true, but the structure I have presented allows more flexibility in playing multiple sounds at once and sequentially, such as in our app: Animal Translate.

Full code below:

AudioViewController.h

AudioViewController.m

13 Apr 2011

How to create a "Rate My App" prompt for iPhone & iPad

This code is provided totally free without need for payment, attribution, or any restrictions on modification or use. If you would like to hire Orange Group Apps to implement this in your app, our standard quote for the Rating feature is a flat $50.00 per App. Please contact me: michael (at) orangegroupapps.com

While many users may use and enjoy your app, few users will make the effort to rate it. Even worse, sometimes only those motivated by a passionate dislike of your app will take that effort. To remedy this, I decided to create a prompt to ask users to rate my app.

Take a few things into account:

1. You don’t want it to pop up the first time they launch it, because they haven’t used your app yet. I decided to have it pop up the third time the app is opened. I used an integer called “launchCount” to measure this. (Note: on multi-tasking phones, it must be closed then re-opened to increase the count). 

2. You don’t want to annoy the user. Have the ability to never show the prompt again. (Boolean “neverRate”).

3. If they do click the “Rate my App” button, you should also never show it again after that.

4. They may want to rate your app, but not right now. Give them the option to remind them the next time the app is opened.

I placed the code in the App Delegate. Inside the applicationDidFinishLaunching method, I simply call [self rateApp]; Be sure to add the UIAlertViewDelegate to the header file. You may copy the following code wholesale, but be sure to change the URL to your own iTunes URL (otherwise you’ll be linking to my app: Hawaiian Names), and change the title and message of the alert view.

The - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex method  handles “buttonIndex” as a integer in the order of the buttons you added to your alert. Starting, of course, at 0, which corresponds to “Rate my App”, we make sure the prompt will never pop up again, then send the user to our app page to rate it. At “buttonIndex” 1, which corresponds to Never ask again, we set the “neverRate” BOOL to YES. At 2, which corresponds to “Remind me later”, we do nothing, and the prompt will pop up again the next time the app is launched. 

18 Feb 2011

1000 Lockers Problem

My sister’s friend proposed a logical/mathematical puzzle today that I decided to solve algorithmically. There may be a more efficient way to solve it, and after figuring it out with the program, I found a better way to think about the problem, but I wanted to post the code that I wrote this afternoon to find the answer.

Here is the puzzle: Imagine 1000 lockers in a school. They all start out closed. There are also 1000 people, each given a number corresponding to one of the 1000 lockers. They then go to their locker number (e.g. Locker #14) and each one of it’s factors (e.g. 7, 2, 1) and open it, or close it (if someone else had already opened it). The question is: How many lockers will be open once every person (1 through 1000) has opened or closed their locker number and every factor of that number.

I’ll post the answer at the end in case you want to solve it for yourself. Here is my code:

The answer is 31. It is the number of perfect squares from 1 to 1000.

16 Jan 2011

Set Region Center to Current Location

I’m working on my first contract project which requires a map to show the location of certain venues & events. It will have the ability to locate nearby events by using the user’s location and provide them with search directions to that location.

For some reason, one of the most frustrating parts was what should be quite simple. Starting out the MapView centered on the user’s current location. For everyone’s benefit, here is the code that worked:

10 Jan 2011

UISearchBar & Custom Table Cells

I’ve been working on an iPhone app that involves using the search bar. This is my first time using the search bar, so I’ve collected bits of code here and there from tutorials and reading questions on Stack Overflow. I can’t find the original tutorial that I used, but this one is strikingly similar.

The problem I was having is that I am using a Custom Cell for the Table View which displays data from 2 different dictionaries. A primary label, subtitle, and an image:

Media_httpmediatumblr_rlayo

The - (void)handleSearchForTerm:(NSString *)searchTerm method from the tutorial was built to search and present data from a single NSMutableDictionary. It was successfully eliminating the data from the dictionary containing the primary label when the search terms changed, but not eliminating the data from the secondary label’s dictionary and the image file dictionary (e.g. when I typed “V”, werewolf and ghost were eliminated from their respective dictionary, but not “Howls at the moon” and “Is transparent and haunts you”. And also the werewolf and ghost images were not removed). The result was that when I searched “Vampirism”, the primary label “Vampire” displayed, but the secondary label and the image displayed were from the first entries in their respective dictionaries. I could search “Vampirism” and it would display a picture of a centaur (the first entry in the dictionary), the primary label “Vampirism” and the secondary label “Half-man, half-horse”.

After probably over 20 hours of struggling with this, I finally found a solution. It’s not elegant, and I still am not able to search by both “Monster Name” and “Monster Description”

The solution was to create an NSMutableIndexSet to get the index numbers that correspond to the monster being removed from the “monsters” NSMutableDArray. I could then use that index set to remove the objects from the other two arrays.

Media_httpmediatumblr_gdjkg

Please feel free to reply with any questions, or even to tell me how there is a much better way to do this. And definitely let me know if you have a hint for how to search by text in either the Monster or Description arrays. That will be my next project to solve, and once I tackle it, I will post how I did it.

4 Jan 2011

Introduction

My name is Michael Patzer and I am an iPhone developer for Orange Group Apps. I started learning Objective-C in October, 2010 with no programming background. I started with Neal Goldstein’s books Objective-C for Dummies and iPhone Application Development All-in-One for Dummies. Even the Dummies books were above me, and I didn’t really progress until reading Rory Lewis’ iPhone and iPad Apps for Absolute Beginners. For anyone just starting out, I highly recommend that book.

I am creating this website to help out beginner iPhone programmers.

Michael Patzer's Space

Lead Developer at Orange Group Apps