有公开的方法可以强制MPNowPlayingInfoCenter显示播客控件吗?

54

我希望通过MPNowPlayingInfoCenter控制中心显示向前15秒/向后15秒的控件,就像苹果在播客中展示的控件一样:

播客控件

缺乏文档让我觉得没有明显的方法可以做到这一点,但是有没有人发现过不使用私有方法来强制实现这一点的非明显方法?

我已经设置好了向前/向后按钮的处理程序以适当地前进,我只想使用更合适的UI。 任何帮助都将不胜感激。


控制中心似乎在大多数方面都是不可变的。不仅应用程序开发人员无法编辑它,即使用户也无法编辑控制中心中的按钮。苹果再次没有分享。 - erdekhayser
如果有方法可以做到这一点,我相信其他10个独立播客客户端已经实现了它。 - seanwolter
是的,我有点抱着侥幸心理。我会在雷达上提交这个问题。 - DesignatedNerd
嗨,请帮我 http://stackoverflow.com/questions/32564494/want-next-and-previous-button-in-my-ytplayerview-while-locked-iphone-ios - Jagveer Singh
5个回答

125

好的,我有点空闲时间,所以我跟随面包屑找到了以下内容:

包含MediaPlayer框架并获取RemoteCommandCenter:

MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];

如果您想像Overcast一样设置跳过控件,则可以执行以下操作:

MPSkipIntervalCommand *skipBackwardIntervalCommand = [rcc skipBackwardCommand];
[skipBackwardIntervalCommand setEnabled:YES];
[skipBackwardIntervalCommand addTarget:self action:@selector(skipBackwardEvent:)];
skipBackwardIntervalCommand.preferredIntervals = @[@(42)];  // Set your own interval

MPSkipIntervalCommand *skipForwardIntervalCommand = [rcc skipForwardCommand];
skipForwardIntervalCommand.preferredIntervals = @[@(42)];  // Max 99
[skipForwardIntervalCommand setEnabled:YES];
[skipForwardIntervalCommand addTarget:self action:@selector(skipForwardEvent:)];

在事件处理程序中,做你需要做的事情以跳过间隔:

-(void)skipBackwardEvent: (MPSkipIntervalCommandEvent *)skipEvent
{
    NSLog(@"Skip backward by %f", skipEvent.interval);
}

-(void)skipForwardEvent: (MPSkipIntervalCommandEvent *)skipEvent
{
    NSLog(@"Skip forward by %f", skipEvent.interval);
}

注意:preferredIntervals属性是NSArray类型,但我还没有弄清楚如何利用额外的间隔来控制中心,除非你自己处理。
需要注意的事项如下。当你这样做时,你将控制所有的控件,所以默认的播放和暂停按钮将不会显示,除非你也对它们进行相同的处理。
MPRemoteCommand *pauseCommand = [rcc pauseCommand];
[pauseCommand setEnabled:YES];
[pauseCommand addTarget:self action:@selector(playOrPauseEvent:)];
//    
MPRemoteCommand *playCommand = [rcc playCommand];
[playCommand setEnabled:YES];
[playCommand addTarget:self action:@selector(playOrPauseEvent:)];

还有一个togglePlayPauseCommand被定义了,但我无法从命令中心触发它 - 不过从耳机上可以触发。

其他发现: 按钮位置固定为左/中/右,因此您不能同时拥有(例如)previousTrack和skipBackward,因为它们都占据左侧位置。

有seekForward / seekBackward命令,需要触发prevTrack和nextTrack命令。当您设置两者时,单击触发下一个/上一个,长按触发开始搜索,松开手指后结束搜索。

    // Doesn’t show unless prevTrack is enabled
    MPRemoteCommand *seekBackwardCommand = [rcc seekBackwardCommand];
    [seekBackwardCommand setEnabled:YES];
    [seekBackwardCommand addTarget:self action:@selector(seekEvent:)];

    // Doesn’t show unless nextTrack is enabled
    MPRemoteCommand *seekForwardCommand = [rcc seekForwardCommand];
    [seekForwardCommand setEnabled:YES];
    [seekForwardCommand addTarget:self action:@selector(seekEvent:)];

-(void) seekEvent: (MPSeekCommandEvent *) seekEvent
{
    if (seekEvent.type == MPSeekCommandEventTypeBeginSeeking) {
        NSLog(@"Begin Seeking");
    }
    if (seekEvent.type == MPSeekCommandEventTypeEndSeeking) {
        NSLog(@"End Seeking");
    }
}

还有一个我以前没有见过的反馈机制(占据了左侧位置)

    MPFeedbackCommand *likeCommand = [rcc likeCommand];
    [likeCommand setEnabled:YES];
    [likeCommand setLocalizedTitle:@"I love it"];  // can leave this out for default
    [likeCommand addTarget:self action:@selector(likeEvent:)];

    MPFeedbackCommand *dislikeCommand = [rcc dislikeCommand];
    [dislikeCommand setEnabled:YES];
    [dislikeCommand setActive:YES];
    [dislikeCommand setLocalizedTitle:@"I hate it"]; // can leave this out for default
    [dislikeCommand addTarget:self action:@selector(dislikeEvent:)];

    BOOL userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat = YES;

    if (userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat) {
        [dislikeCommand setActive:YES];
    }

    MPFeedbackCommand *bookmarkCommand = [rcc bookmarkCommand];
    [bookmarkCommand setEnabled:YES];
    [bookmarkCommand addTarget:self action:@selector(bookmarkEvent:)];

// Feedback events also have a "negative" property but Command Center always returns not negative
-(void)dislikeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Mark the item disliked");
}

-(void)likeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Mark the item liked");
}

-(void)bookmarkEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Bookmark the item or playback position");
}

这会显示三个水平条,并弹出一个警告表单 - 通过设置活动属性,您可以逐个突出显示它们。

还定义了一个评分命令 - 但我无法在命令中心中显示它。

//    MPRatingCommand *ratingCommand = [rcc ratingCommand];
//    [ratingCommand setEnabled:YES];
//    [ratingCommand setMinimumRating:0.0];
//    [ratingCommand setMaximumRating:5.0];
//    [ratingCommand addTarget:self action:@selector(ratingEvent:)];

还有一个播放速度更改命令 - 但是我无法在命令中心中显示它。

//    MPChangePlaybackRateCommand *playBackRateCommand = [rcc changePlaybackRateCommand];
//    [playBackRateCommand setEnabled:YES];
//    [playBackRateCommand setSupportedPlaybackRates:@[@(1),@(1.5),@(2)]];
//    [playBackRateCommand addTarget:self action:@selector(remoteControlReceivedWithEvent:)];

如果您喜欢,还有一种基于块的目标操作机制。
// @property (strong, nonatomic) id likeHandler;
    self.likeHandler = [likeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent *event) {
        NSLog(@"They like it");
        return MPRemoteCommandHandlerStatusSuccess;  // or fail or no such content
    }];

请注意一点:如果您已经通过[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];注册接收远程事件,则某些命令也会触发-(void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent处理程序中的事件。这些是UIEvents,但具有用于区分事件的UIEventTypeRemoteControl和子类型。在此方法中,您不能混合使用MPRemoteCommandEvents。有迹象表明MPRemoteCommandEvents将在某个时候取代UIEvents。
所有这些都基于试错,所以请随时纠正。
Gareth feedback command和skipforward的截图

2
非常感谢您提供如此详细的答案! - DesignatedNerd
5
请注意,MPRemoteCommandCenter 是在 iOS 7.1 中添加的,这可能解释了为什么没有人在使用它! - pkamb
嗨,兄弟,你能帮我解决我的问题吗? - Jagveer Singh
http://stackoverflow.com/questions/32564494/want-next-and-previous-button-in-my-ytplayerview-while-locked-iphone-ios - Jagveer Singh
谢谢你提供完整详细的答案,对我帮助很大。但是我还需要一个小小的帮助来完成我的应用程序。请问是否可以更改反馈alertView的取消按钮标题和它们显示的图标? - Niloufar
显示剩余7条评论

12

面向Swift开发者

import MediaPlayer

let rcc = MPRemoteCommandCenter.shared()

let skipBackwardCommand = rcc.skipBackwardCommand
skipBackwardCommand.isEnabled = true
skipBackwardCommand.addTarget(handler: skipBackward)
skipBackwardCommand.preferredIntervals = [42]

let skipForwardCommand = rcc.skipForwardCommand
skipForwardCommand.isEnabled = true
skipForwardCommand.addTarget(handler: skipForward)
skipForwardCommand.preferredIntervals = [42]

func skipBackward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
    guard let command = event.command as? MPSkipIntervalCommand else {
        return .noSuchContent
    }

    let interval = command.preferredIntervals[0]

    print(interval) //Output: 42

    return .success
}

func skipForward(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
    guard let command = event.command as? MPSkipIntervalCommand else {
        return .noSuchContent
    }

    let interval = command.preferredIntervals[0]

    print(interval) //Output: 42

    return .success
}

其他的命令类似,可以在这里进行查看。


3

哦。Marco Arment在Overcast中使这个工作,并且至少留下了一个面包屑给Castro的人们,通过这条推文:

它是MPRemoteCommandCenter。不过祝你好运,因为文档很难懂。

这里是相关文档,供一直关注这个问题的人参考-我猜这与skipBackwardCommandskipForwardCommand有关。我现在没时间去看了,所以我会把这个留在这里,以防有人想要研究并给出更彻底的答案。


这可能有助于解决代码示例:https://developer.apple.com/library/ios/documentation/MediaPlayer/Reference/MPSkipIntervalCommand_Ref/Reference/Reference.html#//apple_ref/occ/cl/MPSkipIntervalCommand - erdekhayser

2

由于无法更改,因此苹果没有文档。同样,苹果保留最好的东西(例如Siri)。

越狱版支持更改控制中心按钮,我在这个网站上找到了它。我有一种感觉,你想在实际的iOS 7上使用这个应用而不是越狱版,所以这对你没有帮助。

这些私有API经常妨碍开发优秀的应用程序。除非苹果给我们更多使用当前私有API的自由,否则你很遗憾。


3
遗憾的是,对于7.x版本来说,这是正确的答案。如果您和我一样感到不满,请提交一个radar(反馈),要求获得此功能的访问权限。可能只是在井底呼喊,但他们偶尔会阅读它们。https://bugreport.apple.com/ - DesignatedNerd
1
@DesignatedNerd 雷达已提交。 - erdekhayser

1
除了其他回答之外,我发现如果我没有在MPNowPlayingInfoCenter上设置nowPlayingInfo,则跳过按钮不会出现,但默认的nextTrack和PreviousTrack按钮会出现。(出现纯快进和倒带按钮) 确保你在某个时刻设置了MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo,像下面这样:
 var songInfo: NSMutableDictionary = [
        MPMediaItemPropertyTitle: "song title",
        MPMediaItemPropertyArtist: "artist ",
        MPNowPlayingInfoPropertyElapsedPlaybackTime: "0"
    ]
    MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo as [NSObject : AnyObject]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接