iPhone Dev « Tonny Xu
...Life is like a box of chocolates,
you never know what you’re gonna get...
» iPhone Dev «

After I finished an iPhone project, I decided to create a similar project based on that one. So, I copied the previous project directory to an new directory and build it. Everything goes fine, the new project was correctly signed and installed on the machine, the icon and Default.png was correctly displayed.  But, only one thing was out of my expectation.

I installed the debug version of the previous project on the simulator and want to compare the look and feel, but after I install the new project, which was derived from the old project, on the iPhone simulator, shit happened! The old project was disappeared! Only the new project was there. I checked the project setting over and over again and got no clue completely. This drove me mad! Was it because I did not rename the project? I simply copied to a new directly, without changing the project name. Nope, it wasn’t. Was it because I set the wrong Product Name? Nope, it was not. What made the iPhone thinks this 2 apps were the same?

After I googled and tried a lot, just before I want to give up, I suddenly saw a key in info.plist file. the key is “Bundle Identifier“. Oh My GOD! It should be the reason! My instinct told me! I added some suffix to the identifier to make it unique, then try again on the simulator, it WORKED! It’s the reason!

Yes, iPhone Programming Guide told us every project need an unique identifier, thus Apple recommend us use the Java Package Style to identifier each app. But if you are copying project from here to there, you might miss this because without modify it, the app also worked fine. Dude….

I hope this would help you if you are facing similar problem as me.

Comments

iPhone app developers are facing their hard worked app appears on the pirate app web site the day after it appears on iTunes. So you must want to protect your app as I do, right? But how? What’s the best way to protect your apps?

Here is the best practice by far I know. And it’s really simple and easy to do with. As far as Doskoi know, every hacked iPhone app need to add a key to the info.plist file. They need to add this:

SignerIdentity
Apple iPhone OS Application Signing

So it would be easy for us to detect whether your app was pirated or not. Simply using the following code to protect your apps.

 NSBundle *bundle = [NSBundle mainBundle];
 NSDictionary *info = [bundle infoDictionary];
 if ([info objectForKey: @"SignerIdentity"] != nil)
 {
 // Add your anti-pirate code here.
 }

Hope it will help you.

Doskoi’s Lounge » iPhone软件的破解保护.

Comments

Yes, I knew, I am SO stupid, I should Google it before I started to change the XCode project name. It cost me a whole day! What a joke.

All right, if you are looking for the correct way to change your application’s name show on the iPhone main screen. You need follow my steps.

  1. Scroll the left “Groups & Files” panel to the top(Where you put it, I putted it in the left.), and double-click your project name. This will lead us to step 2.
  2. In the Build tab, find the configuration dropdown list, select “All configurations”(Usually, on the top), and then type “Product Name”(It’s not case sensitive, remember the space) in the search box next to the dropdown list.
  3. Type whatever name you like in the right side field, and then close it and go to step 4.
  4. Choose Build->Clean all targets, then rebuild your project, It’s done!

Remember! Do NOT change your target or add your own target! That’s the wrong way, and will cause code sign failure, and it’s hard to repair!

God, Damn you Apple, you should post a tutorial for the developer. Now I did it for you, and you should pay me!

Comments

Problem

Few days ago, I wrote a post on which is the best audio format we should choose when developing an iPhone app. The conclusion is using IMA4, it’s the best choice if you want to record audio on the device.

Today, I was trying to use the System Sound service to play a short audio and in order to save the spaces, I chose the “AAC” format to encode my sound effects. I just thought it’s would be capable for a system sound and didn’t searched the documentation for which format is suit for System Sound. Everything went fine in the simulator. But, when I load the app into the device, and, BOOM~~, it failed to play the sound effect! My first reaction was somewhere programmatic mistake in my code, and after a careful review, I thought the reason could  be the format. So I changed the format back to IMA4, and this time, it went well!

Apparently, System sound did not support AAC format, and I could not find the appropriate document where described it. Apple just pushes us to use IMA4 and other linear PCM format to reduce the CPU and power consume. Yeah, I understand that, but please, place such kind of important information some where we can find it easily! The API documentation could be a good place.

If I am the director of the documentation team, I would promote such information and place it in a notable place! Damn it.

Why I’m angry?

Because if you using AAC for recording or System Sound, it works fine on the simulator, but will be failed on the device! If the device does not support AAC for recording and System Sound, please disable it on the simulator!

Conclusion

The conclusion is if you want to playback a song or something like this, you can choose AAC as your primary format for it is well supported by hardware codec, but only for this purpose please. If you want to record audio or play system sound effect, please choose IMA4, it’s is the second best format for iPhone.

“AAC” is a good compressed format, but it’s also has its cost.

Comments

My app is still not online now, because I have to fix some autorotation problems. Before today, I really didn’t know how to enable autorotation when my app is combined with UITabBarController and UINavigationController and my own views. After doing a little search, The solution is I need to enable autorotation for every view controller that will be presented in the UITabBarController.

Let’s assume we have a UITabBarController, theTabBarController and 3 UINavigationController named A, B, C. We need to set all the three controllers(A, B, C) to return YES in this method:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return YES;
}

OK, now your tab bar and navigation bar and your views will be automatically rotated.

Comments

Yesterday, technically, today, June 8th, is the iPhone Day! WWDC was opened about 14H ago, and almost all the main IT news channel are full of iPhone, We really need to celebrate it, 8th June, the iPhone Day.

OK, Let me tell you what’s my interest in iPhone Day.

  • The Rumor was real!
  • The new iPhone release date, June 19, was a little bit earlier than I expected.iPhone3GS, Release Date
  • Will Apple unlock the CPU limitation of current iPhone 3G? Still unknown.
  • In App Purchase is really, really what I need. But I could not catch the iPhone 3GS release time.Picture 5
  • I must work much more hard to get my app released.

Damn it, I like iPhone!

Comments

AVAudioPlayer is providing a very convenient way to play iPhone supported audio file. Especially, if you want to implement fast forward and rewind, AVAudioPlayer is the best choice.

But I just found an odd problem. If I use [AVAudioPlayer pause] method, next time if I invoke [AVAudioPlayer play], it had no responde. But after I changed pause to stop, it worked fine. The problem looks like it somewhere inside AVAudioPlayer to control the AudioQueue Object to resume playing. Whatever, by using [AVAudioPlayer stop], you can archive the same goal as [AVAudioPlayer pause] do, I mean FFW and RWD.

BTW, the document said, pause will return YES/NO, but clearly, it is a no return value instance method. The guy who is responsible for this method might copied the same comment from play!

Picture 1

What a joke. This line was there since iPhone 2.2, and is still there in 3.0b5. Didn’t there anybody reported this problem? Should I fire a bug?

Comments

Problem

I’ve been fighting for AVAudioPlayer and AudioQueue object for 2 days,

Here is my Dev environment:
iPhone: 3.0Beta 5
OSX 10.5.7

Here is my scenario:
1. I need to use AVAudioPlayer to play a CAF with IMA4 data format. Including fast forward and rewind.
2. I need to use AudioQueue Object to record audio, because 3.0 has not go public yet.
3. A common scenario is record an audio A, then play the original audio A’(Not the one recorded) or vice versa.

The problem is I could NOT play the A’ file  after I record file A.
[theAVAudioPlayer play] always return NO, but [theAVAudioPlayer prepareToPlay] return YES.
This situation only happened after I used the AudioQueue Object for recording. If I did not record, it always worked fine.

About the clean up.
1. I released the theAVAudioPlayer object and set to nil each time after I finished playing.
2. I closed the audio file and deposed the AudioQueue Object each time after I finished recording.

Solution

Thanks to Vitali Molodtsov[Open the original post Needs login], the solution is reset the AudioSessionCategory to kAudioSessionCategory_MediaPlayback just after finish recording. Then every thing goes fine.

Conclusion

I think this is a bug for AVAudioPlayer. Each time, when we initialize an AVAudioPlayer object, it should set the correct AudioSessionCategory for us silently, but it doesn’t. So I’ve fired a bug for Apple.

Comments

Thanks to Barry Wark From [Here]

Create a header file like

// Constants.h
extern NSString * const MyFirstConstant;
extern NSString * const MySecondConstant;
//etc. 

You can include this file in each file that uses the constants or in the pre-compiled header for the project.

You define these constants in a .m file like

// Constants.m
NSString * const MyFirstConstant = @"FirstConstant";
NSString * const MySecondConstant = @"SecondConstant"; 

Constants.m should be added to your application/framework’s target so that it is linked in to the final product.

The advantage of using string constants instead of #define constants is that you can test for equality using pointer comparison (stringInstance == MyFirstConstant) which is much faster than string comparison ([stringInstance isEqualToString:MyFirstConstant]) (and easier to read, IMO).

Comments

Today I met a weird exception from AUGraphStart().

Basically, I was running an old sample code written by myself. The main function is mix 2 audio files a playback them simultaneously. I worked fine before, but when I run it, I got this exception:

[00:23:58.425 <AURemoteIOServer>] AQMEIOBase::DoStartIO: timeout
[00:23:58.701 <AURemoteIOServer>] AQMEDevice::StartIO: AudioOutputUnitStart returned -66681
[00:23:58.701 <0xa084a720>] AUIOClient_StartIO failed (-66681)
AUGraphStart FFFEFB87 

Obviously, it wasn’t came from my code, and I have no idea on this exception now. Did anybody get a same exception recently?

I had tried these:

   1. Restart the XCode. — No effects.

   2. Restart the machine(Mac Pro, 10.5.7), and restart the XCode. — No effects.

   3. Reinstall the most recent SDK(Build 9M2735), restart the XCode. — No effects.

   4. Set the base SDK to 2.2.1 and target to Simulator 2.2.1 Debug. — No effects.

It’s really odd!

Please, if anybody had met similar exception and got a solution, help me out!

Still don’t know how to resolve it now. I need  help!

[Update 2009-06-11]

A week ago, Apple’s engineer had confirmed that they had a bug in UIKit framework.

We do have a simple workaround for this UIKit bug. In UILocalizedIndexedCollation.hm change this:

  UIKIT_EXTERN @interface UILocalizedIndexedCollation : NSObject

to

  UIKIT_EXTERN_CLASS @interface UILocalizedIndexedCollation : NSObject

Having done that, we can build your project and confirm that AUGraphStart returns 0 in the 3.0 simulator.

 

But, after I installed the 3.0 GM Version today, it’s still not included in the GM Version. So that means I still can not play audio in the simulator. I can ONLY do it on the device!

Comments