How do I exclude iPad 2 and iPod Touch 5th Generation in a function? - objective-c

I'm trying to create a function that works on ALL iOS devices except the iPad 2 and the iPod Touch 5th Gen.
- (void)doSomething {
// if iPad 2 or iPod 5th Gen
if ()
{
NSLog(#"You're using an iPad 2 or iPod 5th Gen. Sorry!");
}
else
{
NSLog(#"Any other iOS device. Congrats!");
} }
Can someone post a quick sample snippet of how I would accomplish this?

If your app has a major hardware requirement (i.e., it can't really function/do anything useful if the hardware isn't present on the device), you should add an entry to the UIRequiredDeviceCapabilities entry in your Info.plist for your app. This will keep people who don't have the necessary hardware to use your app from purchasing it/downloading it by accident. It will also cause the App store to show a list of all the models that support your software, so people can see what they need in order to use it.
If your app has a function that requires something specific, there are generally in-framework tests you can do to see if the device has the required features/hardware. If this isn't your app's central purpose, you can then enable/disable this feature of your app based on the device's capabilities. You wouldn't want to try and query which device the user is running (except in maybe very limited circumstances), but would rather query whether the device is capable of doing what you want.
Since you mentioned an auto-focusing camera, we'll use that as an example. If your app requires this to do anything useful, you should add the UIRequiredDeviceCapabilities key to your Info.plist file and add the entry auto-focus-camera to the array. This will ensure that only users who have a device with an auto-focusing camera will be able to purchase and install your app. For more information on UIKit keys for Info.plist, including this one, see the Information Property List Key Reference.
If, on the other hand, your app is usable by any device but has a feature that requires an auto-focusing camera, you can test for it's presence using the AVFoundation framework. You can get what you need here from the AVCaptureDevice class. For example, to check if you have access to an auto-focusing camera for video/stills:
// Check for the default camera
AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if( camera && [camera isFocusModeSupported:AVCaptureFocusModeAutoFocus] ) {
// this device has a default video source capable of autofocus, so enable the feature
} else {
// this device does not have the required hardware, so disable the feature
}

Check this:
if ([[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
//device with autofocus
}
else {
//device without autofocus
}

Related

How to identify actual touchBar hardware is available in an Mac book using obj c?

How to identify actual touchBar hardware is available in an Mac book using obj c code so that i can provide touchbar menu options.
From the Apple documentation :
There is no need, and no API, for your app to know whether or not there is a Touch Bar available. Whether your app is running on a machine that supports the Touch Bar or not, your app’s onscreen user interface (UI) appears and behaves the same way.
To check if touch bar is available (to improve UI/UX for example) you should implement the delegate and set a Bool like :
// Declare a class variable
#property (nonatomic, assign) BOOL isTouchBarAvailable;
#available(OSX 10.12.1, *)
// A bellow version can not be installed on a new MacBook.
// Like an iPhone 7 can't have iOS9 installed.
- (NSTouchBar *)makeTouchBar
{
// ... here the code to make the bar
self.isTouchBarAvailable = YES
return touchBar
}
Source : https://developer.apple.com/reference/appkit/nstouchbar?language=objc
NSTouchBar can work in software as well as hardware, as show by the simulator in Xcode. It doesn't require the hardware to work. However, the Xcode 8 release notes tells you how to test if the OS can support any kind of Touch Bar functions.
https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
Xcode 8.1 supports Touch Bar for Macs that include it, and supports adding Touch Bar functionality to your app. (28859277)
Before using Touch Bar functionality in your app, confirm that the app is running on a macOS version that includes support for Touch Bar using a runtime check.
For example, the following Objective-C code performs a runtime check to make sure NSTouchBar is available:
NSClassFromString(#"NSTouchBar") != nil
In Swift code, do an availability check for macOS 10.12.1, and a runtime check for Touch Bar class availability. For example:
NSClassFromString("NSTouchBar") != nil
If you want some control you can use isAutomaticCustomizeTouchBarMenuItemEnabled:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Here we just opt-in for allowing our instance of the
// NSTouchBar class to be customized throughout the app.
if #available(OSX 10.12.2, *) {
NSApplication.shared().isAutomaticCustomizeTouchBarMenuItemEnabled = true
}
}
/*
Whether or not a menu item to customize the touch bar can be automatically
added to the main menu. It will only actually be added when hardware
or simulator is present. Defaults to NO. Setting this property to YES
is the recommended way to add the customization menu item.
*/

Change iOS Simulator Device Name

I'm working on a big project with many view controllers. Progression through these views depends on data being filled in on lengthy forms.
In my not-so-clever way i'm autofilling data so that i can speed through to the current feature I'm working on. I was using a conditional like this...
if(
[[[UIDevice currentDevice] name] hasPrefix:#"Rob"] ||
[[[UIDevice currentDevice] name] hasPrefix:#"iPad Simulator"]
)
{
self.label.text = #"xxx";
...
}
...this worked great because I could test both on my iPad and in the simulator. Now the client wants to also be able to test on their simulator, so I can't leave my autofill in. I'm thinking the simplest solution would be to just change the name of the simulator.
In Settings.app on the simulator, it's not editable. I also haven't seen then text "iPad Simulator" or "Simulator" show up in any files in ~/Library/Application Support/iPhone Simulator/5.1. I've done searches on setting plist properties, but no luck.
Does anyone know how to accomplish this?
You'll be able to check if it's running the iPhone Simulator by checking the model rather than the name of the current device. Something like the following should do:
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone Simulator"]) {
// Run for iPhone simulator
}
Note: You'll need to use "iPad Simulator" for when you use the iPad Simulator
Also, your current code with hasPrefix is not secure at all. Rob is a common name so if someone else has a device with the name of their device beginning with Rob then it'll expose your test information. I highly suggest you just target this autocomplete for the simulator only
Just create a new class and put your loading logic there.
After that, call this class from your delegate didFinishLaunchingWithOptions method.
With this, you can comment the above call whenever you want or better, check if the data is already loaded and ignore it.

How do you programmatically detect your iPad's generation?

I'm working on a program that needs to be able to detect whether or not camera hardware is present in the iPad. I assumed that the easiest way to do this was to determine what generation the device was, but if there is a simpler way to detect the hardware that works too. The iPads that this application is being designed for will likely be recently purchased and running on a standard updated version of iOS.
Nope You can simply check what device is being used!
For checking all iOS devices:
NSString *deviceType = [UIDevice currentDevice].model;
NSLog(deviceType);
In order to check for a camera
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
//there is a camera

Receive remote control events without audio

Here is some background information, otherwise skip ahead to the question in bold. I am building an app and I would like it to have access to the remote control/lock screen events. The tricky part is that this app does not play audio itself, it controls the audio of another device nearby. The communication between devices is not a problem when the app is in the foreground. As I just found out, an app does not assume control of the remote controls until it has played audio with a playback audio session, and was the last do so. This presents a problem because like I said, the app controls ANOTHER device's audio and has no need to play its own.
My first inclination is to have the app play a silent clip every time it is opened in order to assume control of the remote controls. The fact that I have to do this makes me wonder if I am even going to be allowed to do it by Apple or if there is another way to achieve this without fooling the system with fake audio clips.
QUESTION(S): Will Apple approve an app that plays a silent audio clip in order to assume control of the remote/lock screen controls for the purpose of controlling another device's audio? Is there any way of assuming control of the remote controls without an audio session?
P.S. I would prefer to have this functionality on iOS 4.0 and up.
P.P.S I have seen this similar question and it has gotten me brainstorming but the answer provided is not specific to what I need to know.
NOTE: As of iOS 7.1, you should be using MPRemoteCommandCenter instead of the answer below.
You create various system-provided subclasses of MPRemoteCommand and assign them to properties of the [MPRemoteCommandCenter sharedCommandCenter].
I'm keeping the rest of this around for historical reference, but the following is not guaranteed to work on recent iOS versions. In fact, it just might not.
You definitely do need an audio player but not necessarily an explicit session to take control of the remote control events. (AVAudioSession is implicit to any app that plays audio.) I spent a decent amount of time playing with this to confirm this.
I've seen a lot of confusion on the internet about where to set up the removeControlEventRecievedWithEvent: method and various approaches to the responder chain. I know this method works on iOS 6 and iOS 7. Other methods have not. Don't waste your time handling remote control events in the app delegate (where they used to work) or in a view controller which may go away during the lifecycle of your app.
I made a demo project to show how to do this.
Here's a quick rundown of what has to happen:
You need to create a subclass of UIApplication. When the documentation says UIResponder, it means UIApplication, since your application class is a subclass of UIResponder. In this subclass, you're going to implement the remoteControlReceivedWithEvent: and canBecomeFirstResponder methods. You want to return YES from canBecomeFirstResponder. In the remote control method, you'll probably want to notify your audio player that something's changed.
You need to tell iOS to use your custom class to run the app, instead of the default UIApplication. To do so, open main.m and change this:
return UIApplicationMain(argc, argv, nil, NSStringFromClass([RCAppDel`egate class]));
to look like this:
return UIApplicationMain(argc, argv, NSStringFromClass([RCApplication class]), NSStringFromClass([RCAppDelegate class]));
In my case RCApplication is the name of my custom class. Use the name of your subclass instead. Don't forget to #import the appropriate header.
OPTIONAL: You should configure an audio session. It's not required, but if you don't, audio won't play if the phone is muted. I do this in the demo app's delegate, but do so where appropriate.
Play something. Until you do, the remote controls will ignore your app. I just took an AVPlayer and gave it the URL of a streaming site that I expect to be up. If you find that it fails, put your own URL in there and play with it to your heart's content.
This example has a little bit more code in there to log out remote events, but it's not all that complicated. I just define and pass around some string constants.
I bet that a silent looping MP3 file would help work towards your goal.
Moshe's solution worked great for me! However one issue I noticed is when you paused the audio, the media controls would go away and you won't be able to play it again without going back into the app. If you set the Media Info on the lock screen when you play the audio then this won't happen:
NSDictionary *mediaInfo = #{MPMediaItemPropertyTitle: #"My Title",
MPMediaItemPropertyAlbumTitle: #"My Album Name",
MPMediaItemPropertyPlaybackDuration: [NSNumber numberWithFloat:0.30f]};
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:mediaInfo];

Detecting when a space changes in Spaces in Mac OS X

Let's say I want to write a simple Cocoa app to make the Spaces feature of Leopard more useful. I would like to configure each space to have, say, different
screen resolutions
keyboard layouts
volume (for audio)
So there are two parts to my question:
I suppose there are ways to modify these three things independently of Spaces, right? If so, how?
How can I detect in my app when a space change occurs, and when that happens, determine what space the user just switched to? Does Leopard send out some distributed notifications or something?
Update: There has to be some public API way of doing this, judging from all the Spaces-related apps on the Mac App Store.
As Peter says, in 10.6 you can use the NSWorkSpace NSWorkspaceActiveSpaceDidChangeNotification to get a notification when the workspace changes.
You can then determine the current space using Quartz API, the kCGWindowWorkspace dictionary key holds the workspace.
e.g:
int currentSpace;
// get an array of all the windows in the current Space
CFArrayRef windowsInSpace = CGWindowListCopyWindowInfo(kCGWindowListOptionAll | kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
// now loop over the array looking for a window with the kCGWindowWorkspace key
for (NSMutableDictionary *thisWindow in (NSArray *)windowsInSpace)
{
if ([thisWindow objectForKey:(id)kCGWindowWorkspace])
{
currentSpace = [thisWindow objectForKey(id)kCGWindowWorkspace] intValue];
break;
}
}
Alternatively you can get the Space using the private API, take a look at CGSPrivate.h which allows you to do this:
int currentSpace = 0;
CGSGetWorkspace(_CGSDefaultConnection(), &currentSpace);
To change the screen resolution you'll want to look at Quartz services, for altering the volume this may be helpful.
NSWorkspace posts a NSWorkspaceActiveSpaceDidChangeNotification on its own notification center, but only on Snow Leopard.