I'm sorry about asking this question which is discussed here many times once again. But none of the answers haven't really helped me. All I need is to put some simple code in a viewDidLoad to check whether the headphones are plugged in or are not. (If they aren't I want to pop up simple message, but that's not what I'm asking how to do.) Any help?
This should achieve what you want (iOS 6+ compatible)
- (BOOL)areHeadphonesPluggedIn {
NSArray *availableOutputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
for (AVAudioSessionPortDescription *portDescription in availableOutputs) {
if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones]) {
return YES;
}
}
return NO;
}
Here is the Swift 1.2 Version of the code written by Gabriele Petronella
//This method checks if headphones are plugged in.
func areHeadphonesPluggedIn()->Bool
{
var availableOutputs = AVAudioSession.sharedInstance().currentRoute.outputs
for portDescription in availableOutputs
{
if portDescription.portType == AVAudioSessionPortHeadphones
{
return true
}
}
return false
}
Related
Please help me to find out the reason why crash.I known had many question with the same title but with I cannot find out solution for my problem. My problem is my app crash(Bad Access) with ios7, with old version it work ok. This is my code:
- (void)updateLine:(NSNotification*)notification
{
BOOL registered =[(notification.userInfo)[kRADialePushViewNotificationRegistration] boolValue];
if (!registered) {
if (self.navigationController) {// it crash this line
[self.navigationController popViewControllerAnimated:YES];
}
}
}
I find out the problem here is: self.navigationController is nil. But I don't know why ios7 don't accept for access a nil navigationController while I can do it on ios6 or older. My solution is check if the view is current view (it's my DND view), I call popViewController, because if the view is current view you can get self.navigationController which have value not nil.My code is:
- (void)updateLine:(NSNotification*)notification
{
BOOL registered =[(notification.userInfo)[kRADialePushViewNotificationRegistration] boolValue];
if (!registered) {
if (self.isloaded && self.view.window){
if (self.navigationController) {
[self.navigationController popViewControllerAnimated:YES];
}
}
}
}
Is there a way to tell if an iOS app enters the foreground from fast-app switching or manually? I need to know by the time applicationWillEnterForeground is called, so some specific code can be executed (or not executed) depending on the condition in which the app entered the foreground.
EDIT:
It turned out that this was more of a design issue for me. I moved my code to applicationDidBecomeActive. I also added a BOOL property to the appDelegate called fastAppSwitching (probably the wrong name for it). I set this to YES in application:handleOpenURL and application:openURL:sourceApplication:annotation. Then I added the following code to application:didFinishLaunchingWithOptions:
if (launchOptions) {
self.fastAppSwitching = YES;
}
else {
self.fastAppSwitching = NO;
}
In applicationDidBecomeActive, I used the following code:
if (fastAppSwitching == YES) {
self.fastAppSwitching = NO; //stop, don't go any further
}
else {
...
}
EDIT2: MaxGabriel makes a good point below: "Just a warning to others taking the solution described here, applicationDidBecomeActive: is called when the user e.g. ignores a phone call or text message, unlike applicationWillEnterForeground". This is actually also true for in-app purchases and Facebook in-app authorization (new in iOS 6). So, with some further testing, this is the current solution:
Add a new Bool called passedThroughWillEnterForeground.
In applicationWillResignActive:
self.passedThroughWillEnterForeground = NO;
In applicationDidEnterBackground:
self.passedThroughWillEnterForeground = NO;
In applicationWillEnterForeground:
self.passedThroughWillEnterForeground = YES;
In applicationDidBecomeActive:
if (passedThroughWillEnterForeground) {
//we are NOT returning from 6.0 (in-app) authorization dialog or in-app purchase dialog, etc
//do nothing with this BOOL - just reset it
self.passedThroughWillEnterForeground = NO;
}
else {
//we ARE returning from 6.0 (in-app) authorization dialog or in-app purchase dialog - IE
//This is the same as fast-app switching in our book, so let's keep it simple and use this to set that
self.fastAppSwitching = YES;
}
if (fastAppSwitching == YES) {
self.fastAppSwitching = NO;
}
else {
...
}
EDIT3: I think we also need a bool to tell if app was launched from terminated.
If your application is launched by another application, the
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
sourceApplicarion:(NSString *)bundleID
annotation:(id)info;
method is called on your app delegate. You can use this method to e. g. set a Boolean switch to true that indicates whether the app was launched by another program.
The peoblem is that this method is called after applicationWillEnterForeground:, so you can't tell in that method whether your app was launched manually or automatically.
However, I suspect that if you need this to be detected in a particular method, you may have a design problem and you should probably reorganize your code.
In the case where your app is opened from another app, application:openURL:sourceApplication:annotation will be called on your app delegate.
I have seen many tutorials over internet to detect blow in iPhone but my app's requirement is that I need to detect single blow and double blow both so that if user blow single time it can perform action a and if the user blow two times together then to perform action b.
Any way to do this?
Thanks all,
Surely if you know how to detect a single blow, you could just have a timer with a threshold & see if another blow happens within that time? Something like -
-(void)userDidBlow {
if (hasBlownOnce) {
hasBlownOnce = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(singleBlowTimedOut) object:nil];
// do double-blow stuff
} else {
hasBlownOnce = YES;
[self performSelector:#selector(singleBlowTimedOut) withObject:nil afterDelay:kDoubleBlowTime];
}
}
-(void)singleBlowTimedOut {
hasBlownOnce = NO;
// do single-blow stuff
}
I haven't tested it, but it looks ok :)
I am using MPVolumeView for showing Airplay icon and it works fine.
But I need to show an animation when Airplay network comes, and hide that animation when airplay network hides.
Is there a notification that will let me know when Airplay starts and ends?
This is exactly what you're looking for - https://github.com/StevePotter/AirPlayDetector
It is a single class that provides a property to determine whether airplay devices are active. And a notification when availability changes.
Using it is simple. Like, to determine availability you write:
[AirPlayDetector defaultDetector].isAirPlayAvailable
Enjoy!
To be precise:
To check exactly for airplay with public API: NO
All you can do with public API is to check for available wireless routes, which includes airplay in it: (In simple case when you have a MPVolumeView instance hooked up somewhere to your view, you can just call volumeView.areWirelessRoutesAvailable;)
If you are curious how to check if exactly airplay is available with private API:
- (BOOL)isAirplayAvailable
{
Class MPAVRoutingController = NSClassFromString(#"MPAVRoutingController");
id routingController = [[MPAVRoutingController alloc] init];
NSArray* availableRoutes = [routingController performSelector:#selector(availableRoutes)];
for (id route in availableRoutes) {
NSDictionary* routeDescription = [route performSelector:#selector(avRouteDescription)];
if ([routeDescription[#"AVAudioRouteName"] isEqualToString:#"AirTunes"])
return true;
}
return false;
}
(And in fact MPVolumeView has an MPAVRoutingController instance as its ivar, so the -areWirelessRoutesAvailable is just an accessor exactly for [volumeView->_routingController wirelessDisplayRoutesAvailable])
Also AVAudioSession exposes currentRoute to you, so you do can check if airplay is active easily with:
- (BOOL)isAudioSessionUsingAirplayOutputRoute
{
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription* currentRoute = audioSession.currentRoute;
for (AVAudioSessionPortDescription* outputPort in currentRoute.outputs){
if ([outputPort.portType isEqualToString:AVAudioSessionPortAirPlay])
return true;
}
return false;
}
(the answer about AirPlayDetector doesn't guarantee that Airplay is available - all it does it checks the alpha value of MPVolumeView's routeSelection button, which will be shown in any case when wireless routes are available, bluetooth for example. It will do exactly the same as volumeView.areWirelessRoutesAvailable;)
There's a MPVolumeViewWirelessRoutesAvailableDidChangeNotification since iOS 7 you can register for.
It can be done much easier with ReactiveCocoa. Check it out:
MPVolumeView *myVolumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(0, 0, 180, 22)];
for (UIView *view in myVolumeView.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
[[RACAbleWithStart(view, alpha) distinctUntilChanged] subscribeNext:^(id x) {
NSLog(#"airplay button visibility changed %#", x);
}];
[[RACAbleWithStart(view, frame) distinctUntilChanged] subscribeNext:^(id x) {
NSLog(#"airplay button connection changed %#", x);
}];
}
}
6 years later.
I think Sankar Siva did not ask for detecting, but for activating an airplay route.
I've upped #Alf because he placed me on the right direction, but he is not answering to the question.
MPVolumeViewWirelessRoutesAvailableDidChangeNotification fires when MPVolumeView detects a new route.
On the other hand, MPVolumeViewWirelessRouteActiveDidChangeNotification fires when a new route is taken, eg: when you select your Apple TV for example.
No need of private API.
If you want a notification here is the way to do it
[[NSNotificationCenter defaultCenter]
addObserver:self
selector: #selector(deviceChanged:)
name:AVAudioSessionRouteChangeNotification
object:[AVAudioSession sharedInstance]];
- (void)deviceChanged:(NSNotification *)sender {
NSLog(#"Enters here when connect or disconnect from Airplay");
}
I'm currently using -respondsToSelector: like so:
if (![moviePlayer respondsToSelector:#selector(currentPlaybackTime)]) {
NSLog(#"Cannot get current playbackTime on %#", moviePlayer);
return;
}
where moviePlayer is an instantiated MPMoviePlayerController object. I do a lot of other similar selector checks, so I know that pretty much everything else is working fine, but for some reason, this respondsToSelector check returns false, even though if I do something like time = [moviePlayer currentPlaybackTime], it works fine. This is on 4.0+ iOS, so there's no reason for it to return false.
Any reasons why this would happen?
According to the iOS class reference, currentPlaybackTime is a property of MPMusicPlayerController, not MPMoviePlayerController.
MPMusicPlayerController:
http://developer.apple.com/library/ios/#documentation/MediaPlayer/Reference/MPMusicPlayerController_ClassReference/Reference/Reference.html
MPMoviePlayerController:
http://developer.apple.com/library/ios/#documentation/MediaPlayer/Reference/MPMoviePlayerController_Class/MPMoviePlayerController/MPMoviePlayerController.html
It may be a private property of MPMoviePlayerController that does not have an accessor.
EDIT (see comments)
Determine OS version:
float iPhoneOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if ( iPhoneOSVersion < 3.2 )
{
}
else
{
}