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:
I have 3 Apps currently running AdWhirl: Hawaiian Words, Hawaiian 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.
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.
(image/png)
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
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.