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

发布于 2024-12-19 20:59:45 字数 644 浏览 2 评论 0原文

我想用iOS5的原生相机实现相同的行为:

  • 按音量+按钮拍照

理想的存档方式是什么? 有没有办法捕获音量键按下事件

?搜索了几个小时,我找到了 1 个解决方案:使用 NSNotificationCenter

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

但是,它有 2 个问题:

  • 每次按音量键时都会显示“当前系统音量”的半透明覆盖层,这不是我想要的。
  • 对于原生相机来说,当按音量键作为快门时,系统音量不会改变,但是使用上述方法,系统音量会改变。

I want to implement the same behavior with the native camera of 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 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

稚然 2024-12-26 20:59:45

我自己找到了另一种方法来隐藏“系统音量覆盖”和“按下音量键时绕过系统音量变化”。

不好的部分:这是一个超级丑陋的黑客行为。

但是,好的部分是:这个丑陋的黑客不使用私有API。

另一个注意事项是:它仅适用于ios5+(无论如何,对于我的问题,因为AVSystemController_SystemVolumeDidChangeNotification仅适用于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:@"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个小时发现这个超级丑陋的方法...狗屎...草尼马啊!)

另一件事:
如果您采用上述技巧,则需要在应用程序激活时每次都运行代码。
因此,您可能需要将一些代码放入您的应用程序委托中。

- (void)applicationDidBecomeActive:(UIApplication *)application 

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.

However, the good part is: this ugly hack uses NO private APIs.

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.)

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... 草尼马啊!)

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.

- (void)applicationDidBecomeActive:(UIApplication *)application 
素染倾城色 2024-12-26 20:59:45

基于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];

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.

// 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];
鱼忆七猫命九 2024-12-26 20:59:45

……

[[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];   
}

[[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];   
}
七度光 2024-12-26 20:59:45

目前没有官方方法来捕获音量键按下事件。 Apple 的声明是,如果您允许音量按钮显示相机控件,则音量按钮可以与 UIImagePickerController 配合使用。

其他方法,例如监听通知,似乎是不受支持的黑客行为,苹果团队有时对此视而不见。为了防止出现音量 HUD,您可以使用未记录的 UIApplication 方法:

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

我见过的唯一使用说明是:

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

我不确定是否或为什么您似乎需要禁用 HUD特定类别,然后是一般类别,但如果没有适当的文档,很难弄清楚。

因此:如果您想遵守规则,请使用 UIImagePickerController 及其相机按钮。如果您发现某个应用程序似乎可以在规则之外运行,那么它可能正在使用上述方法。

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.

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:

- (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.

So: use UIImagePickerController and its camera buttons if you want to be within the rules. If you've found an app that seems to work outside of the rules then it's probably using the methods above.

∞琼窗梦回ˉ 2024-12-26 20:59:45

viewDidAppear 中调用此方法viewWillDisappear

-(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];
    }
}

我在调用中

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

I call this method from 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

[[AVAudioSession sharedInstance] setActive:NO error:nil];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文