iOS user default name format issue - ios

Using the following method i get the right order instantly on iOS 5 but the order not changing on iOS 6 & 7 after switching it in the settings, nor after restarting application (after closing settings).
BOOL firstNameFirst = NO;
if (IOS_VERSION>=7) {
firstNameFirst = (ABPersonGetCompositeNameFormatForRecord(NULL)==kABPersonCompositeNameFormatFirstNameFirst);
}else{
firstNameFirst = (ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatFirstNameFirst);
}
What am i missing?
EDIT:
This bool supposed to store the user default order, so i can order the first and last name strings and show them to the user in the way he set it in the iPhone settings.
EDIT2: the IOS_VERSION macro works perfectly, i checked them using breakpoint, but whatever the Settings / Mail, Contacts, Calendar / Contacts / Display Order settings is, i always get YES for firstNameFirst's value

I hope to be helpful to you.
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
BOOL firstNameFirst = NO;
if (IOS_VERSION>=7) {
firstNameFirst = (ABPersonGetCompositeNameFormatForRecord(NULL)==kABPersonCompositeNameFormatFirstNameFirst);
}else{
firstNameFirst = (ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatFirstNameFirst);
}
if(addressBook != NULL) {
CFRelease(addressBook);
}

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1)
{
// Load resources for iOS 6.1 or earlier
} else
{
// Load resources for iOS 7 or later
}
do like this.
reference taken from this.
This Link

Related

iPhone simulator (detect different device simulators)

With the upcoming release of the iPhone X, I want to be able to display a different UI layout for the iPhone X (due to round corners and bottom line, which kinda works as the home button replacement).
I am using the following nuget package to retrieve the model information:
https://github.com/dannycabrera/Get-iOS-Model
It works perfectly fine, but all the different simulators (iPhone 7, 8, X) only come up as Simulator.
Is there a way to differentiate between the different iPhone Simulators in code within my Xamarin mobile app?
Many thanks,
Nik
Since the simulator is a weird animal, the screen size is as good as any other test after the other tests for iOS version and the availability of FaceID on a physical device:
public bool iPhoneX()
{
var version = new Version(ObjCRuntime.Constants.Version);
if (version < new Version(11, 0))
return false;
if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.DEVICE)
{
using (var context = new LocalAuthentication.LAContext())
{
if (context.BiometryType == LABiometryType.TypeFaceId)
return true;
}
return false;
}
if (UIScreen.MainScreen.PreferredMode.Size.Height == 2436)
return true;
return false;
}
Or an optimized property for repeated (binding) calls:
static bool? iPhoneX;
public bool isPhoneX
{
get
{
if (iPhoneX == null)
{
if (new Version(ObjCRuntime.Constants.Version) < new Version(11, 0))
iPhoneX = false;
else
{
if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.DEVICE)
{
using (var context = new LocalAuthentication.LAContext())
{
iPhoneX = context.BiometryType == LABiometryType.TypeFaceId;
}
}
else
iPhoneX = UIScreen.MainScreen.PreferredMode.Size.Height == 2436;
}
}
return (bool)iPhoneX;
}
}
You should simply use the Safe Area Layout Guide which will automatically increase the top/bottom margin on the iPhone X.
As others have pointed out you should definitely be using the Safe Area Layout Guide.
If you really really have a need to detect the model then look for the SIMULATOR_MODEL_IDENTIFIER environment variable. iPhone X will return iPhone10,3.
let model = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"]

Different values of BOOL variable in debug and release version

I have one method in which there is one condition which checks the bool value and do some task based on the condition. It is working perfectly in the debug build but in the release build the bool value always return true.
Below is sample code of the method which is behaving differently in debug and release version.
-(void)addNotification:(NSMutableDictionary *)dictNotificationData
{
BOOL addNotification;
if ([[dictNotificationData objectForKey:#"id"] integerValue] == 2) {
if ([[dictNotificationData objectForKey:#"isActive"] boolValue]) {
addNotification = YES;
}
}
else {
addNotification = NO;
}
//In the release version this value always return true eventhough it is going in the else part.
if (addNotification) { 
//code for local notification
}
}
Please let me know if any one has any idea about why it is behaving differently in debug and release version.
Actually I found the solution for that. The Bool local variable always initialised as garbage value if we do not provide any which was creating the problem in my case. When I initialised BOOL addNotification = NO; it works fine.
Found the answer here.
Default value of BOOL
Thanks All.
Not the question that you are asking but in your code is it possible that addNotification is tested before it is initialised - if the second 'if' is false.
For boolValue check please try this
NSNumber * isSuccessNumber = (NSNumber *)[response objectForKey: #"success"];
if([isSuccessNumber boolValue] == YES)
{
} else
{
}
Boolen value can be changed on the device version. So what the result for this line, if this line return 0 or 1, can be change the result. [dictNotificationData objectForKey:#"isActive"]
For instance, run your code on both 32-bit iOS and 64-bit iOS. It should correctly display “Different” on one, but not the other.
if (different(1, 2)) {
NSLog(#"Different!");
} else {
NSLog(#"Not different.");
}

iOS: AVSpeechSynthesizer : need to speak text in Headphone left channel

I am using AVSpeechSynthesizer for TextToSpeech. I have to play the speak in HeadPhone left Channel (Mono 2). I have got the following to set the output channel.
func initalizeSpeechForRightChannel(){
let avSession = AVAudioSession.sharedInstance()
let route = avSession.currentRoute
let outputPorts = route.outputs
var channels:[AVAudioSessionChannelDescription] = []
//NSMutableArray *channels = [NSMutableArray array];
var leftAudioChannel:AVAudioSessionChannelDescription? = nil
var leftAudioPortDesc:AVAudioSessionPortDescription? = nil
for outputPort in outputPorts {
for channel in outputPort.channels! {
leftAudioPortDesc = outputPort
//print("Name: \(channel.channelName)")
if channel.channelName == "Headphones Left" {
channels.append(channel)
leftAudioChannel = channel
}else {
// leftAudioPortDesc?.channels?.removeObject(channel)
}
}
}
if channels.count > 0 {
if #available(iOS 10.0, *) {
print("Setting Left Channel")
speechSynthesizer.outputChannels = channels
print("Checking output channel : \(speechSynthesizer.outputChannels?.count)")
} else {
// Fallback on earlier versions
}
}
}
I have 2 problems in the code
1. Cant able to set outputchannels , It always nil (It is happening on first time calling this method, consecutive calls working fine)
2. outputchannels supports from iOS 10.* But I need to support it from iOS
8.0
Please provide the best way to do that.
Instead of checking the channelName, which is descriptive (i.e. for the user), check the channelLabel. There is an enumeration containing the left channel.
I suspect this may not be possible pre-iOS 10. AVAudioSession doesn't appear to have any method to select only the left output channel. You may be able to use overrideAudioPort:error but it would affect the entire app.

Determine if an iOS device supports TouchID without setting passcode

I'm currently developing an iOS app that enables users to log in to the app using TouchID, but firstly they must set up a password inside the app first. Problem is, to show the setup password option to enable the TouchID login, I need to detect if the iOS device supports TouchID.
Using the LAContext and canEvaluatePolicy (like the answers in here If Device Supports Touch ID), I am able to determine whether the current device supports TouchID if the user has set up passcode on their iOS device. Here is a my code snippet (I'm using Xamarin, so it's in C#):
static bool DeviceSupportsTouchID ()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var context = new LAContext();
NSError authError;
bool touchIDSetOnDevice = context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out authError);
return (touchIDSetOnDevice || (LAStatus) Convert.ToInt16(authError.Code) != LAStatus.TouchIDNotAvailable);
}
return false;
}
If the user has not set up the device passcode, the authError will just return "PasscodeNotSet" error regardless of whether the device actually supports TouchID or not.
If the user's device supports TouchID, I want to always show the TouchID option in my app regardless of whether the user has set up passcode on their device (I will just warn the user to setup passcode on their device first). Vice versa, if the user's device doesn't support TouchID, I obviously don't want to show the TouchID option in my app.
So my question is, is there a nice way to consistently determine whether an iOS device supports TouchID regardless of whether the user has set up passcode on their device?
The only workaround I can think of is to determine the architecture of the device (which is answered in Determine if iOS device is 32- or 64-bit), as TouchID is only supported on devices with 64-bit architecture. However, I'm looking if there's any nicer way to do this.
In conclusion of the discussion below, for the time being it is not possible to determine whether a device actually supports TouchID or not when the user hasn't set up passcode on their device.
I have reported this TouchID flaw on the Apple bug reporter. Those who want to follow the issue can see it on Open Radar here: http://www.openradar.me/20342024
Thanks #rckoenes for the input :)
EDIT
Turns out that someone has reported a similar issue already (#18364575). Here is Apple's reply regarding the issue:
"Engineering has determined that this issue behaves as intended based on the following information:
If passcode is not set, you will not be able to detect Touch ID presence. Once the passcode is set, canEvaluatePolicy will eventually return LAErrorTouchIDNotAvailable or LAErrorTouchIdNotEnrolled and you will be able to detect Touch ID presence/state.
If users have disabled passcode on phone with Touch ID, they knew that they will not be able to use Touch ID, so the apps don't need to detect Touch ID presence or promote Touch ID based features. "
So..... the final answer from Apple is No. :(
Note: similar StackOverflow question from the person who reported this -> iOS8 check if device has Touch ID
(wonder why I didn't find this question before despite my extensive searching...)
The correct way to detect if TouchID is available:
BOOL hasTouchID = NO;
// if the LAContext class is available
if ([LAContext class]) {
LAContext *context = [LAContext new];
NSError *error = nil;
hasTouchId = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
}
Sorry it is in Objective-C, you might have to translate it to C#.
You should refrain from checking the system version and just check whether or not the class or methods are available.
I know this is a question from last year, but this solution does not make what you need? (Swift code)
if #available(iOS 8.0, *) {
var error: NSError?
let hasTouchID = LAContext().canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)
//Show the touch id option if the device has touch id hardware feature (even if the passcode is not set or touch id is not enrolled)
if(hasTouchID || (error?.code != LAError.TouchIDNotAvailable.rawValue)) {
touchIDContentView.hidden = false
}
}
Then, when the user presses the button to log in with touch id:
#IBAction func loginWithTouchId() {
let context = LAContext()
var error: NSError?
let reasonString = "Log in with Touch ID"
if (context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error)) {
[context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
//Has touch id. Treat the success boolean
})]
} else {
//Then, if the user has touch id but is not enrolled or the passcode is not set, show a alert message
switch error!.code{
case LAError.TouchIDNotEnrolled.rawValue:
//Show alert message to inform that touch id is not enrolled
break
case LAError.PasscodeNotSet.rawValue:
//Show alert message to inform that passcode is not set
break
default:
// The LAError.TouchIDNotAvailable case.
// Will not catch here, because if not available, the option will not visible
}
}
}
Hope it helps!
For Objective C
It works great on all devices without checking device version.
- (void)canAuthenticatedByTouchID{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = touchIDRequestReason;
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
}else{
switch (authError.code) {
case kLAErrorTouchIDNotAvailable:
[labelNotSupportTouchID setHidden:NO];
[switchBtn setHidden:YES];
[labelEnableTouchid setHidden:YES];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self showAlertMessage:#"EyeCheck Pro" message:#"Device does not support Touch ID Service."];
});
break;
}
}
}
Here is a bit tedious way to figure out if device has physical touch id sensor.
+ (BOOL)isTouchIDExist {
if(![LAContext class]) //Since this mandotory class is not there, that means there is no physical touch id.
return false;
//Get the current device model name
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *model = malloc(size);
sysctlbyname("hw.machine", model, &size, NULL, 0);
NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
//Devices that does not support touch id
NSArray *deviceModelsWithoutTouchID = [[NSArray alloc]
initWithObjects:
#"iPhone1,1", //iPhone
#"iPhone1,2", //iPhone 3G
#"iPhone2,1", //iPhone 3GS
#"iPhone3,1", //iPhone 4
#"iPhone3,2",
#"iPhone3,3",
#"iPhone4,1", //iPhone 4S
#"iPhone5,1", //iPhone 5
#"iPhone5,2",
#"iPhone5,3", //iPhone 5C
#"iPhone5,4",
#"iPod1,1", //iPod
#"iPod2,1",
#"iPod3,1",
#"iPod4,1",
#"iPod5,1",
#"iPod7,1",
#"iPad1,1", //iPad
#"iPad2,1", //iPad 2
#"iPad2,2",
#"iPad2,3",
#"iPad2,4",// iPad mini 1G
#"iPad2,5",
#"iPad2,5",
#"iPad2,7",
#"iPad3,1", //iPad 3
#"iPad3,2",
#"iPad3,3",
#"iPad3,4", //iPad 4
#"iPad3,5",
#"iPad3,6",
#"iPad4,1", //iPad Air
#"iPad4,2",
#"iPad4,3",
#"iPad4,4", //iPad mini 2
#"iPad4,5",
#"iPad4,6",
#"iPad4,7",
nil];
return ![deviceModelsWithoutTouchID containsObject:deviceModel];
}
Reference:
https://www.theiphonewiki.com/wiki/Models
https://en.wikipedia.org/wiki/IOS
Following is the way by which you can identify whether Touch Id or Face ID is supported on the device
open class LocalAuth: NSObject {
public static let shared = LocalAuth()
private override init() {}
var laContext = LAContext()
func canAuthenticate() -> Bool {
var error: NSError?
let hasTouchId = laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
return hasTouchId
}
func hasTouchId() -> Bool {
if canAuthenticate() && laContext.biometryType == .touchID {
return true
}
return false
}
func hasFaceId() -> Bool {
if canAuthenticate() && laContext.biometryType == .faceID {
return true
}
return false
}
}
And following is the Usage of the above-shared code
if LocalAuth.shared.hasTouchId() {
print("Has Touch Id")
} else if LocalAuth.shared.hasFaceId() {
print("Has Face Id")
} else {
print("Device does not have Biometric Authentication Method")
}
For iOS 11+ you can use biometryType: LABiometryType of LAContext. More from Apple documentation:
/// Indicates the type of the biometry supported by the device.
///
/// #discussion This property is set only when canEvaluatePolicy succeeds for a biometric policy.
/// The default value is LABiometryTypeNone.
#available(iOS 11.0, *)
open var biometryType: LABiometryType { get }
#available(iOS 11.0, *)
public enum LABiometryType : Int {
/// The device does not support biometry.
#available(iOS 11.2, *)
case none
/// The device does not support biometry.
#available(iOS, introduced: 11.0, deprecated: 11.2, renamed: "LABiometryType.none")
public static var LABiometryNone: LABiometryType { get }
/// The device supports Touch ID.
case touchID
/// The device supports Face ID.
case faceID
}
For iOS 11+, for context error, you can check for kLAErrorBiometryNotAvailable

How to detect that the app is running on a jailbroken device? [duplicate]

This question already has answers here:
How do I detect that an iOS app is running on a jailbroken phone?
(18 answers)
Closed 3 years ago.
I have just released my app for iOS, but I'm not sure how to make my app safe from being used by jailbrakers.
Can I do something to prevent my app working on jailbroken devices?
You can detect through code that if the app is running on a jail broken device or not. Through that way you can pop up an alert and close the app. You can do whatever you want to do. Here is a tutorial for it:
http://thwart-ipa-cracks.blogspot.com/2008/11/detection.html
and here is a Stack Overflow post:
How do I detect that an iOS app is running on a jailbroken phone?
Also, if you want a complete solution, you can see in tapjoy sdk code. They are detecting jailbroken iPhone. Here is tapjoy URL https://www.tapjoy.com/
Check for these paths
+ (BOOL)isJailBroken {
#ifdef TARGET_IPHONE_SIMULATOR
return NO;
#endif
NSArray *paths = #[#"/bin/bash",
#"/usr/sbin/sshd",
#"/etc/apt",
#"/private/var/lib/apt/",
#"/Applications/Cydia.app",
];
for (NSString *path in paths) {
if ([self fileExistsAtPath:path]) {
return YES;
}
}
return NO;
}
+ (BOOL)fileExistsAtPath:(NSString *)path {
FILE *pFile;
pFile = fopen([path cStringUsingEncoding:[NSString defaultCStringEncoding]], "r");
if (pFile == NULL) {
return NO;
}
else
fclose(pFile);
return YES;
}
Additionally, you can take a look https://github.com/OneSignal/OneSignal-iOS-SDK/blob/master/iOS_SDK/OneSignalSDK/Source/OneSignalJailbreakDetection.m
Try to find a file which cydia or jailbroken device create. Or try to write in a file outside the app's blackbox. If you succeed to do that, the device is compromised/jailbroken :)
- (BOOL)jailbroken
{
NSFileManager * fileManager = [NSFileManager defaultManager];
return [fileManager fileExistsAtPath:#"/private/var/lib/apt/"];
}
/**
Detect that the app is running on a jailbroken device or not
- returns: bool value for jailbroken device or not
*/
public class func isDeviceJailbroken() -> Bool {
#if arch(i386) || arch(x86_64)
return false
#else
let fileManager = FileManager.default
if (fileManager.fileExists(atPath: "/bin/bash") ||
fileManager.fileExists(atPath: "/usr/sbin/sshd") ||
fileManager.fileExists(atPath: "/etc/apt") ||
fileManager.fileExists(atPath: "/private/var/lib/apt/") ||
fileManager.fileExists(atPath: "/Applications/Cydia.app") ||
fileManager.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib")) {
return true
} else {
return false
}
#endif
}
-(BOOL) isJailbroken
{
#if TARGET_IPHONE_SIMULATOR
return NO;
#else
FILE *f = fopen("/bin/bash", "r");
if (errno == ENOENT)
{
// device is NOT jailbroken
fclose(f);
NSLog(#"no");
return NO;
}
else {
// device IS jailbroken
fclose(f);
NSLog(#"yes");
return YES;
}
#endif
}
You can detect if a device is jailBroken or not by checking the following
Cydia is installed
Verify some of the system paths
Can perform a sandbox integrity check
Perform symlink verification
Verify whether you create and write files outside your Sandbox
There is an open source library I created from various articles and books, try it out.
Based off of #karim's answer heres a slightly modified swift version:
func hasJailbreak() -> Bool {
#if arch(i386) || arch(x86_64)
println("Simulator")
return false
#else
var fileManager = NSFileManager.defaultManager()
if(fileManager.fileExistsAtPath("/private/var/lib/apt")) {
println("Jailbroken Device")
return true
} else {
println("Clean Device")
return false
}
#endif
}
Even if your device is jailbroken , ipa applications can only access their own sand boxes, so
If device is either jailbroken or not your method will return NO :)
Look for another way
Also if you try to access somewhere but your sandbox publishing app on the appstore may head problems
There are many ways to find the jailbroken devices. checking cydia technic will not be work if skilled hacker changes the application path.
A good way to check for it would be to see if we can modify a file in some other location outside the application bundle.
NSError *error;
NSString *stringToBeWritten = #"This is a test.";
[stringToBeWritten writeToFile:#"/private/jailbreak.txt" atomically:YES
encoding:NSUTF8StringEncoding error:&error];
if(error==nil){
//Device is jailbroken
return YES;
} else {
//Device is not jailbroken
[[NSFileManager defaultManager] removeItemAtPath:#"/private/jailbreak.txt" error:nil];
}
Find more techniques in the below url
http://highaltitudehacks.com/2013/12/17/ios-application-security-part-24-jailbreak-detection-and-evasion/
SWIFT 3:
func hasJailbreak() -> Bool {
#if arch(i386) || arch(x86_64)
print("Simulator")
return false
#else
return FileManager.default.fileExistsAtPath("/private/var/lib/apt")
#endif
}
There is no way to detect if device is jailbroken.
Consider that even if there was, the device has already been jailbroken, meaning arbitrary code execution is possible, and the jailbreaker would just modify whatever method of detection you would use to signal that the device has not been jailbroken.
reference:
https://forums.developer.apple.com/thread/43073
credits go to Apple Staff who answered this same question

Resources