Friday, May 5, 2017

Xcode 8.3: How to Migrate off of PackageApplication

Our iOS build server happily created IPA files until we upgraded to Xcode 8.3. Now, instead of delivering our applications, our server complains:

xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH

And that's how a ten-minute Xcode upgrade became a several-hour project. On Xcode 8.2 and earlier, we used PackageApplication to generate an IPA file from an xcarchive:

xcrun -sdk iphoneos PackageApplication "$ARCHIVE_PATH/Products/Applications/$\" -o "somePath/buildName.ipa"

The command was simple. It took the app file in the xcarchive as input, and it created an IPA file named exactly as the -o flag indicated. Too bad they deprecated and removed it!

My research indicated that the replacement command was xcodebuild -exportArchive, but the documentation didn't explain very much. Let me save you a lot of work. The new command looks like this:

xcodebuild -exportArchive -archivePath "$ARCHIVE_PATH" -exportPath "somePath" -exportOptionsPlist "$SRC_ROOT/aNewPlist.plist"

The argument to -archivePath is the path to the xcarchive, not to the .app file inside of it. If you accidentally specify the path to the .app file, you'll get this cryptic message:

error: exportArchive: exportOptionsPlist error for key 'method': expected one of {}, but found enterprise

The -exportPath is a directory where you want the IPA file to be saved -- you no longer can control the name of the exported IPA file. Luckily, you can provide a path that ends in a directory that doesn't exist yet -- -exportArchive will create that new directory for you and deposit the IPA file inside of it.

The -exportOptionsPlist is a new input! You must supply a path to a plist file which describes some options for the export. You can use xcodebuild -help to see how to configure the plist file. As far as I can tell, the method key is the most important item to have. You can find example plists for -exportOptionsPlist online. Xcode can help you create and edit the plist file.

Good luck, and I hope this helps!

Sunday, March 20, 2016

ERROR ITMS-90164 ... the bundle contains a key value that is not allowed: 'true' for the key 'get-task-allow'

You're trying to upload your iOS app to the App Store and you keep getting this mysterious error:

ERROR ITMS-90164: "Invalid Code Signing Entitlements. The entitlements in your app bundle signature do not match the ones that are contained in the provisioning profile. According to the provisioning profile, the bundle contains a key value that is not allowed: 'true' for the key 'get-task-allow' in ...

Maybe you've successfully uploaded the same app before. Maybe git proves that nothing has changed with your entitlements, code signing, or the provisioning profile you're using. You're probably frustrated.


Somehow the Code Signing Identity for Release had switched to development. You can find this in the Build Settings for each target. In the project file. Make the settings look like the above screenshot and you should be set.

Saturday, July 18, 2015

Your App Stutters in iOS 9?

Did you try your app out on iOS 9 and discover that the audio or UI was stuttering?

I just spent a few hours with Instruments and an iOS 9 beta (the July 8, 2015 iOS 9 beta 13A4293g) trying to figure out why Modern Metronome was skipping a beat. Timers would sometimes fail to start an animation at the correct time, and some Audio Queue requests weren't getting fired at all.

Funny, everything worked fine in iOS 8.

I optimized several methods that seemed to be problematic, but the stuttering remained. I finally got down to these two calls:

[AVAudioSession setCategory:withOptions:error:]
[AVAudioSession setActive:error:]

It turned out that I was calling them both every time that I created an Audio Queue. On iOS 8, these repeated calls didn't have any noticeable effect. On the iOS 9 beta, they have larger performance consequences than Instruments implies.

I moved those two lines so they would only get called once, and my stuttering disappeared. I hope this helps you!

Saturday, February 15, 2014

Error: ImageIO: PNG Not a PNG file

<Error>: ImageIO: PNG Not a PNG file

Does your iOS app log the above message and fail to render an image? Do you feel completely befuddled? You're in the right place.

I recently spent a lot of time debugging a problem where an UIImage vanished after doing a perfect job of rendering. Reproducing the bug required four big steps to reproduce. The steps involved around thirty classes total. There were view controllers, file operations, and many views. Stepping through the code in the debugger took ages.

If you need an excuse for removing unnecessary log statements from your app, consider this. The whole time I was debugging the app, the ImageIO log message was hiding among the normal verbose messages in my app. If my app logged zero messages in normal operation, I would have noticed a new one much sooner.

But why did my image disappear? To begin at the end, the log message was 100% accurate. The PNG file wasn't a PNG file. It was a JPEG.

But how did the UIImage ever render to the screen if it tried to open a JPEG as a PNG? It didn't. It opened a PNG as a PNG. Of course.

But at some point the app wrote over the PNG with the same image in JPEG format. If you read the documentation for + (UIImage *)imageWithContentsOfFile: you'll see the phrase that made me smack my forehead:

"does not cache the image"

Oh snap. So our app opened the image, displayed it, and then at some point decided to save space by re-writing the file as a JPEG. But the UIImage was still open. In the next run through drawRect:, the UIImage went back to the file only to discover that its PNG wasn't a PNG. And so the image did the only think it knew how to do: vanish.

The fix I decided to use was to replace the UIImage when the file changed. Now to prune those NSLog()s from the app!

Monday, April 26, 2010

Adding Unit Tests to an Existing Android Project

I looked for tutorials on how to add Unit Testing to an existing Android Project, but wasn't able to find anything too recent or complete. There is probably more than one way to do this, hopefully you'll find mine useful. This applies to Android 2.1 using Eclipse

I performed the following steps in the same workspace as the project I wished to write Unit Tests for.

1. File::new::Project...

2. Select Android::Android Test Project.

3. Click Next.

4. Name the test project, Select the project you want to write tests against with the "An existing Android Project" field (use the browse button).

5. Click Finish.

6. In the test project you just created, create a new source file with File::New::JUnit Test Case.

7. In the dialog, select "New JUnit 3 test", the source folder should correspond to the new test project you just created. The package should be the test package of the new project. Name the class as you wish (e.g. FooTest). For "Class Under Test" you can browser and pick a class from the project you wish to test.

8. In the new test class you created, create a JUnit test method. The name of the test method needs to start with "test" (e.g. testFooBar). You can use junit.framework.Assert methods to test the conditions you expect.

9. Run the test cases by clicking Run::Run as::Android JUnit Test.

10. The test results will appear in a JUnit perspective on the left side.

Am I missing any steps? Have I missed any nuance or a better way to do it? Help me out and comment below.

Friday, May 23, 2008

Engineers, Experience, and Education (Part 1)

My first real experience with a co-op started as I waited nervously at the Gainesville Regional Airport. If you've never been to anything but a big international airport, you're missing out.

The Gainesville Airport had two gates but they didn't have those motorized hallways that dock to a plane. At this airport the passengers were faced with two normal doors that opened directly on the tarmac. At boarding time everyone was expected to walk across the taxiway, step on a stool, and climb into the plane. Just like Casablanca.

I didn't pay for my ticket. A rental car and a room at the Embassy Suites awaited my arrival in Austin. All my expenses were covered by the interviewing company. The next day would be busy with a drug test, interview, and flight back to Florida. I was nervous, but I was excited too.

Why You Want an Internship or Co-op

I distinctly remember how exciting internships and co-ops seemed when I first learned about them. Sadly, I was probably almost three years into my degree. When a professor encouraged my Microcontrollers class to get co-ops (or an internship, they're similar), this is what stuck in my head:
  • Co-ops are paid! Instead of me paying to learn, some company might pay me to learn. Not only that, but many Co-ops pay quite well.
  • Co-ops often will take you to new cities, even new states. Sometimes a company will fly you out somewhere, feed you, and entertain you just for an interview. If you get an offer, many companies will pay to help you move there and then back to school.
  • No homework. Go to work to work. Come home and relax, just like a normal human being.
  • Get real experience to put on your resume and discuss in interviews.
  • Work on real problems. Unlike school, people actually notice when you solve a problem. Your work is appreciated.
Co-ops and internships sounded awesome. A semester of adventure instead of school. How had I not heard this before? I told all my engineering friends and immediately started to look for opportunities.

When the career fair came to campus, I attended with the goal of getting an interview for a Co-op. The fair was held in the O-dome, a big sports arena with a air-supported roof. Inside, both levels of the arena were jammed with booths for every sort of company imaginable. There were Fortune 500 giants next to tiny companies I'd never heard of.

I walked up to the first big booth and stepped in line. In front of me, four or five students in identical black suits waited for the chance to talk to a recruiter. I watched each in turn perform the same ritual.

Each student would step forward, shake hands, and hand a resume to the recruiter. The recruiter and student would chat for a few minutes. The recruiter occasionally made a mark on the resume. Then finally the recruiter would hand the student a brochure, pen, t-shirt, flashlight, or some other marketing device before the student left. The resume fell into a huge stack. It was an assembly line.

A similar performance repeated for me at each booth. A chat, a trade of papers, and goodbye. Although I stopped at lots of booths, I never got an invitation to further interviews. It felt like an awkward school event. I talked to a bunch of girls, but I never quite figured out how to ask for a dance.

And yet somehow I ended up with an interview and an actual co-op a few months later. But I'll save that story for a later post.

The Book on Internships and Co-ops

If you're a student, especially one in a technical field, please check out my recently published book Conquering Your Engineering Internship: Planning, Getting, and Making the Most of an Internship or Co-op. I think the book is a great resource to help you with every aspect of an internship or co-op: getting hired, learning new skills, making a good impression, having an adventure, and otherwise changing your life for the better. Others agree -- just check out the reviews on Amazon.

I strongly believe that engineering students and recent graduates will benefit greatly from the knowledge in my book. I believe it so strongly that the book is currently available for free download on my publisher's website. Even if you can't afford the paperback, please take a look at the download -- you can buy the hard copy when you get a paying internship. I'd love to know what you think.

Thursday, February 7, 2008

Video Lecture on How to Lecture

I just watched a recursive lecture by Patrick Winston. It explained how to lecture using lots of zany little stories and interesting concepts.

Patrick mentioned one interesting idea he called the "near miss". This technique illustrates concepts by demonstrating what isn't part of the concept. For instance, he demonstrates several techniques which do not make for a good lecture.

One final tidbit from the video: Patrick mentioned that he didn't believe people could learn concepts they didn't already almost know. Interesting notion.Watch the video.

Video Link.

Via Ramit Sethi's feed. Link.