Apple is Rejecting Its Own Advice

November 30, 2009 6 comments

We’re not sure where to begin, so we’ll pick up the story from our last post: Static Analysis Rejection? That post has been referenced in a number of other articles about App Store rejections by RogueSheep, Daring Fireball, and App Rejections, just to name a few. We’ve had many e-mail conversations with concerned developers asking us for advice before they submit an app that takes advantage of new iPhone features while retaining compatibility with older OS versions. Unfortunately, we’re not sure what to recommend, because as soon as someone like us is rejected for following the rules, someone else reports that Apple has been extra lenient. Of course, this inconsistent behavior is nothing new.

Nobody who’s followed our story will be surprised to learn that our yet-to-be-approved (and new) app was rejected—again—on November 14th. This time, we didn’t receive a rejection e-mail; instead, we happened to login to iTunes Connect and noticed the “Rejected” status. We immediately sent an e-mail to the app review team to ask why we were rejected:

After logging-in to the portal this evening, I see that [new app name] was rejected this morning. However, I have not received an e-mail nor a reason why it was rejected. Can someone please let me know the reason so we can make necessary changes?

For what it’s worth, 16 days later, we have yet to receive any response from Apple.

We speculated that the rejection may have been for the same reason we’ve been rejected many times before…namely that Apple (and/or its static analysis tool) thinks we’re calling private APIs. So, very reluctantly, we decided to create a version that only works on iPhone 3.1 or later, and we’ve submitted it for approval. The new app changed status to “In Review” yesterday morning (November 29th), and we’ll see what happens over the coming days. We’d really like to support customers who haven’t yet upgraded to iPhone OS 3.1 or later, but it appears that Apple is giving us no choice.

Separately, we submitted an update to our existing free app, 3D Camera Lite, on November 20th. It’s a very minor update that adds frequently-requested “Save to Album” and “Send to Facebook” features. While there were no changes at all to the camera functionality from the version that is currently available in the App Store, it was rejected today. You’ll never guess the reason:

Thank you for submitting 3D Camera Lite to the App Store.  Unfortunately it cannot be added to the App Store because it is modifying or extending an undocumented API, which as outlined in the iPhone Developer Program License Agreement section 3.3.1 is prohibited:

“3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs.”

There is no documentation for creating custom subclasses of UIImagePickerController, the organization or layout of the view hierarchy managed by UIImagePickerController, and any of the custom classes managed by UIImagePickerController in iPhone OS 3.0.1.

Camera APIs are available in the iPhone OS 3.1 SDK that allow applications to take pictures, provide camera view overlays, and add custom camera controls.  Please review these APIs to determine if they provide the functionality you require in your product.  If your product requires additional functionality that is not provided by the Camera APIs in the iPhone OS 3.1 SDK, please file an enhancement request using the Apple Bug Reporter, <http://bugreport.apple.com>.

Our speculation is that we’ve been bitten yet again by the static analysis tool. 3D Camera Lite runs on iPhone OS 3.0 or later, and we check the OS version before calling any of the new 3.1 APIs…exactly as Apple recommends in its own documentation. For 3D Camera Lite, we’re not sure what to do, so we’ve written e-mail to the app review team hoping for a useful response. We don’t want to require that users upgrade to OS 3.1 just to use this minor update. If we are left with no other choice, we may have to cancel this update, and that will only hurt our users.

Perhaps you’re wondering what Apple’s documentation has to say about using newer API features while remaining compatible with older versions. Well, in a post to the iPhone Dev Center on November 20th (how timely) titled “Adding iPhone OS 3.x Features to Your iPhone OS 2.x-compatible Apps,” they state:

By using “weak linking” in your Xcode project, you can include frameworks you’ll need for the newer features, and check for API availability when your application is running. This technique provides you with the broadest possible audience for your application.

Later, the same post references Apple’s SDK Compatibility Guide. In a section titled “Checking for Undefined Method and Function Calls” they state:

To run successfully, your code must avoid calling methods and functions in system versions that do not support them. It can do this either by checking the system version at run time and globally taking a different code path based on the version, or by checking for the existence of each Objective-C method or C function before calling it.

In the interest of full disclosure, here’s the relevant code from 3D Camera Lite and the yet-to-be-released app:

// If running OS 3.1 or newer, add overlay view
if (osVersion >= 3.1f)
{
    imagePicker.showsCameraControls = NO;

    // Add overlay view and controls
    imagePicker.cameraOverlayView = cameraView;
}

The showsCameraControls and cameraOverlayView properties are only available in iPhone OS 3.1 and later, which is why we follow Apple’s advice and check for the correct OS version before using them.

Frustrating.

Update on 12-1-2009: This morning, we received a response from Apple regarding 3D Camera Lite:

Thank you for your email. It would be appropriate to set the minimum OS to 3.1.  Once the needed changes have been made to your application, please resubmit your binary to iTunes Connect. Thank you.

Based on this response, it sounds like Apple’s own documentation is misleading at best. Our takeaway is that Apple isn’t interested in supporting users who haven’t upgraded to the latest iPhone OS version. So, reluctantly, we’ll resubmit a version that requires OS 3.1 or later.

Second update on 12-1-2009: This evening, Apple approved our new app called Spy Pix. While we’re thrilled to have it released, we’re disappointed that it requires iPhone OS 3.1 or later. Unfortunately, this appears to further confirm our suspicions.

Static Analysis Rejection?

November 7, 2009 6 comments

Mobile Orchard pointed to a post by Joe Hewitt (developer of the Facebook iPhone app) where he mentions that Apple may be using a static analyzer to help review app submissions. If that’s the case, it might explain our recent rejections. Here’s the boilerplate response that we’ve (unfortunately) come to expect each time we submit an app. This is from a recent rejection:

Thank you for submitting 3D Camera & 3D Camera Lite to the App Store.  Unfortunately it cannot be added to the App Store because it is modifying or extending an undocumented API, which as outlined in the iPhone Developer Program License Agreement section 3.3.1 is prohibited:

“3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs.”

There is no documentation for the custom subclasses or self-contained views of UIImagePickerController in iPhone OS 3.0.1.  This includes PLCameraView and its custom subclasses (PLImageTile, PLRotationView, PLImageScroller, PLImageView, PLCropOverlay, PLCropLCDLayer, TPBottomDualButtonBar, TPPushButton and TPCameraPushButton).

Additional Camera APIs are now available in iPhone OS 3.1.  Please review these new APIs to see if they meet your needs.  If any additional APIs are desired, please file an enhancement request via the Bug Reporter, <http://bugreport.apple.com>.

While we haven’t announced anything on our site yet, we’ve been waiting for Apple to review a brand new Juicy Bits app that also happens to use the camera, and guess what? It was rejected for exactly the same reason (same text, except for the app name).

Funny thing is, neither 3D Camera, 3D Camera Lite, nor the yet-to-be-approved app use any undocumented APIs at all! As a matter of fact, all three apps have been built using 3.1.x SDKs, and they all use the new official camera APIs to implement their overlays. For astute readers, yes, this is exactly what Apple recommends that we do in the last paragraph of their rejection e-mail!

The nuance is that while we’ve compiled these apps using 3.1.x SDKs, we’ve set the minimum iPhone OS Deployment Target to 3.0 so that the apps will run on older devices (read the section titled Specifying the Runtime Environment in Apple’s Running Applications documentation for a good explanation). We still have a lot of users running 3.0.x devices, and we want to make sure they can upgrade and use our apps.

In the code, we check to see if the app is running on a 3.1.x device before calling any of the new 3.1.x APIs (like the camera overlay). If the app is running on an older 3.0.x device, we don’t use the new APIs and the standard built-in camera controls are used. This is exactly what Apple’s documentation says we should do.

For 3D Camera and 3D Camera Lite, Apple asked that we set the minimum OS to 3.1 and re-submit. Presumably, this is because the reviewer saw the camera overlay and also noticed that the app would run on a 3.0.x device. Our guess is that the reviewer never tried the apps on a 3.0.x device to see that the camera overlay feature is disabled. Because so many of our users are still running a 3.0.x device, we chose to ignore this advice and instead tried to explain the situation to Apple. After a very slow and non-interactive e-mail exchange, 3D Camera and 3D Camera Lite were both approved.

So, we weren’t surprised when our yet-to-be-approved app was rejected for the same reason, since it uses identical camera overlay code and logic and runs on 3.0.x devices. Thus begins the very slow e-mail “conversation” to re-explain the same situation all over again. It’s frustrating, because we’re doing exactly what Apple wants us to do, yet we’re paying for it with very long delays.

We’re now wondering if the static analysis tool sees the 3.1.x API call in our app, notices that it runs on 3.0.x devices (that don’t support the new APIs), and flags or rejects it as a result. This would actually make sense! The only problem is that the tool appears to be ignoring the code where we check the device version before making that call, and that may be the nuance that’s causing all of our delays.

Of course, we’re only speculating about the static analysis rejection, because we don’t know how Apple reviews apps for the App Store. Like others, we try to reverse engineer the black box that is the approval process, and also like others, we wait.



PHVsPjxsaT48c3Ryb25nPndvb19hZGRibG9nPC9zdHJvbmc+IC0gdHJ1ZTwvbGk+PGxpPjxzdHJvbmc+d29vX2Fkc19yb3RhdGU8L3N0cm9uZz4gLSB0cnVlPC9saT48bGk+PHN0cm9uZz53b29fYWRfaW1hZ2VfMTwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTEyNXgxMjUtMS5naWY8L2xpPjxsaT48c3Ryb25nPndvb19hZF9pbWFnZV8yPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tL2Fkcy93b290aGVtZXMtMTI1eDEyNS0yLmdpZjwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX2ltYWdlXzM8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb20vYWRzL3dvb3RoZW1lcy0xMjV4MTI1LTMuZ2lmPC9saT48bGk+PHN0cm9uZz53b29fYWRfaW1hZ2VfNDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS9hZHMvd29vdGhlbWVzLTEyNXgxMjUtNC5naWY8L2xpPjxsaT48c3Ryb25nPndvb19hZF91cmxfMTwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX2FkX3VybF8yPC9zdHJvbmc+IC0gaHR0cDovL3d3dy53b290aGVtZXMuY29tPC9saT48bGk+PHN0cm9uZz53b29fYWRfdXJsXzM8L3N0cm9uZz4gLSBodHRwOi8vd3d3Lndvb3RoZW1lcy5jb208L2xpPjxsaT48c3Ryb25nPndvb19hZF91cmxfNDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbTwvbGk+PGxpPjxzdHJvbmc+d29vX2FsdF9zdHlsZXNoZWV0PC9zdHJvbmc+IC0gZGFya2dyZWVuLmNzczwvbGk+PGxpPjxzdHJvbmc+d29vX2F1dG9faW1nPC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19ibG9nY2F0PC9zdHJvbmc+IC0gL2NhdGVnb3J5L2Jsb2cvPC9saT48bGk+PHN0cm9uZz53b29fYmxvZ19jYXRfaWQ8L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19jYXRtZW51PC9zdHJvbmc+IC0gZmFsc2U8L2xpPjxsaT48c3Ryb25nPndvb19jdXN0b21fY3NzPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fY3VzdG9tX2Zhdmljb248L3N0cm9uZz4gLSA8L2xpPjxsaT48c3Ryb25nPndvb19leF9mZWF0cGFnZXM8L3N0cm9uZz4gLSB0cnVlPC9saT48bGk+PHN0cm9uZz53b29fZmVhdGhlaWdodDwvc3Ryb25nPiAtIDwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlYXRwYWdlczwvc3Ryb25nPiAtIDUzNiw0NjYsNiw5NTwvbGk+PGxpPjxzdHJvbmc+d29vX2ZlZWRidXJuZXJfdXJsPC9zdHJvbmc+IC0gPC9saT48bGk+PHN0cm9uZz53b29fZ29vZ2xlX2FuYWx5dGljczwvc3Ryb25nPiAtIDxzY3JpcHQgdHlwZT1cInRleHQvamF2YXNjcmlwdFwiPg0KdmFyIGdhSnNIb3N0ID0gKChcImh0dHBzOlwiID09IGRvY3VtZW50LmxvY2F0aW9uLnByb3RvY29sKSA/IFwiaHR0cHM6Ly9zc2wuXCIgOiBcImh0dHA6Ly93d3cuXCIpOw0KZG9jdW1lbnQud3JpdGUodW5lc2NhcGUoXCIlM0NzY3JpcHQgc3JjPVwnXCIgKyBnYUpzSG9zdCArIFwiZ29vZ2xlLWFuYWx5dGljcy5jb20vZ2EuanNcJyB0eXBlPVwndGV4dC9qYXZhc2NyaXB0XCclM0UlM0Mvc2NyaXB0JTNFXCIpKTsNCjwvc2NyaXB0Pg0KPHNjcmlwdCB0eXBlPVwidGV4dC9qYXZhc2NyaXB0XCI+DQp0cnkgew0KdmFyIHBhZ2VUcmFja2VyID0gX2dhdC5fZ2V0VHJhY2tlcihcIlVBLTg5MTI0ODctMVwiKTsNCnBhZ2VUcmFja2VyLl90cmFja1BhZ2V2aWV3KCk7DQp9IGNhdGNoKGVycikge308L3NjcmlwdD48L2xpPjxsaT48c3Ryb25nPndvb19ncmF2YXRhcjwvc3Ryb25nPiAtIHRydWU8L2xpPjxsaT48c3Ryb25nPndvb19pbWFnZV9oZWlnaHQ8L3N0cm9uZz4gLSAyNTA8L2xpPjxsaT48c3Ryb25nPndvb19pbWFnZV93aWR0aDwvc3Ryb25nPiAtIDM5MDwvbGk+PGxpPjxzdHJvbmc+d29vX2ludHJvPC9zdHJvbmc+IC0gV29uZGVyaW5nIHdoZXJlIHRvIGdldCBmcmVlIDNEIGFuYWdseXBoIGdsYXNzZXM/IENoZWNrIG91dCB0aGUgPGEgaHJlZj1cImh0dHA6Ly93d3cuanVpY3liaXRzc29mdHdhcmUuY29tL2ZhcS9cIj4zRCBDYW1lcmEgRkFRPC9hPi48L2xpPjxsaT48c3Ryb25nPndvb19sb2dvPC9zdHJvbmc+IC0gaHR0cDovL3d3dy5qdWljeWJpdHNzb2Z0d2FyZS5jb20vaW1hZ2VzL2p1aWN5LWJpdHMtaGVhZGVyLWxvZ28td2l0aC1zdWJoZWFkLnBuZzwvbGk+PGxpPjxzdHJvbmc+d29vX21hbnVhbDwvc3Ryb25nPiAtIGh0dHA6Ly93d3cud29vdGhlbWVzLmNvbS90aGVtZS1kb2N1bWVudGF0aW9uL292ZXItZWFzeS88L2xpPjxsaT48c3Ryb25nPndvb19tZW51cGFnZXM8L3N0cm9uZz4gLSA2LDk1LDEwMSwxMjIsNDY2LDUyODwvbGk+PGxpPjxzdHJvbmc+d29vX3Jlc2l6ZTwvc3Ryb25nPiAtIHRydWU8L2xpPjxsaT48c3Ryb25nPndvb19zaG9ydG5hbWU8L3N0cm9uZz4gLSB3b288L2xpPjxsaT48c3Ryb25nPndvb190aGVtZW5hbWU8L3N0cm9uZz4gLSBPdmVyIEVhc3k8L2xpPjxsaT48c3Ryb25nPndvb190aGVfY29udGVudDwvc3Ryb25nPiAtIHRydWU8L2xpPjwvdWw+