EDIT: It is appearing that there may not be ANY possible way to, on app termination only, set the device volume back to the level it was when an app started. To me this is a possible oversight on the part of Apple. Why wouldn't Apple want my app to be a good camper that leaves their campsite the way they found it, there must be a way, please help... I tried to get an answer to this broader question with another topic but it was closed as a duplicate, please go there and vote to re-open it :)
When my app terminates, I want to set the system volume back to the same volume it was when my app started (Edit: and not change the volume when the app enters the background).
I am attempting to do that with MPVolumeView as the mechanism to set the devices volume. From what I have researched, that seems to be the only way to set the devices volume programmatically. If there is another way, please suggest it.
So, when I launch my app I save the system volume as an external variable 'appStartVol' in my AppDelegate.m.
I let the user change the volume during app usage with MPVolumeView.
Then I try to set the system volume back to the appStartVol in the AppDelegate.m files' applicationWillTerminate. EDIT: applicationWillTerminate is called when a user dismisses apps from their recents list. I do this all the time and leave regularly used apps in recents so I don't have to scroll through 9 pages of icons to find them. So, there is a reason to do what I am asking, in that function.
I use this approach for screen brightness but can not seem to do it for volume.
I am having trouble because I do not seem to be able to get access to my storyboard MPVolumeView in AppDelegate.m applicationWillTerminate and I can not seem to make a local MPVolumeView work in AppDelegate.m applicationWillTerminate.
If I use a UIApplicationWillTerminateNotification notification in my view controller, I still run into the same problems in the notification event since the storyboard MPVolumeView also seems not accessible from that event.
EDIT: This is the reason that using code in applicationDidEnterBackground does not meet my needs: I want my users to be able to use my music player at the volume they have manually chosen in my app even when they decide to bring another app into focus. I believe that this is what the users would naturally assume would happen. For instance, why would the volume change if I want to use the calculator? I also want to believe that the natural assumption for a user would be that the volume should pop back to pre-app volume if the app is dismissed. Using applicationDidEnterBackground would make the app go to pre-app volume both when the app goes into background AND when it terminates, this is not acceptable.
ATTEMPT 1: Here is my code in my AppDelegate.m applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(@"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(@"=== Screen brightness back to pre-app level of %f ===", brightnessORG);
UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)view;
volumeViewSlider.value = appStartVol;
break;
}
}
}
ATTEMPT 1: Here is my AppDelegate.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
extern CGFloat brightnessORG;
extern float appStartVol;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
MPVolumeView *_mpVolumeViewParentView;
}
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, retain) IBOutlet MPVolumeView *mpVolumeViewParentView;
@end
Re. ATTEMPT 1: Although this code runs without error, it does not set the volume back to appStartVol since there are no views in the app delegates [_mpVolumeViewParentView subviews]. I am obviously not accessing the mpVolumeViewParentView that is in my storyboard.
ATTEMPT 2: Lets see if I can just add a local MPVolumeView in AppDelegate.m applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(@"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(@"=== Screen brightness back to pre-app level of %f ===", brightnessORG);
MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
UISlider *volumeViewSlider;
volumeViewSlider = (UISlider*)volumeView;
volumeViewSlider.value = appStartVol;
}
Re. ATTEMPT 2: Runs with error = 'Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MPVolumeView setValue:]: unrecognized selector sent to instance'
But I have tried :), as you can see I am an objective-c newbie...
Any help would be appreciated :)
ATTEMPT 3: Try subviews in local MPVolumeView in applicationWillTerminate:
MPVolumeView *_mpVolumeViewParentView = [ [MPVolumeView alloc] init];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
[_mpVolumeViewParentView addSubview:volumeView];
UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)volumeView;
volumeViewSlider.value = appStartVol;
break;
}
}
Re. ATTEMPT 3: Runs with error at for loop initiation: 'Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MPVolumeView setValue:]: unrecognized selector sent to instance'
ATTEMPT 4: After adding AVfoundation framework to the project, I added this to my AppDelegate.m:
#import <AVFoundation/AVFoundation.h>
And I put these two lines to AppDelegate.m applicationWillTerminate:
AVAudioPlayer* wavplayer = [[AVAudioPlayer alloc] init];
wavplayer.volume = appStartVol;
Re. ATTEMPT 4: Runs with error at 'wavplayer.volume= appStartVol;': 'Thread 1: EXC_BAD_ACCESS (code=1, address=0x48)' , darn......