Adapt app from iOS7 to iOS6 - iphone

I wrote my application for iPhone in xcode 5.0 and it supports only 7 ios.
How can I make it available for ios 6?
Also interested in how to prevent applications load on ipad?

First question: Make sure your deployment target is 6.0, don't use API's that are iOS 7 only, or check by using
if ([someObject respondsToSelector:#selector(ios7onlymethod)] {
// do your iOS 7 only stuff
} else {
// Fall back to iOS 6-supported ways
}
Or use
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f) {
// do your iOS 7 only stuff
} else {
// Fall back to iOS 6-supported ways
}
New frameworks you want to use should be marked as optional in Xcode; to do that select your target, click general, and scroll to the "Linked Frameworks and Libraries" section.
What's really cool is that classes in frameworks marked as optional are replaced with nil on versions of iOS that don't have them. So suppose you write some code like this, using a class from the Sprite Kit framework, new in iOS 7:
SKSpriteNode *spriteNode = [SKSpriteNode spriteWithImageNamed:#"mySprite"];
On iOS 6, when the linker, which "links" frameworks to apps (apps don't copy frameworks, they just get them from the system), sees SKSpriteNode in your code, and the framework is marked as optional, that line of code will be replaced by this:
... = [nil spriteWithImageNamed:#"mySprite"];
Sending messages to nil in Objective-C does absolutely nothing, so the above code doesn't crash. No problem. So instead of lingering your code with if-statements checking for the existence of a class, you can just go with the flow and let the dynamic linker do the work.
Further reading:
iOS 7 UI Transition Guide: Supporting iOS 6
Supporting Multiple iOS Versions and Devices
Second question: There is no way to say that you want your app to only run on iPhones and iPod touches. You can require things that are specifical to the iPhone and iPod touch (like a certain processor architecture or the M7 motion coprocessor) but Apple won't like it if you require the M7 chip to exclude a certain device when you don't even need it. You should probably think about why you don't want your app to run on iPads.

Related

iOS 4 and iOS 5 backward compatibility

I have a question regarding iOS 4 and 5. I am really confused and hope someone will clear it out for me.
I am using iOS 5 SDK in my application. If i use the iOS 5 Twitter integration which is provided by apple, will it run on an iPhone that has iOS 4 installed ?
Does backward compatibility work ?
I have used Twitter as an example, but does backward compatibility really work with iOS 5 ?
If you set up your app properly, so that it can be run on devices running iOS 4 without crashing, then: yes, it will run on an iPhone that has iOS 4 installed.
Your app should implement logic such that the Twitter API is used when the app is being run on an iOS 5 device. When the app is running on an iOS 4 device, you can conditionally choose not to use the Twitter API.
Instead, you can use a different Twitter library (like MGTwitterEngine, or your own) - or just exclude Twitter functionality for those users.
To check whether the TWRequest Class exists, use NSClassFromString.
Class twRequestClass = NSClassFromString(#"TWRequest");
if (twRequestClass == nil) {
// TWRequest does not exist on this device (running iOS version < 5.0)
// ... do something appropriate ...
} else {
TWRequest *twRequest = [[twRequestClass alloc] init];
// ^ I didn't look up the proper initializer, so you should change that line if necessary
// ...
}
You would have to create ifs dependently of the iOS version the user is using. Exemple, in iOS 5 there is an Appearance API to modify most of the UI, but not in iOS 4, so you have to create a little if like that:
// not supported on iOS4
UINavigationBar *navBar = [myNavController navigationBar];
if ([navBar respondsToSelector:#selector(setBackgroundImage:forBarMetrics:)])
{
[navBar setBackgroundImage:[UIImage imageNamed:#"bg.jpg"] forBarMetrics:UIBarMetricsDefault];
}
If you set up your app properly, so that it can be run on devices running iOS 4, it will crash. This is because you're trying to access methods/features that arn't available.
The way to get around this is to check if a feature is available using
if(NSClassFromString(#"UIPopoverController")) {
// Do something
}
(Popover controller is just an example)
You could also check the version using
float version = [[[UIDevice currentDevice] systemVersion] floatValue];
And then depending on the version run a specific piece of code (i.e. if iOS 5, preform twitter stuff,else do something different)
No, if you use the Twitter APIs available in iOS5, they will not be able to run on iOS4.
The reason being that when app will run on iOS4, the system will not be having the APIs availability.
if you check the documentation, you can see the iOS version from where this Class/API is available.
I hope this helps..

iOS5 CMMotionManager startDeviceMotionUpdatesToQueue: fails on iPhone3GS

I have a software-hardware related issue that I'm trying to troubleshoot. My app was developed for iPhone4, iOS5 and uses Core Motion framework to process accelerometer and gyroscope data in real time. The app fails when running on iPhone 3GS with iOS5
My main core-motion method looks like this:
[motionManager startDeviceMotionUpdatesToQueue:motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
//notify calibration delegate
if(calibrationDelegate)
{
[calibrationDelegate collectCalibrationMotionData:motion];
}
//a lot more processing
}
I have reports that iPhone3GS does not return yes to isGyroAvailable, while iPhone4 returns yes.
BOOL accelerometerAvailable = (motionManager.isAccelerometerAvailable)?YES:NO;
BOOL gyroscopeAvailable = (motionManager.isGyroAvailable)?YES:NO;
if(!accelerometerAvailable && ! gyroscopeAvailable)
{
//handle error
remoteControlState = kRemoteControlStateError;
}
I've painfully discovered that Apple sells my app to customers with iPhone4, 4s AND 3GS. The app does not work for customers with iPhone 3GS because the call above does not seem to pass the motion objects to the calibration delegate.
I do not have iPhone 3GS to test the app on, so I have a few questions:
Is it possible to specify anywhere in the XCode project properties
that I want my app to run ONLY on iPhone4 and above? (or devices with gyroscope available?)
Where can I find more information on iOS5 quirks like the one above
to better understand how iPhone3GS differs from iPhone4?
Is it possible to specify anywhere in the XCode project properties that I want my app to run ONLY on iPhone4 and above? (or devices with gyroscope available?)
Yes, you would specify such dependencies in the UIRequiredDeviceCapabilities key of your Info.plist (gyroscope would be the requirement in this case).
However, for a released app, it's unfortunately impossible to add new requirements.

best practice to write app both for ios4.3, ios5 and ipad

I am just started write app for ios.
I have 2 questions.
I know there are some codes which work fine in ios4.3 but don't work in ios5 and the opposite is also true.I want to know,which is the best practice for writing app both for ios4.3 and ios5?Is it acceptable run-time to check the version for specific parts of code??
I am also should write same app for ipad. So, I want to know which is the best practice for writing app for iphone which works also on ipad??
Thanks
iOS 5 or iOS 4
Another way to detect the version is to use the respondsToSelector: message on objects. The advantage compared to the version method is that you don't need to know what the next versions of iOS are gonna be to maintain your application. (What if, for instance, a new 5.0.2 version shows up? Your app should know that the "5.0.2" string is newer than "5.0"? I agree it would not be complicated to code, but using respondsToSelector: is much more convenient)
iPhone/iPod Touch or iPad
My usual way to code universal app (ie iPhone and iPad) is to define a basic implementation of my custom UIViewController classes, and then implement an HD version of it, inheriting the default behavior but customizing it for the iPad (overriding methods works well but the delegate pattern might be better: you get compilation warnings if you forget to implement methods).
If you use a different .xib file from the beginning of your application lifecycle (that's what you get by universal Xcode-provided templates), you may end up defining classes just from Interface Builder, and won't need to implement any runtime test in your code to know if you're running on an iPhone or an iPad.
You can get the version using:
[[UIDevice currentDevice] systemVersion];
The systemVersion returns a string, like "5.0". You can then compare the strings using string comparison. For example:
NSString *requiredVersion = #"5.0";
NSString *currentVersion = [[UIDevice currentDevice] systemVersion];
if ([currentVersion compare:requiredVersion options:NSNumericSearch] != NSOrderedAscending)
isItSupported = TRUE;
The documentation indicates that you can use the following to determine if you have an iPhone or iPad:
[[UIDevice currentDevice] model];
I've not used this though.
See the documentation.

ios: add printing, but keep compatibility with ios 3

i'm trying to add printing features to an ios app.
while printing itself works fine, and the app works on ios > 4, i haven't figured out yet how to keep the ios 3.1 compatibility...
i guess the issue is this: completionHandler:(UIPrintInteractionCompletionHandler)
A block of type UIPrintInteractionCompletionHandler that you implement to handle the
conclusion of the print job (for instance, to reset state) and to
handle any errors encountered in printing.
once i add the block:
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
the app won't even launch on iOS 3.1
probably because blocks aren't available there.
yes, i made sure that this code won't be run when launched on iOS 3.1...
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.2) && ([UIPrintInteractionController isPrintingAvailable]))
so i wonder if there's a way to have printing support for iOS >4.2, but keeping it to run on iOS 3.1?
maybe there's a way to use a method instead of the "block"?
or how would be the correct way to have printing available on supported iOS devices, and remain backwards compatible to iOS 3.1?
just add -weak_framework UIKit to the project settings under "Other Linker Flags" and make sure you use conditional code for printing API.
Conditional code should check feature availability, not OS version:
if (NSClassFromString(#"UIPrintInteractionController")){
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
}
Set your project target to iOS 3, and you're good to go.
The best practice for detecting if AirPrint is available is to use NSClassFromString. If you use this method in general, then you always know if exactly the class you want is available, without having to hard-code which features correspond with which version. Example code:
Class printControllerClass = NSClassFromString(#"UIPrintInteractionController");
if (printControllerClass) {
[self setupCanPrintUI];
} else {
[self setupCannotPrintUI];
}
That way your app can still work on previous iOS versions, although it won't be able to print from them.
I've been able to use this technique and run it on an iOS 3.0 device without any problems with the block code (the ^-based stuff). In my build settings, I have the Base SDK set to iOS 4.2, and the Deployment Target set to iOS 3.0.
I posted a sample Xcode project at the end of this blog post on printing in iOS. This is the project that successfully runs for me on a device with iOS 3.0 and another device with iOS 4.2. You may have to change the bundle identifier in the info.plist to get the code-signing to work for you, but that's independent of the printing stuff.
Set Deployment Target in your Project Settings to iOS 3.x. However, set the Base SDK to 4.2. Now you can use the 4.2 classes and iPhones running 3.x can install your app too.
Keep in mind that when you use a 4.2 class on an iPhone 3.x, the application will crash (so keep checking the system version on-the-go).
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:#"3.2" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending && [[UIDevice currentDevice]isMultitaskingSupported]) {
// >4.2
}
else {
//< 4.2
}
Note:
also change UIKit framework setting from "required" to "weak" this will help you to run application on iOs < 4.2 as well as iOs >= 4.2

How do I run a universal app on the iPhone 3.1.3 simulator?

I'm working on a new app that I want to be universal for the iPhone and iPad. I started out with the "Create a Window-based app" wizard, and it created separate app delegates in "iPhone" and "iPad" groups. Since I already was quite familiar with iPhone dev, I did that part of my project, and now I'm ready to do some iPad stuff.
So... I started out by adding a UISplitViewController to my iPad delegate, switch the Active SDK to 3.2, and it works! But when I switch back to 3.1.3, and try to run it in the simulator, Build and Go fails. For starters, I see:
...path.../iPad/AppDelegate_Pad.h:13: error: expected specifier-qualifier-list before 'UISplitViewController'
I've got my Base SDK set to 3.2 and my Deployment Target set to 3.1.3. I thought that was enough. But I also have found in the documentation this method to conditionally compile:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
MyIPadViewController* vc;
// Create the iPad view controller
#else
MyIPhoneViewController* vc;
// Create the iPhone view controller
#endif
So do I need to do this everywhere? It seems like an awful lot of code to add (that I'll be getting rid of in a short time for 4.0 anyway) so I feel like I must be doing something wrong. And, I don't even have any idea how this works for things like #property or #synthesize declarations.
tl;dr version of the question - did I miss a setting somewhere?
I use this C function to help keep the code concise:
BOOL isPad() {
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}
Another thing I do, when I have different xib files for iPhone vs iPad. I have a stripPadSuffixOnPhone() function that helps keep the code simpler:
// Load/create the Delete table cell with delete button
self.deleteCell = [Utilities loadNib:stripPadSuffixOnPhone(#"DeleteCell~ipad")
ClassName:#"DeleteCell"
Owner:self];
Things like that can make coding more straightforward and a lot less conditionals. Still have to test everything twice though.
Quite the opposite. A universal app runs the same binary on iPhone and iPad so you cannot use conditional compilation to differentiate between the two version. But you need to use the macro Apple cites in the documentation:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad-specific code
} else {
// iPhone-specific code
}
Here's what works for me:
Build your app using SDK 3.2.
Switch the active SDK to iPhone Simulator 3.1.3 (or whatever).
From the Run menu select Debug (not Build and Debug).
The binary built under 3.2 will be installed in the 3.x simulator without rebuilding. When you are finished don't forget to set your active SDK back to 3.2.