16

Is it possible somehow to code like below in iOS app ?

if(app is live in app store)
{
   //Do something
}
else
{
  //Do other thing
}

I wanted to avoid cases where our QE/Dev team is using app for testing. Is there a way I can detect how app code is signed (Developer/Adhoc/Distribution) to check ? Even if it is possible, it will not eliminate cases when Apple is using our app for testing as part of review. We recorded many downloads of our content by Apple before our app goes live in App store.

msk
  • 8,885
  • 6
  • 41
  • 72
  • 1
    Why would you want to do that? You can use preprocessor macros to distinguish between debug and release builds, but the Apple Review Team needs to use the same app as the customers without modifications. You can use a server-side test of the IP addresses to ensure that you are not billing the reviewers for the downloaded content or whatever, but don't try to fool them. – Fabian Kreiser Mar 28 '12 at 11:34
  • I already have macros to differentiate debug and release builds. But it is not what I want. We use testflight to send our apps to customers and testers. Problem is that when they download any content we do not want to track that because they are not actual users. One solution (in theory) I thought of is to take decisions based on "Ad-Hoc/Developer" or "Distribution" provisioning profile used in code. How, I need to figure out. Another problem is content downloaded by Apple as part of review. Any way I can detect that? – msk Mar 28 '12 at 17:39
  • You could add a parameter for the requests to your server when it's an AdHoc build and check for that parameter on the server. When Apple tests the app you can detect the IP address on your server. – Fabian Kreiser Mar 29 '12 at 07:37
  • if you hava knowledge regarding android for same subject then please share – Nikunj Patel Jul 11 '12 at 09:24

6 Answers6

11

You can determine if your app was distributed via the app store by checking for the absence of embedded.mobileprovision. This file is only included in adhoc builds.

Like this:

if ([[NSBundle mainBundle] pathForResource:@"embedded"
                                    ofType:@"mobileprovision"]) {
  // not from app store (Apple's reviewers seem to hit this path)
} else {
  // from app store
}

This technique is from the HockeyApp SDK. I personally have applications in the store that use this technique, and of course there are many apps distributed that include the HockeyApp SDK.

Based on an immediate crash I accidentally released in a particular build of my application in the "from app store" path, Apple's team will follow the "not from app store" path. Let my loss be your gain on that one. :)

Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • 1
    Will this distinguish Apple testers? Do they use their own MobileProvision to load apps for testing, or do they have a special way to load them? – xdumaine Dec 18 '12 at 18:10
  • Good question. I don't know the answer. I have had code that uses this technique approved by Apple, and as part of the HockeyApp SDK it's probably fairly widely deployed. So if you're only curious if it'll get you rejected, it seems like it won't. Beyond that…? – Steven Fisher Dec 18 '12 at 18:13
  • 2
    Okay, I now have pretty strong (though not conclusive) evidence that Apple's App Review team would follow the "not from app store" path in this code. – Steven Fisher Jan 18 '13 at 21:32
  • I was using this technique to differentiate between apps downloaded from the App Store and TestFlight builds. Something has changed in Xcode7. Before, TestFlight builds returned `NO`, now it returns `YES` – kwahn Oct 09 '15 at 12:15
  • Same as @kwahn, this doesn't seem to be working with XCode 7 – Matthieu Rouif Oct 12 '15 at 16:34
  • Modern TestFlight is something entirely different than it used to be. It's basically a new product that reuses the old name. – Steven Fisher Nov 03 '15 at 18:30
4

On iOS 7 and later, you may also be able to check:

if ([NSData dataWithContentsOfURL:[NSBundle mainBundle].appStoreReceiptURL] != nil) {
    // Downloaded from App Store
} else {
    // Not downloaded from App Store
}
Frank Schmitt
  • 25,648
  • 10
  • 58
  • 70
  • Will it work for free apps also? I think [NSBundle mainBundle].appStoreReceiptURL will be nil in that case, right? – msk Sep 28 '15 at 19:02
  • 1
    I haven't tested this (the time investment to add this to an app, get it approved, and somehow extract the data is pretty significant). But as I understand it, a free app counts as a "purchase", just one that happens at zero cost to the consumer. – Frank Schmitt Sep 28 '15 at 20:51
3

This isn't working anymore with XCode 7, I would suggest to use the new HockeyApp workaround https://github.com/bitstadium/HockeySDK-iOS/blob/6b727733a5a93847b4a7ff8a734692dbe4e3a979/Classes/BITHockeyHelper.m Here is a simplified version:

+ (BOOL)isAppStoreBuild
{
#ifdef DEBUG
    return NO;
#else
    return ([UIApplication isTestFlightBuild] == NO);
#endif
}

+ (BOOL)isTestFlightBuild
{
#ifdef DEBUG
    return NO;
#else
    NSURL *appStoreReceiptURL = NSBundle.mainBundle.appStoreReceiptURL;
    NSString *appStoreReceiptLastComponent = appStoreReceiptURL.lastPathComponent;
    BOOL isSandboxReceipt = [appStoreReceiptLastComponent isEqualToString:@"sandboxReceipt"];

    return isSandboxReceipt;
#endif
}
Matthieu Rouif
  • 2,843
  • 1
  • 19
  • 28
1

For the Swift version:

private static let isTestFlight = NSBundle.mainBundle().appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"

This complete answer explains more elaborately on how you could use it.

Community
  • 1
  • 1
LorenzoValentijn
  • 1,381
  • 1
  • 11
  • 12
1

I faced a similar situation in my app. At least I think I did, I'm not sure I'm entirely understanding your question.

In my app I have users with accounts create content. I don't want developer content (or Apple employees content) from polluting the public content. I have a "test" bit in the user data structure that gets turned on and test content is not visible to the public. I've not submitted to the App Store yet but I'll need to work with Apple to make sure that their accounts have this test bit turned on.

If this isn't your goal, well, never mind then! :- )

Paul Cezanne
  • 8,629
  • 7
  • 59
  • 90
  • Can you elaborate what you ask Apple ? What do you mean by "test" bit ? How do someone set/reset it ? – msk Mar 28 '12 at 17:45
  • On my server, I have a user data structure, it contains things like Login, password, email. It also has a boolean named "test." If that boolean is ON, then my application behaves differently. I set it via an API to my server. When I do submit to the Apple store, I'll have to work with them to make sure the test bit is ON. – Paul Cezanne Mar 28 '12 at 18:04
  • Ahhh, I see your comment above. Yes, you can have a special account for TestFlight and Apple users. It doesn't answer your question but it will solve your problem. – Paul Cezanne Mar 28 '12 at 18:05
  • Thanks for help Paul, but I think any answer which explain how to check "Ad-Hoc/Developer" or "Distribution" build can answer my question to some extent. – msk Mar 28 '12 at 20:53
  • @MSK I think you're on the wrong track with trying to differentiate between *Ad-Hoc/Developer* and *Distribution* for the sole reason that when Apple is testing your app, it will be with the *Distribution* version, not the *Ad-Hoc* version, and thus, your problem is not solved. Paul is right. If you're trying to distinguish certain users, you should do it at the user level, not the app level. – xdumaine Dec 18 '12 at 18:09
0

Swift

func isAppStoreBuild() -> Bool {

    if NSBundle.mainBundle().appStoreReceiptURL != nil {
        if let _ = NSData(contentsOfURL: NSBundle.mainBundle().appStoreReceiptURL!) {
            return true
        }
    }
    return false
}
msk
  • 8,885
  • 6
  • 41
  • 72