简体   繁体   English

如何为iPhone实现音量键快门?

[英]How to implement a volume key shutter for iPhone?

I want to implement the same behavior with the native camera of iOS5 : 我想用iOS5的原生相机实现相同的行为:

  • press the volume + button to take a photo 按音量+按钮拍照

What's the ideal way to archive it? 归档它的理想方式是什么? Are there any ways to capture the volume key pressed event? 有没有办法捕捉音量键按下事件?

After googling & searching around for hours, I found 1 solution: using NSNotificationCenter : 谷歌搜索和搜索了几个小时后,我找到了一个解决方案:使用NSNotificationCenter

...
    [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(volumeChanged:)
         name:@"AVSystemController_SystemVolumeDidChangeNotification"
         object:nil];
...
- (void)volumeChanged:(NSNotification *)notification{
    [self takePhoto];   
}

However, it has 2 issues: 但是,它有两个问题:

  • There is an semi-transparent overlay of "current system volume" show up every time when pressing the volume key, this is not what I wanted. 每次按音量键时都会出现“当前系统音量”的半透明叠加,这不是我想要的。
  • For the native camera, when you press the volume key as shutter, the system volume won't change, however, by using the above method, the system volume will change. 对于本机相机,当您按下音量键作为快门时,系统音量不会改变,但是,使用上述方法,系统音量将会改变。

Building on huxia's code, this works on ios5+, no need to run the code every time it becomes active, just run it once in the beginning. 基于huxia的代码,这适用于ios5 +,无需在每次激活时运行代码,只需在开始时运行一次。

// these 4 lines of code tell the system that "this app needs to play sound/music"
AVAudioPlayer* p = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"photoshutter.wav"]] error:NULL];
[p prepareToPlay];
[p stop];

//make MPVolumeView Offscreen
CGRect frame = CGRectMake(-1000, -1000, 100, 100);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[volumeView sizeToFit];
[self.view addSubview:volumeView];

I've found another way to hide the "system volume overlay" and "bypass the system volume change when the volume key pressed" by myself. 我找到了另一种方法来隐藏“系统音量叠加”和“当按下音量键时绕过系统音量变化”。

The bad part: this is an super UGLY hack. 坏的部分:这是一个超级UGLY黑客。

However, the good part is: this ugly hack uses NO private APIs. 然而,好的部分是:这个丑陋的黑客使用NO私有API。

Another note is: it only works for ios5+ (anyway, for my issue, since the AVSystemController_SystemVolumeDidChangeNotification only works for ios5, so this UGLY hack just fits my issue.) 另一个注意事项是:它只适用于ios5 +(无论如何,对于我的问题,因为AVSystemController_SystemVolumeDidChangeNotification仅适用于ios5,所以这个UGLY黑客只适合我的问题。)

The way it work: "act as a music/movie player app and let the volume key to adjust the application-volume". 它的工作方式:“充当音乐/电影播放器​​应用程序并让音量键调整应用程序量”。

Code: 码:

// these 4 lines of code tell the system that "this app needs to play sound/music"
AVAudioPlayer* p = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"photo-shutter.wav"]] error:NULL];
[p prepareToPlay];
[p stop];
[p release];

// these 5 lines of code tell the system that "this window has an volume view inside it, so there is no need to show a system overlay"
[[self.view viewWithTag:54870149] removeFromSuperview];
MPVolumeView* vv = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];
[self.view addSubview:vv];
vv.tag = 54870149;
[vv release];

(5 hours spending on discovering this super ugly method... shit... 草尼马啊!) (5个小时花在发现这个超级丑陋的方法......狗屎......草尼马啊!)

Another thing: if you take the above hack, you need to run the code EVERY-TIME when your app become active. 另一件事:如果您采取上述攻击,则需要在应用程序变为活动状态时每隔一段时间运行代码。 So, you might need to put some code into your app delegate. 因此,您可能需要将一些代码放入您的app委托中。

- (void)applicationDidBecomeActive:(UIApplication *)application 

...

[[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(volumeChanged:)
     name:@"AVSystemController_SystemVolumeDidChangeNotification"
     object:nil];

...

- (void)volumeChanged:(NSNotification *)notification{ 

    CGRect frame = CGRectMake(-1000, -1000, 100, 100);
    MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
    [volumeView sizeToFit];
    [self.view addSubview:volumeView];
    [volumeView release];

    [self takePhoto];   
}

I call this method from viewDidAppear 我从viewDidAppear调用此方法

-(void) startTrackingVolume
{
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
    [[AVAudioSession sharedInstance] setActive:YES error:nil];

    if (!self.volumeView) {
        // put it somewhere outside the bounds of parent view
        self.volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 10, 0)];
        [self.volumeView sizeToFit];
    }

    if (!self.volumeView.superview) {
        [self.view addSubview:self.volumeView];
    }
}

In viewWillDisappear in call viewWillDisappear中调用

[[AVAudioSession sharedInstance] setActive:NO error:nil];

There's currently no official way to capture the volume key pressed event. 目前还没有正式的方法来捕获音量键按下事件。 Apple's stated line is that the volume button works with the UIImagePickerController if you've allowed it to show camera controls. 如果您允许它显示摄像机控件,那么Apple的声明就是音量按钮可以与UIImagePickerController使用。

Other approaches, such as listening for the notification, seem to be unsupported hacks that Apple's team are — anecdotally — sometimes turning a blind eye to. 其他方法,例如收听通知,似乎是苹果公司团队无法支持的黑客 - 有时候 - 有时候会对此视而不见。 To prevent the volume HUD from appearing you can use the undocumented UIApplication methods: 要防止出现卷HUD,可以使用未记录的UIApplication方法:

- (void)setSystemVolumeHUDEnabled:(BOOL)enabled;
- (void)setSystemVolumeHUDEnabled:(BOOL)enabled forAudioCategory:(NSString *)category;

The only statement of their use I've seen is: 我见过他们使用的唯一声明是:

UIApplication *app = [UIApplication sharedApplication];
[app setSystemVolumeHUDEnabled:NO forAudioCategory:@"Ringtone"];
[app setSystemVolumeHUDEnabled:NO];

I'm unsure if or why you seemingly need to disable the HUD for a specific category and then in general, but without proper documentation that's difficult to figure out. 我不确定你是否或为什么似乎需要为特定类别禁用HUD,然后一般情况下,但没有适当的文档很难弄明白。

So: use UIImagePickerController and its camera buttons if you want to be within the rules. 所以:如果你想要在规则范围内,请使用UIImagePickerController及其相机按钮。 If you've found an app that seems to work outside of the rules then it's probably using the methods above. 如果你发现一个似乎在规则之外工作的应用程序,那么它可能正在使用上面的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM