¿Hay alguna forma pública de obligar a MPNowPlayingInfoCenter a mostrar controles de podcast?

Me gustaría que el Centro de control (a través de MPNowPlayingInfoCenter) muestre los controles de 15 segundos hacia adelante / atrás de 15 segundos que Apple muestra con los podcasts, de esta manera:

controles de podcast

La total falta de documentación me dice que no hay una forma obvia de hacerlo, pero ¿alguien por ahí ha encontrado alguna forma no obvia de forzar esto sin recurrir a un método privado?

Ya tengo mi manejo para que el botón de avance / retroceso se configure correctamente para avanzar, solo me gustaría utilizar la IU más adecuada. Cualquier ayuda sería muy apreciada.

OK, así que tuve un poco de tiempo en mis manos, así que seguí el rastro de pan … Esto es lo que encontré.

Incluye el marco MediaPlayer y obtén el RemoteCommandCenter:

MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter]; 

luego, si desea establecer los controles de omisión según Overcast, puede hacer lo siguiente:

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

y en caso de que los manejadores hagan lo que deben hacer para saltear el intervalo:

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

Nota: La propiedad IntervaloPreferida es una NSArray pero no he descubierto cómo el centro de comando puede utilizar intervalos adicionales a menos que haga algo con esto usted mismo.

Cosas para notar que he encontrado hasta ahora. Cuando haces esto, estás tomando el control de todos los controles, por lo que los botones de reproducción y pausa predeterminados no se mostrarán a menos que hagas lo mismo con ellos:

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

(También hay un togglePlayPauseCommand definido, pero no pude hacer que disparara desde el Command Center, aunque sí dispara desde los auriculares).

Otros descubrimientos: los botones están en posiciones fijas izquierda / centro / derecha, por lo que no puede tener (por ejemplo) un seguimiento anterior y un salto adelante ya que ambos ocupan la posición izquierda.

Hay comandos seekForward / seekBackward que necesitan un comando prevTrack y nextTrack para ser activados. Cuando configura ambos, un solo toque activa los siguientes / previos y mantener presionado dispara una búsqueda de inicio y una búsqueda final cuando levanta el dedo.

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

También hay un mecanismo de retroalimentación que no he visto antes (ocupa la posición izquierda)

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

Esto muestra tres barras horizontales y muestra una hoja de alerta: puede resaltarlas individualmente configurando la propiedad activa.

También hay un comando de clasificación definido, pero no pude conseguir que se muestre en el Centro de Comando

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

y un comando de cambio de velocidad de reproducción, pero nuevamente no se pudo mostrar en Command Center

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

También hay un mecanismo de acción objective basado en bloques si lo prefiere

 // @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 último punto a tener en cuenta: si se ha registrado para recibir eventos remotos a través de [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; luego, algunos de estos comandos también desencadenan eventos en el controlador – (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent. Aunque son UIEvents con el tipo UIEventTypeRemoteControl y un subtipo para distinguir el evento. No puede mezclarlos ni combinarlos con MPRemoteCommandEvents en este método. Hay indicios de que MPRemoteCommandEvents reemplazará a los UIEvents en algún momento.

Todo esto basado en prueba y error, así que no dude en corregirlo.

Gareth

Captura de pantalla del comando de retroalimentación y skipforward

Oooooooh Marco Arment consiguió que esto funcione en Overcast, y al menos dejó un rastro de migas para los Castro con este tweet :

Es MPRemoteCommandCenter. Buena suerte con la documentación, sin embargo.

Aquí está dicha documentación para cualquiera que haya estado siguiendo esta pregunta: supongo que tiene que ver con skipBackwardCommand y skipForwardCommand . No tengo tiempo para analizarlo en este mismo momento, así que lo dejo aquí por si alguien quiere insistir y dar una respuesta más completa.

Para los desarrolladores de 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 } 

Otro comando sería similar y se pueden verificar aquí

Apple no tiene documentación porque no hay forma de cambiar esto. Una vez más, Apple se está guardando las mejores cosas para sí misma (Siri viene a la mente también).

La versión jailbroken admite el cambio de botones del Centro de control, que encontré en este sitio . Tengo la sensación de que desea utilizar esta aplicación en el iOS 7 actual , no una versión jailbreak, por lo que esto no ayuda en absoluto.

Estas API privadas obstaculizan el desarrollo de buenas aplicaciones con demasiada frecuencia. A menos que Apple nos dé más libertad para usar las API actualmente privadas, no tiene suerte.