Есть ли публичный способ заставить MPNowPlayingInfoCenter показывать элементы управления подкаста?

Я хотел бы, чтобы Центр управления (через MPNowPlayingInfoCenter) отображал элементы управления 15 секунд назад / 15 секунд, которые Apple показывает с подкастами, например:

управление подкастом

Полное отсутствие документации говорит мне, что нет очевидного способа сделать это, но кто-нибудь там нашел какой-нибудь неочевидный способ заставить это, не прибегая к частному методу?

Я уже настроил обработку кнопки "вперед / назад", чтобы продвигаться соответствующим образом, я просто хотел бы использовать более подходящий пользовательский интерфейс. Любая помощь будет принята с благодарностью.

4 ответа

Решение

Хорошо, так что у меня было немного времени на руках, и поэтому я последовал за крошкой... Это то, что я нашел.

Включите среду 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);
}

Примечание. Свойство prefeIntervals является 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 *)receiveEvent. Это UIEvents, хотя с типом UIEventTypeRemoteControl и подтипом для различения события. Вы не можете смешивать и сопоставлять их с MPRemoteCommandEvents в этом методе. Есть подсказки, что MPRemoteCommandEvents заменит UIEvents в какой-то момент.

Все это основано на методах проб и ошибок, поэтому не стесняйтесь исправлять.

Gareth

Скриншот команды обратной связи и skipforward

Для разработчиков 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
}

Другая команда была бы аналогичной и их можно проверить здесь

Oooooooh. Марко Армент заставил это поработать в Overcast и, по крайней мере, оставил для ребят из Кастро след в виде крошки:

Это MPRemoteCommandCenter. Удачи с документацией, хотя.

Вот упомянутая документация для тех, кто следит за этим вопросом - я предполагаю, что это связано с skipBackwardCommand а также skipForwardCommand, У меня нет времени, чтобы изучить это в эту самую секунду, поэтому я оставлю это здесь на случай, если кто-то захочет ткнуть в это и дать более подробный ответ.

У Apple нет документации, потому что нет способа это изменить. Опять же, Apple хранит лучшие вещи при себе (Siri также приходит на ум).

Версия с джейлбрейком поддерживает изменение кнопок Центра управления, которые я нашел на этом сайте. У меня такое ощущение, что вы хотите использовать это приложение на реальной iOS 7, а не на джейлбрейкнутой версии, так что это вам совсем не поможет.

Эти частные API слишком часто мешают разрабатывать хорошие приложения. Если Apple не предоставит нам больше свободы в использовании в настоящее время частных API, вам не повезло.

В дополнение к другим ответам я обнаружил, что если я не установил nowPlayingInfo в MPNowPlayingInfoCenter, то кнопки пропуска не появлялись, но появлялись кнопки nextTrack и PreviousTrack по умолчанию. (появляются простые кнопки быстрой перемотки вперед и назад) Убедитесь, что вы устанавливаете MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo в какой-то момент, как показано ниже:

 var songInfo: NSMutableDictionary = [
        MPMediaItemPropertyTitle: "song title",
        MPMediaItemPropertyArtist: "artist ",
        MPNowPlayingInfoPropertyElapsedPlaybackTime: "0"
    ]
    MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo as [NSObject : AnyObject]
Другие вопросы по тегам