How to detect iOS version in Objective C? - ios

I'm using Firebase 3.7.x to store my database. Firebase 3.7.x is support iOS 7.0 or higher but my project supports from iOS 6.0. So I want to detect iOS version in device to call #import Firebase. Something like that:
if IOS_7_OR_HIGHER
#import Firebase
else
//do nothing
if IOS_7_OR_HIGHER
- (void)dosomething{}
else
- (void)donothing {}
I know about if #available in swift. Is there any code like if #available in Objective C? Or is there any way to import Firebase for iOS 7 or higher and disable disable for iOS6?
Thanks.

You can get device system version by using
-(NSString*)getDeviceVersion{
return [[UIDevice currentDevice] systemVersion];
}
it will return you device version as string e.g. #"4.0" .
Hope it help you.

Try below code:
NSArray *osVersion = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[osVersion objectAtIndex:0] intValue] >= 7) {
// iOS-7 or greater
} else if ([[osVersion objectAtIndex:0] intValue] == 6) {
// iOS-6 code
} else if ([[osVersion objectAtIndex:0] intValue] > 2) {
// iOS-3,4,5 code
} else {
// iOS-1,2... code
}

To answer your question you can do it like this:
#ifdef __IPHONE_6_0
//Do something patchy!
#else
#import Firebase
#endif
Humble suggestion: You can consider upgrading your app.
A recent iOS version stats counter from Apple showing that there are only 5% devices which are still having iOS 8, 7 or <= 6. Means, you should drop out support for all those versions or you should start supporting iOS9 onwards.
By doing this you will get all the latest iOS features and you will never have to make this kind of patch in future.
Source: https://developer.apple.com/support/app-store/

Related

Getting existing app with fingerprint authentication to work with iPhone X FaceId

I have an app already developed and is live on the store. Its working well and has fingerprint authentication implemented. Now that Apple has made it mandatory to provide iPhone X support, I will be releasing one more update of the app.
But, i wish to understand what will happen if install the already submitted version of the app on iPhone X..?
I have read that -
App will provide a compatibility alert saying This app was designed to use Touch ID and may not fully support FaceID, But it goes away if we insert a key NSFaceIDUsageDescription in the plist.
I have also read that the app will crash if build using iOS 11 SDk (without the key NSFaceIDUsageDescription in the plist).
Here is my question - what if the app is build using iOS 8 and installed in iOS 11, will it still crash ? if not, how will be the exact behaviour..? I have tested in the simulator and the app did not crash but i do not have iPhone X available at hands and cannot crosscheck the same on the actual device.
NOTE - This crash is observed on the device more and not on simulator.
How important it is to have the word FaceId in the app running on iPhone X. What if I use a general terms like "Biometric authentication" in place of touchId & FaceId. Will the app still be fine and won't end up rejected ?
Any help or leads will be truly appreciated!
You're right in that you need the NSFaceIDUsageDescription key in your plist to properly support Face ID.
If you built the app using Xcode 9 against the iOS 11 SDK, even if you set the target to iOS 8, you need to include that key to support iPhone X.
That said, I don't see how this might be crashing. The same code that you use for Touch ID also supports Face ID.
I use this to handle faceID or touchID
if (#available(iOS 11.0, *)) {
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
if (myContext.biometryType == LABiometryTypeTouchID) {
SwitchItem *touchIdItem = [[SwitchItem alloc] init];
touchIdItem.name = NSLocalizedString(#"PROFILE_SETTINGS_TOUCHID", nil);
touchIdItem.active = [[[Global instance] objectInKey:KEY_TOUCHID_ENABLED] boolValue];
[self.dataSource addObject:touchIdItem];
} else if (myContext.biometryType == LABiometryTypeFaceID) {
SwitchItem *faceIdItem = [[SwitchItem alloc] init];
faceIdItem.name = NSLocalizedString(#"PROFILE_SETTINGS_FACEID", nil);
faceIdItem.active = [[[Global instance] objectInKey:KEY_FACEID_ENABLED] boolValue];
[self.dataSource addObject:faceIdItem];
}
}
} else {
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
SwitchItem *touchIdItem = [[SwitchItem alloc] init];
touchIdItem.name = NSLocalizedString(#"PROFILE_SETTINGS_TOUCHID", nil);
touchIdItem.active = [[[Global instance] objectInKey:KEY_TOUCHID_ENABLED] boolValue];
[self.dataSource addObject:touchIdItem];
}
}
You have to evaluate iOS version and after that yo can suppose if the gadget have a touchID or faceID

Use NSUserActivity and CoreSpotlight but still set iOS8 as Deployment Target

Is it possible to use the new features of iOS9 such as NSUserActivity and CoreSpotlight, but still set my Development Target to 8.2 so that users with iOS8 can still use the app?
I assume I would just need to do a iOS version number check or use respondsToSelector:.
Is this correct?
Yes, I do it in one of my apps (actually have a deployment target of iOS 7). It's trivial to do. Just make sure the CSSearchableIndex class exists, make the CoreSpotlight framework optional, and write your code properly to prevent the newer APIs from being run on devices with earlier versions of iOS.
You can even guard the code so it compiles under Xcode 6 if you had some reason to do so.
Example:
// Ensure it only compiles with the Base SDK of iOS 9 or later
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
// Make sure the class is available and the device supports CoreSpotlight
if ([CSSearchableIndex class] && [CSSearchableIndex isIndexingAvailable]) {
dispatch_async(_someBGQueue, ^{
NSString *someName = #"Some Name";
CSSearchableIndex *index = [[CSSearchableIndex alloc] initWithName:someName];
// rest of needed code to index with Core Spotlight
});
}
#endif
In your app delegate:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray *restorableObjects))restorationHandler {
if ([[userActivity activityType] isEqualToString:CSSearchableItemActionType]) {
// This activity represents an item indexed using Core Spotlight, so restore the context related to the unique identifier.
// The unique identifier of the Core Spotlight item is set in the activity’s userInfo for the key CSSearchableItemActivityIdentifier.
NSString *uniqueIdentifier = [userActivity.userInfo objectForKey:CSSearchableItemActivityIdentifier];
if (uniqueIdentifier) {
// process the identifier as needed
}
}
return NO;
}
#endif

respondsToSelector but the selector is unrecognized

I'm following apple's example code to the letter for how to implement receipt validation under iOS 7, and it works, except when I run the following code (taken basically verbatim from their sample) under iOS 6
NSBundle *bundle =[NSBundle mainBundle];
if ([bundle respondsToSelector:#selector(appStoreReceiptURL)]) { // can do local device receipt validation
NSURL *receiptURL = [bundle performSelector:#selector(appStoreReceiptURL)];
}
It returns true to the responds to selector, and therefore tries to perform the selector at which point it crashes because the selector doesn't exist... Why am I getting a positive response to a selector that doesn't exist?
The documentation for appStoreReceiptURL explains that this method existed as a private method before iOS 7, and that its implementation prior to iOS 7 calls doesNotRecognizeSelector:. Therefore you cannot use respondsToSelector: to check whether it's ok to call the method.
Instead, you need to check the system version:
NSString *version = [UIDevice currentDevice].systemVersion;
if ([version compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending) {
// safe to use appStoreReceiptURL
} else {
// not safe to use appStoreReceiptURL
}
I also got bitten by the bad sample code given at the WWDC session. It looks like Apple has updated their documentation with new reccomended sample code:
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
// Load resources for iOS 6.1 or earlier
} else {
// Load resources for iOS 7 or later
}
Based on this sample, you could write it in a single branch like so if you prefer, and check afterwards if the object is nil:
NSURL* url = nil;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
//iOS 7 or later, safe to use appStoreReceiptURL
url = [[NSBundle mainBundle] performSelector:#selector(appStoreReceiptURL)];
}
I saw that in the WWDC 2013 talk (e.g., “Using Receipts to Protect Your Digital Sales”) too. And the conflicting statement in the appStoreReceiptURL docs. It seems that the WWDC 2013 code example for appStoreReceiptURL was untested.

Check if device is running iOS 5 or higher [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Check iPhone iOS Version
One of the changes made in iOS 5 is the ability to override the drawrect methods. This means I need to change the appearance of the navigationBar and tabBar on a different way. I am able to use apple new methods:
[[UINavigationBar appearance]setBackgroundImage:[UIImage imageNamed:#"navigationBarBackgroundRetro.png"] forBarMetrics:UIBarMetricsDefault];
//I create my TabBar controlelr
tabBarController = [[UITabBarController alloc] init];
// I create the array that will contain all the view controlers
[[UITabBar appearance] setBackgroundImage:
[UIImage imageNamed:#"navigationBarBackgroundRetroTab.png"]];
[[UITabBar appearance] setSelectionIndicatorImage:
[UIImage imageNamed:#"tab_select_indicator"]];
I'm developing an app for iOS 4.3 and 5.0. However, iOS 5 ignores the drawrect method that I'm overriding, so it should run the above code. How can I check the iOS version so I can use the above code if the device is on iOS 5?
The samples below work for any version number. e.g.: to detect iOS 5 instead 7, replace 7 with a 5 in the code.
AvailabilityInternal.h macros
This detects the SDK you are building with:
#ifdef __IPHONE_7_0
// iOS 7.0
#endif
This detects the version set as Deployment Target in the General tab of your target configuration:
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
// iOS 7.0 or later
#else
// less than 7
#endif
NSFoundation version
BOOL isAtLeastIOS61 = NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_6_1;
BOOL isAtMost61 = NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1;
BOOL is7x = floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1;
If you ⌘ click NSFoundationVersionNumber, you'll see version constants for iOS and OSX. The constant for the current SDK is always missing.
Core Foundation version
BOOL atLeastIOS61 = kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_6_1;
As with NSFoundationVersionNumber, the SDK version is missing.
Device system version
NSString *version = [[UIDevice currentDevice] systemVersion];
BOOL isAtLeast6 = [version floatValue] >= 6.0;
BOOL isAtLeast7 = [version floatValue] >= 7.0;
An alternative way:
BOOL isAtLeast6 = [version hasPrefix:#"6."];
BOOL isAtLeast7 = [version hasPrefix:#"7."];
An alternative way:
BOOL isAtLeast6 = [version compare:#"6.0" options:NSNumericSearch] != NSOrderedAscending
BOOL isAtLeast7 = [version compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending
In case of concerns about float/string conversion, let it be know that everything above reports correctly if the version is equal or greater, for any possible iOS version (6.0, 6.0.1, 6.1, etc.).

How can I programmatically determine if my app is running in the iphone simulator?

As the question states, I would mainly like to know whether or not my code is running in the simulator, but would also be interested in knowing the specific iphone version that is running or being simulated.
EDIT: I added the word 'programmatically' to the question name. The point of my question is to be able to dynamically include / exclude code depending on which version / simulator is running, so I'd really be looking for something like a pre-processor directive that can provide me this info.
Already asked, but with a very different title.
What #defines are set up by Xcode when compiling for iPhone
I'll repeat my answer from there:
It's in the SDK docs under "Compiling source code conditionally"
The relevant definition is TARGET_OS_SIMULATOR, which is defined in /usr/include/TargetConditionals.h within the iOS framework. On earlier versions of the toolchain, you had to write:
#include "TargetConditionals.h"
but this is no longer necessary on the current (Xcode 6/iOS8) toolchain.
So, for example, if you want to check that you are running on device, you should do
#if TARGET_OS_SIMULATOR
// Simulator-specific code
#else
// Device-specific code
#endif
depending on which is appropriate for your use-case.
Updated code:
This is purported to work officially.
#if TARGET_IPHONE_SIMULATOR
NSString *hello = #"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = #"Hello, device!";
#else
NSString *hello = #"Hello, unknown target!";
#endif
Original post (since deprecated)
This code will tell you if you are running in a simulator.
#ifdef __i386__
NSLog(#"Running in the simulator");
#else
NSLog(#"Running on a device");
#endif
Not pre-processor directive, but this was what I was looking for when i came to this question;
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:#"iPhone Simulator"]) {
//device is simulator
}
There is a better way now in Swift.
As of Xcode 9.3 and newer, you can use #if targetEnvironment(simulator) to check.
#if targetEnvironment(simulator)
//Your simulator code
#endif
The best way to do this is:
#if TARGET_IPHONE_SIMULATOR
and not
#ifdef TARGET_IPHONE_SIMULATOR
since its always defined: 0 or 1
In case of Swift we can implement following
We can create struct which allows you to create a structured data
struct Platform {
static var isSimulator: Bool {
#if targetEnvironment(simulator)
// We're on the simulator
return true
#else
// We're on a device
return false
#endif
}
}
Then If we wanted to Detect if app is being built for device or simulator in Swift then .
if Platform.isSimulator {
// Do one thing
} else {
// Do the other
}
Works for Swift 4.1 and newer and Xcode 9.3 and newer
Use this code:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
All those answer are good, but it somehow confuses newbie like me as it does not clarify compile check and runtime check. Preprocessor are before compile time, but we should make it clearer
This blog article shows How to detect the iPhone simulator? clearly
Runtime
First of all, let’s shortly discuss. UIDevice provides you already information about the device
[[UIDevice currentDevice] model]
will return you “iPhone Simulator” or “iPhone” according to where the app is running.
Compile time
However what you want is to use compile time defines. Why? Because you compile your app strictly to be run either inside the Simulator or on the device. Apple makes a define called TARGET_IPHONE_SIMULATOR. So let’s look at the code :
#if TARGET_IPHONE_SIMULATOR
NSLog(#"Running in Simulator - no app store or giro");
#endif
For Swift 4.2 / Xcode 10
I created an extension on UIDevice, so I can easily ask for if the simulator is running.
// UIDevice+CheckSimulator.swift
import UIKit
extension UIDevice {
/// Checks if the current device that runs the app is xCode's simulator
static func isSimulator() -> Bool {
#if targetEnvironment(simulator)
return true
#else
return false
#endif
}
}
In my AppDelegate for example I use this method to decide wether registering for remote notification is necessary, which is not possible for the simulator.
// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {
// REGISTER FOR SILENT REMOTE NOTIFICATION
application.registerForRemoteNotifications()
}
The previous answers are a little dated. I found that all you need to do is query the TARGET_IPHONE_SIMULATOR macro (no need to include any other header files [assuming you are coding for iOS]).
I attempted TARGET_OS_IPHONE but it returned the same value (1) when running on an actual device and simulator, that's why I recommend using TARGET_IPHONE_SIMULATOR instead.
In swift :
#if (arch(i386) || arch(x86_64))
...
#endif
From Detect if app is being built for device or simulator in Swift
Has anyone considered the answer provided here?
I suppose the objective-c equivalent would be
+ (BOOL)isSimulator {
NSOperatingSystemVersion ios9 = {9, 0, 0};
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
if ([processInfo isOperatingSystemAtLeastVersion:ios9]) {
NSDictionary<NSString *, NSString *> *environment = [processInfo environment];
NSString *simulator = [environment objectForKey:#"SIMULATOR_DEVICE_NAME"];
return simulator != nil;
} else {
UIDevice *currentDevice = [UIDevice currentDevice];
return ([currentDevice.model rangeOfString:#"Simulator"].location != NSNotFound);
}
}
I had the same problem, both TARGET_IPHONE_SIMULATOR and TARGET_OS_IPHONE are always defined, and are set to 1. Pete's solution works, of course, but if you ever happen to build on something other than intel (unlikely, but who knows), here's something that's safe as long as the iphone hardware doesn't change (so your code will always work for the iphones currently out there):
#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif
Put that somewhere convenient, and then pretend that the TARGET_* constants were defined correctly.
To include all types of "simulators"
NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:#"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
// we are running in a simulator
}
With Swift 4.2 (Xcode 10), we can do this
#if targetEnvironment(simulator)
//simulator code
#else
#warning("Not compiling for simulator")
#endif
My answer is based on #Daniel Magnusson answer and comments of #Nuthatch and #n.Drake. and I write it to save some time for swift users working on iOS9 and onwards.
This is what worked for me:
if UIDevice.currentDevice().name.hasSuffix("Simulator"){
//Code executing on Simulator
} else{
//Code executing on Device
}
/// Returns true if its simulator and not a device
public static var isSimulator: Bool {
#if (arch(i386) || arch(x86_64)) && os(iOS)
return true
#else
return false
#endif
}
Apple has added support for checking the app is targeted for the simulator with the following:
#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif
if nothing worked, try this
public struct Platform {
public static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
}
}
This worked for me best
NSString *name = [[UIDevice currentDevice] name];
if ([name isEqualToString:#"iPhone Simulator"]) {
}
In my opinion, the answer (presented above and repeated below):
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:#"iPhone Simulator"]) {
//device is simulator
}
is the best answer because it is obviously executed at RUNTIME versus being a COMPILE DIRECTIVE.

Resources