I have an interesting issue with submitting an update for my iOS app. I have 2 API versions: production and staging. The TestFlight builds use the staging server, and the App Store builds use production via this check:
if ([[NSBundle mainBundle] pathForResource:#"embedded" ofType:#"mobileprovision"]) {
// TestFlight, use staging API
} else {
// App Store, use production API
}
This works great. We get to test the next version of the app with the next version of the API, while keeping the released version working with the production API.
The problem is that when we submit the app to Apple for review, their reviewers now have the new code that needs the new API, but the above check points them to the production API. This caused a crash and thus we got rejected.
I know that we should do proper API versioning so we could have the old and new API running in production at the same time, but sadly we're not at that stage yet. We mistakenly figured that the Apple reviewers would take the first code path (using the staging server), and we would manually release the app after it got approved and time that with deploying the new API to production and thus everything would work out just fine.
So, finally the question. Is there any way in code to detect if the app is run by Apple's reviewers, have it use the staging server? Or are we screwed and need to get the new API into production (and thus breaking the app that's currently in the App Store)?
I don't believe that you will find a reliable way of detecting the reviewer activity.
Is it possible to add a new "API" on your server specifically for your new app where it can post its version and get an answer back as to whether it is released or not (and therefore which server it should talk to subsequently)?
Once the app is approved then you can change the answer from this new API. You could even store a "production" answer in NSUserDefaults so that the app no longer checks each time once it "knows" it is in production - presumably you would never revert to staging.
Related
I have an app I developed in Xcode for Apple devices, and I have the following question I'm not sure how to deal with.
I have a server side to my app, and for testing I use a development URL, which has dummy data. When releasing, I connect to the live URL, which is connected to the live data.
Now, sometimes I make a build with the development URL that I want to put into TestFlight for the users to test, but I want to make sure that its clear on the app store connect, that this is a build connected to the development URL. I don't want in the future to publish this build by mistake. So I tried in the version to put 2.0.2-DEV, but when sending to the App Store, Xcode gave me an error:
The provided entity includes a relationship with an invalid value.
And this is because the version code has to be number.number.numnber without any text.
I also tried to do it, that the builds connected to the development URL, will be coded from 9.0.0, etc. However, once I did this, when I released new versions with the live URL, for example. 2.0.1, the users were not notified, since this number is before 9.0.0
I hope it’s clear what I am trying to say,
So how can I label a build to be using the dev development URL, so it will be clear on the app store connect that it’s not a live build?
You can not release a development and production to TestFlight. TestFlight is only for production.
But you can:
Always release the app using Phased release, so you can halt the rollout quickly if you released the wrong version.
You can use only odd numbers for development and even numbers for production
The problem, as you might expect, is the app review process.
In order to get Apple to review an app update, it has to be pointing at my production server. In order for that to work, I must update the build on my production server. But of course I don't want to do that until the app update is available in the Apple Store.
Now this isn't a problem if I've only made changes that can be deployed via hot code push ... but changes that can be deployed via hot code push don't need a new app wrapper anyway. I'm concerned about things like new node modules, or an updated meteor version.
Anybody know how meteor expects us to handle this?
(And in case it's useful, here's my related meteor forum post: https://forums.meteor.com/t/whats-the-right-way-to-do-updates-via-the-apple-store/28491)
According to the meteor forums, the right way to do this is to package a separate release that just includes the wrapper-breaking changes (an update to the meteor version, for example).
Once that has been deployed (and "all users" have received it) then you can deploy updates that change the app interface.
... and since there's really no such thing as "all users" receiving the update, I'm thinking it might also be good to have the client know about breaking app wrapper versions and lock down somehow if the client's wrapper version is incompatible.
I want to know how others are managing their back end API's during the time when their iOS app is under review.
We are constantly updating/adding new API endpoints every release. The major problem we're encountering is when we have to make DB schema changes. We don't want to promote our backend changes to our production server until after the app has been approved by Apple (which may take up to 4+ days).
Currently, we set our iOS app to manual release and flip between 2 production servers. So app v1.0 in the app store will point to our prod1 server and app v2.0 in review will point to our prod2 server. When Apple approves v2.0, we copy our prod1 database to prod2, run all the migrations and then release v2.0. Once we've promoted our changes to prod2, we'll update a config setting on prod1 that will send a response back to app v1.0 providing a link to the app store to download app v2.0.
It feels like there are better ways to solve this problem. Interested to see how others have approached this issue.
We've successfully used the iOS app version (passed as part of the headers) in the REST calls to support multiple app versions on the same server(s). Seeing as you often have to support multiple older versions of the iOS client anyway this seems to be the simplest approach.
My Cordova iOS web app works with a production web site. The version of iOS webapp must match the version of the website for them to work properly.
Now I need to submit a version 2 of iOS webapp to Apple for review. I do have a staging website of version 2.
I have two options:
summit webapp pointing to staging server for Apple Review. If approved, change it to point to production server and submit it again with note indicating only changes made and hope for quick approval. Then I update production website to version 2 and promote the approved version iOS webapp to iTune appstore.
Find some way to save SERVER_URL setting outside the iOS webapp (in html5 cache, etc) and let webapp to read this setting before running and ask Apple reviewer to change this setting to STAGING_SERVER_URL before testing.
I don't like either. Maybe I am missing some other better approaches. I am hoping some guru can point me in the right direction. Thanks in advance.
Is it anyone else's experience that lately (Nov. 2011) the production URL for validating In App Purchase receipts now works to validate sandbox-generated receipts?
If this can be relied upon its a huge boon for me. It means that the build I submit to Apple can be exactly the same as the build I test with (except for final code signing.)
I'm referring to https://buy.itunes.apple.com/verifyReceipt and https://sandbox.itunes.apple.com/verifyReceipt.
This is no longer working as of 7/26/2012 (just found this post here, trying to figure out when it originally changed). You'll need to go back to the prod -> sandbox failover code, detailed in this tech note - http://developer.apple.com/library/ios/#technotes/tn2259/_index.html
I'm guessing this is because of all the hacking of IAPs going on, and Apple now closing possible loopholes.
If you want identical development and life behaviour (plus identical behaviour while your app is being reviewed): Verify the purchase first with the life server, and if it fails with the sandbox server.
I noticed this too, and it is May 2012 so I guess this has been working for awhile.