web-dev-qa-db-fra.com

Existe-t-il un moyen public de forcer MPNowPlayingInfoCenter à afficher les contrôles de podcast?

Je voudrais que Control Center (via MPNowPlayingInfoCenter) affiche les commandes avant 15 secondes/arrière 15 secondes que Apple affiche avec des podcasts, comme ceci:

podcast controls

Le manque total de documentation me dit qu'il n'y a pas de moyen évident de le faire, mais quelqu'un a-t-il trouvé un moyen non évident de forcer cela sans recourir à une méthode privée?

J'ai déjà ma manipulation pour le bouton avant/arrière configuré pour avancer correctement, je voudrais juste utiliser l'interface utilisateur la plus appropriée. Toute aide serait grandement appréciée.

50
DesignatedNerd

Bon alors j'ai eu un peu de temps sur les mains et j'ai donc suivi le fil d'Ariane… C'est ce que j'ai trouvé.

Incluez le framework MediaPlayer et mettez la main sur RemoteCommandCenter:

MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];

si vous souhaitez définir les commandes de saut selon Overcast, vous pouvez effectuer les opérations suivantes:

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:)];

et dans le cas où les gestionnaires d'événements feraient ce que vous devez faire pour ignorer l'intervalle:

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

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

Remarque: La propriété PreferredIntervals est un NSArray, mais je n'ai pas compris comment des intervalles supplémentaires peuvent être utilisés par le centre de commande, sauf si vous faites quelque chose avec cela vous-même.

Choses à noter que j'ai trouvé jusqu'à présent. Lorsque vous faites cela, vous prenez le contrôle de toutes les commandes afin que les boutons de lecture et de pause par défaut ne s'affichent que si vous faites de même pour eux:

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:)];

(Il y a également un togglePlayPauseCommand défini mais je ne pouvais pas obtenir cela à partir du Command Center - il se déclenche cependant à partir d'un casque.)

Autres découvertes: les boutons sont dans des positions fixes à gauche/au milieu/à droite, vous ne pouvez donc pas avoir (par exemple) un previousTrack et un skipBackward car ils occupent tous deux la position de gauche.

Il existe des commandes de recherche de recherche/recherche de retour qui nécessitent le déclenchement d'une commande prevTrack et nextTrack. Lorsque vous configurez les deux, un seul appui déclenche le suivant/précédent et un appui prolongé déclenche une recherche de début et une recherche de fin lorsque vous soulevez votre doigt.

    // 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");
    }
}

Il y a aussi un mécanisme de rétroaction que je n'avais jamais vu auparavant (occupe la position gauche)

    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");
}

Cela affiche trois barres horizontales et affiche une feuille d'alerte - vous pouvez les mettre en évidence individuellement en définissant la propriété active.

Il y a aussi une commande de classement définie - mais je n'ai pas pu faire apparaître cela dans le Command Center

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

et une commande de changement de taux de lecture - mais encore une fois, cela ne pouvait pas être affiché dans Command Center

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

Il existe également un mécanisme d'action cible basé sur des blocs si vous préférez

// @property (strong, nonatomic) id likeHandler;
    self.likeHandler = [likeCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent *event) {
        NSLog(@"They like it");
        return MPRemoteCommandHandlerStatusSuccess;  // or fail or no such content
    }];

Un dernier point à savoir: si vous vous êtes inscrit pour recevoir des événements distants via [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; certaines de ces commandes déclenchent également des événements dans le gestionnaire - (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent. Ce sont des UIEvents avec le type UIEventTypeRemoteControl et un sous-type pour distinguer l'événement. Vous ne pouvez pas les mélanger et les faire correspondre avec MPRemoteCommandEvents dans cette méthode. Il existe des indications que MPRemoteCommandEvents remplacera les UIEvents à un moment donné.

Tout cela basé sur des essais et des erreurs, alors n'hésitez pas à corriger.

Gareth

Screenshot of feedback command and skipforward

116
Gareth

Pour développeurs 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
}

Une autre commande serait similaire et peut être vérifiée ici

7
zombie

Oooooooh. Marco Arment l'a fait fonctionner dans Overcast, et a au moins laissé un fil d'Ariane pour les gars de Castro avec ce Tweet :

Il s'agit de MPRemoteCommandCenter. Bonne chance avec la documentation.

Voici cette documentation pour tous ceux qui suivent cette question - je suppose que cela a à voir avec skipBackwardCommand et skipForwardCommand. Je n'ai pas le temps de l'examiner tout de suite, alors je vais laisser cela ici au cas où quelqu'un voudrait le pousser et donner une réponse plus approfondie.

3
DesignatedNerd

Apple n'a pas de documentation car il n'y a aucun moyen de changer cela. Encore une fois, Apple conserve les meilleures choses pour lui-même (Siri me vient aussi à l'esprit).

La version jailbreakée prend en charge la modification des boutons du Control Center, que j'ai trouvé sur ce site . J'ai le sentiment que vous souhaitez utiliser cette application sur le réel iOS 7, pas une version jailbreakée, donc cela ne vous aide pas du tout.

Ces API privées gênent trop souvent le développement de bonnes applications. À moins que Apple nous donne plus de liberté pour utiliser les API actuellement privées, vous n'avez pas de chance.

2
erdekhayser

En plus des autres réponses, j'ai trouvé que si je n'avais pas défini nowPlayingInfo sur MPNowPlayingInfoCenter, les boutons de saut n'apparaissaient pas, mais les boutons par défaut nextTrack et PreviousTrack sont apparus. (Avance rapide et rembobinage des boutons apparaissant) Assurez-vous de définir MPNowPlayingInfoCenter.defaultCenter (). nowPlayingInfo à un moment comme ci-dessous:

 var songInfo: NSMutableDictionary = [
        MPMediaItemPropertyTitle: "song title",
        MPMediaItemPropertyArtist: "artist ",
        MPNowPlayingInfoPropertyElapsedPlaybackTime: "0"
    ]
    MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo as [NSObject : AnyObject]
0
grizzb