Programmatically distinguish between Ad-hoc and AppStore version of app - ios

I have an app that sends logs to Keen IO for logging and analysis purposes. The code that sends logs to Keen IO is guarded by preprocessor macros, and hence it never sends any logs when I’m running it on the simulator or my own phone while development.
What I generally follow is this — After the app is (almost) done, I release an ad-hoc version and give it to some testers who use it for a few days and test it. However, since it is also a “release” version, the app sends analysis data. This data usually pollutes my other data that was supposed to come from my real users!
I want to programmatically know inside the app if it is an ad-hoc release version or AppStore release version, so I can handle those two conditions. Is there a way to do this?
The only way I can think of is have another preprocessor macro AD_HOC that tells that its a test version. But it can happen that I forget to remove the macro while submitting to the AppStore. Its not gonna help if that happens.

I use such a macro for a very similar reason. I build the adhoc version using the release building setting and the app store version using the distribution build setting. In that way I avoid forgetting to set the #define to the right value.

Related

How to have multiple versions of app in TestFlight?

I've just published an app on Apple's store and I'm wondering about having multiple versions of the same app for testing on TestFlight. Of course dev doesn't stop when publishing... from now on I'll have to update the app store version (v1.0.0) with bug fixes (v1.0.1, v1.0.2, ...) and before doing so I'd like to check them in test flight to ensure the fix was appropriate.
My problem is that I'm already starting to develop the next version with further functionalities of the app which will become v1.1
So ideally I'd like to have my app available both for my bug fixes, for instance v1.0.2 and also my next version v1.1.0 (this will include all bug fixes made to the store version and also many new features, refactors, redesign, etc)
I know that if I build and upload to the apple store connect a build with v1.1.0 (next version) I won't be able to upload one for a built with a bug fix on the current app store version (v1.0.2) since this version would be lower than the one I uploaded (next version)
Is there a way to accomplish this? I've read this article https://savvyapps.com/blog/using-testflight-to-distribute-multiple-versions-ios-app which solution is to create extra applications in iTunes with different app ids and bind them to different certificates. But what will happen when the next release is ready to be in the store? I would have to release it and then disable the previous one? How may this affect my users? Will they have to re-install a new app rather than updating it?
I really need to start testing and checking the next release of my app in TestFlight and also support the current one with updates if something pops up. Thanks in advance!
I am able to upload multiple versions of the app to TestFlight. Each upload requires a higher version/build number, but you can switch the TestFlight test version between them as need be for testing.
Once I submit a particular build for release, however, I seem to lose the TestFlight access to the old builds.
In short, you can have many builds available in TestFlight, but once you submit the app for release, you have to start over making builds for TestFlight.
You keep talking about numbers like v1.0.1. That looks like a public-facing version string, with a major, minor, and patch number.
But that is not what TestFlight cares about. Well, it cares to some extent. But all TestFlight really cares about is that every new build you upload has a new build number. This is just an integer which you simply increment every time you submit a new build.
So you could have v1.0.1(23) on the App Store, and then on TestFlight you could upload v1.0.2(24) which starts moving forward toward version 1.0.2, but also upload v1.0.2(25) which is actually an attempt at a prospective version 1.1. TestFlight doesn't know or care what these different builds signify. They can all exist simultaneously on TestFlight. Keeping them all straight and on their individual trajectories is up to you.

What does TestFlight do to my iOS executable?

I hash my iOS executable at launch to verify its integrity, and have had no problems doing so until TestFlight -- which appears to modify the executable as well as install it in some funky (undocumented?) way.
Even more concerning is I get multiple hash values, which appear to vary by device or iOS version or carrier or something. I don't own enough devices to be certain. But none of the hashes match the one I compute prior to uploading to TestFlight.
So I have two questions: (1) What is TestFlight doing to my executable, and is the process documented somewhere? And (2) Does the final app store release pull the same shennanigan, or something similar, or does it leave my executable unmodified from when I uploaded it?
That's what code signing is for.
Code signing your app assures users that it is from a known source and
the app hasn’t been modified since it was last signed.
Source: https://developer.apple.com/support/code-signing/
It seems like Apple encrypts your app. While this post is about App Store submission, could be the same for Test Flight (not sure about this).
See: https://stackoverflow.com/a/5784332/2019384
Also it's not recommended to verify your apps integrity by yourself, as you'll run in such issues. Besides iOS already does this for you:
Apple does not provide any supported way for you to check your app’s
integrity. iOS already does that by default.
Source: https://forums.developer.apple.com/thread/52801
In addition to d4rk's answer, if you're using Swift, Apple compiles in appropriate bits to optimize your app for each device.

itunesconnect App - Revert to previous version

I released an update for my App and it was approved. It was approve despite the fact that it included a serious localization bug where most users are getting the wrong language. Is there any way to quickly revert back to the previous version, suspend current downloads of the current version, or anything else that might help aid this issue?
I did read the following thread from a couple years ago:
Can I revert to my previous version app in iTunes Connect?
I was hoping maybe there is a more painless solution to this now.
Btw, I did thoroughly test the version before it was added as a new version. So, I'm still not entirely sure what's wrong or how to fix it.
It is not possible to revert the app version. You can upload the previous version as new version again to fix this.
One thing you can do is : "Expediting an App Review"
Please check the following link.
https://developer.apple.com/appstore/contact/?topic=expedite
Thanks
Here's a snippet from iTunes Connect Help page :
Question: The new version of my app on the App Store has a bug. Can I use a previous version to replace it?
No. You cannot revert to a previous version on the App Store. You must submit a new version.
Source : iTunes Connect FAQ
Obviously the alternative would be to submit a new build but ask for expedited app review.
But that means that either your app is event-related or you have a critical bug that you need fixed as soon as possible.
I believe that you can prepare for problems by creating a fallback version with a higher version number and submitting it for approval with manual publishing. That should cause it to be quiescent in your store until you choose to fall back, and you publish it.
I am not certain whether you can then submit improved versions with a lower version number than your fallback version.
I had to do this recently. I was able to adjust a previous version archive. I started by copying the archive and opening the copy, then editing the info.plist files, adjusting/incrementing both the version and build numbers at both the archive and app package levels. Then uploaded to iTunes, which recognized it as a new version.
Preface: I agree with the other posts here that you can't perform a rollback through the iTunes Connect itself. Even if you could, you'd suffer the lag time it takes for users to update to the rolled-back-version. But that doesn't mean we can't still rollback apps.
Retroactively, you cannot rollback an app. Proactively, however, you can instrument your app to enable future rollbacks after a build has been released and installed.
High-level steps:
Build each version of your application as a framework
For each release build, include both the current and old framework versions
On app boot, decided which framework to load and execute (include sane defaults)
When you want to rollback, update the cached values across all user devices and wait for the next app open.
This strategy uses similar mechanics to feature flags which are commonly used to enable/disable features without re-releasing. However, in this case, you're "feature-flagging" your entire app version.
Is feature flagging between embedded libraries against App Store Guidelines?
No. Embedding two versions of your app into one release is not against App Store review guidelines:
4.7 HTML5 Games, Bots, etc.
Apps may contain or run code that is not embedded in the binary (e.g.
HTML5-based games, bots, etc.), as long as code distribution isn’t the
main purpose of the app, the code is not offered in a store or
store-like interface, and provided that the software (1) is free or
purchased using in-app purchase; (2) only uses capabilities available
in a standard WebKit view (e.g. it must open and run natively in
Safari without modifications or additional software); your app must
use WebKit and JavaScript Core to run third-party software and should
not attempt to extend or expose native platform APIs to third-party
software;
Similar to feature flags, all code that you plan to run is included in the binary that you submit for review. What's more, as long as you are rolling back to releases that Apple already reviewed and approved, you're not breaking the spirit of the guidelines.
Does this hurt performance?
I've profiled this approach against many of the popular and heavy open-source iOS apps including Wikipedia, Signal, Firefox, etc. You can be smart about deduping assets and shared libraries, resulting in a sandwiched-app-bundle size of about 1.2x the original size (really just depending on how much code you changed). You also incur about a 50ms startup cost when choosing which version of the app to boot.
IMO, both time and size increases are worthwhile in return for the ability to selectively rollback users experiencing issues while you take time implementing a fix.
Do real apps do this?
Major apps feature-flag between dylibs all the time when launching new features and optimizing performance. I have also heard of major tech companies using this app-level pattern for their largest releases. I have a personal app in the App Store using this pattern, and I have helped other developers do the same.
How can someone do this for their app
If you are comfortable going deep on the Xcode build system, you can follow the steps outlined above and with some fiddling, start feature flagging your app version on boot. Note that you'll also need some form of caching and a server endpoint to update the on-device flag.
The implementation described above is also exactly how screenplay.dev implements iOS rollbacks. The tool:
Adds two build targets to your Xcode project, one for building the framework version, and one for bundling the final release build.
Serves as a repository for your old app build versions.
Provides a web UI for toggling live versions.

How to simulate iOS version upgrade?

We need to test our app in the context of an iOS upgrade (e.g., 5.1 -> 6.0). Unfortunately, Apple doesn't allow downgrading devices. We thought of doing it in the simulator, but different versions of the simulator are different environments in themselves. I think we can copy the bundle from one simulator to the other, but that won't migrate the keychain (will it?).
Thanks!
To test a transition from one state (before) to another (after), you need a way to put the app in the before state.
Your app surely won't be running while the OS is being updated, so you really only need to worry about the app starting up and discovering that the OS has been updated. There are a couple options:
Copy all your app's data files from a device running the "old" iOS version (5.1 according to your question) to a device running the new (6.0) version. The organizer in Xcode will let you easily copy your app's "container" from a device to your Mac or vice versa.
Make your app write it's data in the "old" format. It's not uncommon for an app to have methods for reading and writing data in different formats depending on the environment, so it's often easier to get your app to write data out in the old format than to actually copy from an old device.
Whichever path you choose, think about any other places (like user defaults) where you might made OS version-dependent changes and set those back to values that correspond to the previous OS. This applies especially to keychain items, which aren't stored in your app's sandbox.
Unit testing frameworks (like Apple's XCTest framework) generally have a setup mechanism that you could use to reset your app to the before state, including copying files, adding and removing keychain items, setting defaults items, etc. You can then add unit tests that run whatever code might be involved in an update and test the results. With a set of easily repeatable tests you'll be able to debug any problems more easily.
However you approach it, the goal is to put the app in the same state that it would be in if it were running for the first time after an OS update occurred. You don't have to worry about simulating the actual OS update, you only need to trick the app into thinking that the update has just happened.
For now, you can still install iOS 8.2. When a new version is released, Apple leaves both versions open for installation for a short time. While that "signing window" is open you can upgrade a device, test, and then restore it from an image of the older version. So you could do some intensive testing while the window is open, but obviously that's not a long-term solution (it typically lasts only a few days).
If you have the budget for it, you could install 8.2 on a device, put a big sticker on it saying "do not upgrade", and keep it on 8.2 for as long as it's relevant. Install your app on that device and take a backup (with backup encryption enabled so that keychain entries will be included), then restore that backup to another device that's on 8.3 - this is basically the same procedure you'll go through when doing an upgrade/restore through iTunes so it should be pretty close. It won't be exactly the same as an OTA update on-device of course, but for that, see option 1 above (and see it soon).

My app is now in the Apple App Store but crashes during the splash screen

My application is in the Apple App Store but when downloaded it crashes after the splash screen.
I thought the week long approval process was to ensure the quality of the app.
Version 1.0 of my app does run but I hear there is no way to roll it back. For now I have changed the availability date to the future so that people do not download it. When will it be taken out of the search results?
Thanks.
The approval process is not for QA testing. (Of course, they will reject an app if it crashes while testing they are other for things, such as violation of various SDK rules, HIG guidelines, etc.) A developer has to test and QA your apps themselves on the OS versions and the iOS device types for which they submit the app as appropriate for, and under stress conditions as well. A developer also needs to make very certain that the build they submit is identical (except for certificate signing) to the builds they have tested. (It is a common mistake to have different Build Settings or source files selected between the Release and Distribution builds.)
Check to see if a bad preference setting is the culprit.
Or if it worked only for you, then it may be the lack of a preference setting. You may have created a good preference before the bug was introduced.
Was taken out of search results by the end of the day.

Resources