REJECTED: My own app! (BrainGame:Summation)
Oh, the irony! I, the author of a blog collating app rejection reasons, just got an Update rejected, for Summation. I’m still chuckling over this :).
I was using a VERY common workaround to some bugs in the official Apple APIs. So common that I’d forgotten they were even in there! Fortunately, several other people have been rejected in the last week for the same reason (as I said, it’s a *common* workaround). So, here’s the problem, and a NEW workaround (which others claim has passed submission; I’ll let you know how it works out for me).
A brief aside
I’ve had updates rejected before – although not until I’d been developing on iPhone for more than 6 months. Usually you just get an automated email. Today, I got a personal phone call – international to the UK.
Not hugely helpful – it was purely “it’s being rejected, this is the only problem, fix this and you should be OK” – but a lot more friendly and humane than the old process.
Problem
Apple’s UIAlert class does some internal rendering tricks that mean it displays incorrectly when you add views to it.
Original workaround (DON’T USE THIS!)
To get around this, whenever Apple apps ask you for a password, they’re using two undocumented API calls:
addTextFieldWithValue:label:
textFieldAtIndex:
We all knew they were technically undocumented – but it was obvious that they:
- Work perfectly well: Apple (apparently) uses them
- Were intended for doing exactly what we needed
- Are a lot cleaner than trying to hard-code a custom workaround to the original bug(s)
Only … now, with the new static analysis tool … you won’t be getting through submission with them in.
New workaround (PARTIAL)
Basically … instead of using the private “this worksaround the problem” method calls, instead just put newline characters in your text. Yes, really.
NB: this is ABSOLUTELY a buggy, inferior workaround to the one everyone was using to date. There is literally NO GOOD REASON for Apple to make us do this – they are forcing us to make our applications more likely to break in future. But hey. That’s their choice – it’s their platform.
I’d already noticed this workaround on iphoneDevSDK.com, and looking through the source, I’m pretty sure this will work. I’ll update this post if/when it passes re-submission!
UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:@”title”
message:@”message\n\n”
delegate:self
cancelButtonTitle:”@Cancel”
otherButtonTitles:@”Ok”, nil];myAlert.frame = CGRectMake( 0, 0, 300, 260);
UITextField *myTextField = [[UITextField alloc] initWithFrame:CGRectMake(32.0, 65.0, 220.0, 25.0)];
myTextField.placeholder = @”Your Name”;
myTextField.delegate = self;
myTextField.tag = 1;
[myAlert addSubview:myTextField];
CGAffineTransform myTransform = CGAffineTransformMakeTranslation(0.0, 75.0);
[myAlert setTransform:myTransform];
[myAlert show];
[myAlert release];
November 25th, 2009 at 9:36 pm
Why do all my UIAlerts display fine?
With no trickery at all???
Can you post a screen-shot of the “bad UIAlert” page?
[ADMIN: please note; "Donna" and "Jill" are the same person (with spoofed email addresses)]
November 26th, 2009 at 4:54 am
Its kind of ridiculous to think that you should be able to use private interfaces. The reason they are private is because they may change in the future to something that is better expressed for public consumption.
November 26th, 2009 at 12:37 pm
@Donna, Joe
Just for you guys … I’ll write a post specifically about the realities of Private API’s very soon…
November 26th, 2009 at 6:44 pm
@Joe: Your point doesn’t make a lot of sense. Once it is used in a production app by the vendor, a “private” function becomes a integral part of the OS (of course, “private” is a misnomer; it is clearly not a private call. Traditionally calls that are fully functional and accessible to developers while being left out of the official spec and frowned on by the OS manufacturer are called “undocumented”). If the function is replaced by something that “works better”, Apple corporate developers will be faced with the same issues that 3rd party developers would be.
Apple learned it’s lessons from Bill Gates well. This is the exact method he used to keep 3rd party developers from being able to compete with applications made by MS all through the DOS era. But Jobs has created Gates’ wet dream. MS had to move functions to different interrupts once discovered – Jobs just kills anything that might compete with him outright by not letting it on the platform.
If Apple is using the calls in *their* apps but nobody else can, the only plausible explanation for preventing others from doing so as well is to ensure competitive advantage for Apple’s own applications. It’s part-and-parcel with the inherent conflict of interest that exists when a corporation creates an economic market by producing an OS and then competes in that market against 3rd party developers in the application arena. It is one of the most corrupt aspects of the industry, always has been, and it’s not just Apple who plays the game (even Google is playing it). As developers, we work within the system because that’s what we’re stuck with … but that doesn’t make it suck any less.
One exception to this IMO is when an “interface” represents a potential security risk, like removing public access to the HardwareManager class from Android just before the 1.0 API was released. I just don’t see security being an issue here.
This also brings up an interesting contrast between Apple and Android: in Android, control is maintained by literally making classes private – the developer can no longer access them unless the app is signed with the same certificate as the OS. The end result is developers know if the software works on a device/emulator, it’s using legal functions. That’s one reason why Android can be less brutal on the app approval process. Android’s garden is walled at the OS/API level, Apple’s is walled at the App Market level. There are pluses and minuses to each model, but Apple is in a position to be rather arbitrary and play favorites much more easily.
November 27th, 2009 at 8:38 pm
I’m just curious… last time I checked, it was against the NDA to publicly discuss why your app was rejected. Are you and other devs not worried about being blacklisted for violating the NDA?
November 27th, 2009 at 10:21 pm
@ron j
Interesting question.
As a general issue … at what point do you abrogate personal responsibility for doing what is right *for all parties involved*, over what is simply easy to accept?
November 28th, 2009 at 6:57 pm
@Kent to summarize (and this is not intended as a strawman argument)
* Google declares a set of API private and enforces this by the Runtime = good and reasonable.
* Apple declares a set of API private (which happens to include all undocumented APIs) and enforces this via Static Analysis = completely unacceptable/monopolistic/evil.
What is considered “private” does not depend upon what your personal opinion considers to be “traditional” or the mechanism for enforcement, it depends upon what the documentation for the platform/API says; in Apple’s case it says that all undocumented APIs are considered private and not to be used. While I would completely agree Google’s approach to enforcement is more reliable/secure and that Apple should provide some form of their static analysis tool to aid people in testing their own apps, neither is any less capable of the MS abuses you cite as why Apple’s review is evil. This is just the intrinsic power of controlling a platform; the platform can always be updated maliciously to break 3rd party applications.
And to your statement “If the function is replaced by something that ‘works better’, Apple corporate developers will be faced with the same issues that 3rd party developers would be.” You are correct, however Apple can certainly inform their own developers and search their entire codebase with ease to update it. They can also ensure that any updates are released concurrently with the new private API support. They can even do both of these in advance of releasing the new software. What they can not do easily is locate and update all 3rd party applications ahead of release, nor force newer versions to be deployed alongside the update. I would consider that to be reason enough alone for apple to steer 3rd party developers away from the private/undocumented APIs.
December 2nd, 2009 at 10:06 pm
@kent -
I think you’re overlooking some less offensive possibilities here.
While Jobs has actually come out and said that he considers third-party apps to be directly competing with Apple (and not in a good, fun, let’s-all-give-this-a-go kind of way), there *are* far simpler explanations than the usual (and historically warranted – I’ll agree there) concerns about The Msn keeping us down.
First off, the iPhone was going to sell anyway – even if we’d gone with Apple’s original plan of doing everyhing as web apps. Yeah, it would’ve *sucked* to have had to limit our apps to the lameness that is the Mobile Web vs. having access to what the platform really has to offer (OpenGL vs. crap scripting hosted inside a WebView accessed by a glorified bookmark? Laaaaaaame…). Apple didn’t *have* to give us this level of access to the phone. This is, whether we like the sound of it or not, a priviledge, and, to me, grattitude is partly expressed by Apple’s rules – rules *we all agreed to*. While they’ve confused matters by letting some apps through despite calls to “private” APIs (I also agree with you on the distinction in terminology), it’s quite possible that they have good, or at least semi-passable, reasons for doing so. Many apps are just plain garbage, and they get rejected for many reasons, but devs will latch on to one or two and then grumble about them without mentioning, say, almost zero attention paid to designing apps that conform to Apple’s various guidelines. It’s their sandbox; we agree to their rules for access to it; it’s our responsibility to accept those rules. If someone doesn’t like them, then don’t sign up for the program. If someone chooses to ignore Apple’s rules, then they ought to be big enough to accept that, at that point, they are *rightly* subject to the whim of the approvers.
Second, (and I hope this is coherent – typing on my phone, and it can be inconvenient to go back and read everything I’ve written so far), there are likely performance and stability issues here to consider. Like XML support. I was bothered by the lack of support for parsing XML outside SAX (and I *really* hate SAX). So I wrote everything against the DOM bits that… weren’t on the phone (the lovely “But it was on the simulator!” issue). I was further troubled by how the parser would silently fail when it hit a character it didn’t like – no warning – no message. Nothing. That’s just bad implementation, and it’s probably due to Apple having rushed the SDK. Considering the fact that they hired some of the devs who built the “open” unofficial SDK suggests they needed help – probably to get the SDK out there ask quickly as possible. Maybe to stop people from jailbreaking; maybe because they Saw the Light. Whatever the case, they had a tremendous amount of work to do in very little time. I used to think they had the SDK planned and mapped out long before release (like the way OS X (not just Darwin) was being built against x86 LONG before Apple came out and said anything about it). I’ve since chaned my mind based on official comments and all the bugs in the APIs. As something produced in a hurry, the SDK is, and has been, impressive. But that doesn’t change the simple fact that it has repeatedly shipped with serious flaws. In the case of non-SAX based parsing, it’s totally plausible that Apple wasn’t ready to release the APIs. It’s reasonable, too – for some reason (I come from a background working with a bajillion different tools and platforms – even worked for Microsoft for three years), and I’ve been astounded by a general lack of understanding of XML by iPhone devs. Books gloss over it, devs write garbage code… Had Apple given us access to anything more powerful than SAX, would we have seen issues arise? Like devs trying to pull eight-trillion database entries from a web service (likely synchronously at that), using up the phone’s resources, already spare, by eating memory and burning CPU (battery) because they didn’t realize that such an operation would result in an app that 1) Appears to hang like the dickens (therefore provides a bad experience – one that would violate Apple’s guidelines), and 2) Crashes like the dickens.
I know there are nice wrappers out there so SAX wasn’t the only choice, but it was all Apple wanted to give us, and I don’t blame them. *They* might be using what they kept from us, but that’s because they’d likely have used it responsibly, understanding that you always have to give something up in return for convenience (like performance – having a forward-only parser is, unless the implementation is insane, is always going to be faster than loading an entire document into memory so you can query against it – also going to consume less memory because you can free resources on each iteration of the parsing process). And that, when making such a trade-off, you need to do so responsibly.
Nearly every app I’ve downloaded (in a number, I’ve downloaded in the quantity of “tons”), has been trash. Stuff doesn’t work, devs are obviously unable to figure out how to manage their views to keep them wired up and responsive (Hey! These buttons suddenly don’t do *anything at all*…), memory-management is an insurmountable challenge for them, and they can’t be bothered to read the docs that Apple has clearly marked as “Required Reading” on the iPhone dev site.
The more power Apple gives us, the greater the potential for devs to make their platform look bad. I’ve worked on some large, very high-profile apps, and can argue that it’s *not* hard to put things out there that Just Work…
…provided you take the time to learn the platform and its quirks. And provided you take the time to read the fine-print and accept that, by joining, you’re *agreeing* to *their* terms.
In my opinion, if that means blocking an app that has violates those terms, then that’s totally fair play for Apple. I’m not saying it’s always done for honorable reasons, but there’s much more going on than just an attempt to keep third-party devs from competing with Apple. Good apps at good prices make Apple more money – if something’s quality enough to sell above the ridiculous $.99 price mark, and if it sells well, then that’s in Apple’s interest. They *want* us despite what Jobs has said.
In exchange for this kind of access to the infrastructure Apple provides for creating, distributing, and selling apps, I think it’s perfectly fair for them to do what they do. I also think it’s fair for them to accept or reject apps that use “private” APIs at their discretion – and they tell you in the contract you agreeed to as an iPhone dev that that’s how it is. It’s up to them, and we agreed to it. Nobody’s forcing us to develop iPhone software, so we ought to suck it up and accept it when apps get rejected while others don’t even when the same “offense” has been committed.
Finally (I’m getting carpal-thumb here), I feel like it’s a weed-out process. The App Store is a great thing, but Apple has made the mistake of setting a precedent regarding app approval by approving *way* too many apps. The store has become nearly useless. If it weren’t for the Genius feature, I don’t even know if I’d still be buying apps – I don’t want to wade through the muck to get to the good stuff. Apple should, in my (likely unpopular) opinion, have rejected *most* apps. But they didn’t, and now the App Store is a joke (and the butt of many jokes). They *need* more justifications for rejecting apps. The acceptance rate so far has been kind to producers, despite what so many believe, but has been bad for consumers by giving them overwhelming choice, and their choices usually come down to crapp number one vs. crapp number two vs. crapp number three… that’s not in the consumer’s favor, which makes the App Store a disaster. They’re going to fix it – they *have* to – but in the meantime, they *need* to reject apps left and right, only letting in the best of the best. They’re not doing that, of course, but they’re getting closer by being stricter.
Oh… the real “finally”: Android is a dead-end, and it always has been. It’s suffering the same problem Windows Mobile did. It’s a perfectly fine OS, and the dev tools aren’t ancient like Apple’s (It took twenty years, but here’s v2.0 of ObjC! It’s taken years, but here’s an IDE that actually kind of works! And, while we’re at it, here’s a UI builder originally designed for *LISP* that predates New Coke! Have fun…). But the openness of their platform makes it impractical. How they didn’t learn this from Windows Mobile is beyond me (except for the usual Google hubris). And anybody who thinks WM isn’t any good, I suggest you go learn a bit about it before trashing it – it’s been allowing devs to write apps with far more freedom than Apple does with their stack, the dev tools are decades ahead, and they gave devs garbage-collection back when Apple devs were still coding against Carbon using Project Builder. The problem is making an OS that runs on any old hardware that conforms to the simplest, required aspects of a spec. Good luck writing a *nice* app that can reach a large audience when you don’t know if they have GPS, a camera, a proper GPU, enough RAM, etc. – Apple’s disliked laws and what devs perceive as handcuffs are actually *better* for the producer *and* the consumer.
So, Apple’s Way has problems, but it’s a better way than what’s come before, provided you aren’t getting caught up in academic conversations about the morality of applying these restrictions, etc.
Just sayin’.
December 4th, 2009 at 5:22 pm
[...] got rejected for using Private API’s to modify UIAlert – a common workaround for bug(s) in the UIAlert dialog). Good news: the *non-Private API* version (source code on the linked page above) … works. [...]