Application

Mac OS X 与iOS 上的application 不太相同,在Mac OS X 上是NSApplication,在iOS 上则是UIApplication,但基本上都负责相同的工作:把来自外部的种种传递给内部,包括硬件事件,与其他各种系统事件。

硬件事件会被传递给window,而其他系统事件,像App被开启或关闭、被推到前景或背景、收到push notification…等等,则是会转发给application 的delegate。

由于application 位在responder chain 的最底层,每一个view 与window 都不处理的时候,才会丢给application 处理,所以如果我们希望处理一些会影响整个App 行为的事件的时候,就适合由application 这一层处理。

比方说,KKBOX是一个音乐App,所以我们会希望用户可以透过蓝芽耳机或线控耳机上的按钮,切换KKBOX当中的歌曲,换到前一首或下一首歌曲。在iOS 7.1之前,我们要处理线控耳机的事件,会选择实现UIResponder protocol中的-remoteControlReceivedWithEvent:。因为换歌这件事情应该是对整个KKBOX的操作,无论放在哪个view或view controller都不适合,所以应该要放在application这一层。

要让application 这一层可以做额外的事情,我们首先要建立自己的UIApplication subclass:

@interface KKApplication : UIApplication
@end

然后,在main.m里头,告诉UIApplicationMain,我们应该要使用KKApplication,而不是原本的UIApplication的实现:

int main(int argc, char * argv[]) {
    @autoreleasepool {
    return UIApplicationMain(argc, argv,
        NSStringFromClass([KKApplication class]),
      NSStringFromClass([AppDelegate class]));
    }
}

我们就可以在KKApplication 处理事件了:

@implementation KKApplication
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent
{
    if (theEvent.type == UIEventTypeRemoteControl) {
        switch(theEvent.subtype) {
            case UIEventSubtypeRemoteControlPlay:
                break;
            case UIEventSubtypeRemoteControlPause:
                break;
            case UIEventSubtypeRemoteControlStop:
                break;
            case UIEventSubtypeRemoteControlTogglePlayPause:
                break;
            case UIEventSubtypeRemoteControlNextTrack:
                break;
            case UIEventSubtypeRemoteControlPreviousTrack:
                break;
            ...
            default:
                return;
        }
    }
}
@end

当然,如果我们想要开始接收来自耳机的事件,我们还要对UIApplication的singleton实例调用-beginReceivingRemoteControlEvents:

虽然跟application 这一层无关,不过提到了耳机线控,就得提一下。苹果在推出iOS 7.1 的时候,同时推出了Car Play 功能,Car Play 允许用户在车用音响的介面上控制iOS App,由于车用音响的画面较大,所以,除了可以用来切换前后首歌曲之外,苹果还加入了可以对歌曲评分,表示喜欢或不喜欢等功能,于是整个改写了处理耳机线控的这一块,推出MPRemoteCommandCenter 这个class。

从MPRemoteCommandCenter的singleton实例sharedCommandCenter上,我们可以拿到许多种不同的MPRemoteCommand,然后对MPRemoteCommand设定target/action。我们之前想要开始播放,会在-remoteControlReceivedWithEvent:里头处理UIEventSubtypeRemoteControlPlay,现在会改成向MPRemoteCommandCenter要求playCommand,然后指定target/action,例如:

[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(play:)];

results matching ""

    No results matching ""