Guía de integración del SDK de AppleTV
En esta guía de integración se explica cómo integrar el SDK de AppleTV de Xandr en la aplicación AppleTV, de modo que pueda usar la inserción de anuncios del lado cliente de Xandr para pujar, realizar un seguimiento y medir la publicidad de vídeo del lado cliente dentro de la aplicación. En las instrucciones y ejemplos se da por supuesto lo siguiente:
- Está desarrollando en Apple tvOS 12.0 o superior.
- Tiene instancias existentes de AVPlayer y controlador AVPlayerView en el entorno de desarrollo.
- Está usando las bibliotecas de código de Swift en Swift Core Libraries: Foundation. La versión mínima es SWIFT 4.2.
- Usa Xcode v10.0 o superior.
Esta aplicación admite los /ptv
puntos de conexión y /vmap
.
En las secciones siguientes se explican los pasos necesarios para completar la integración, se proporciona una referencia a las opciones de personalización, se sugieren procedimientos recomendados y se realizan recomendaciones para los desarrolladores que prefieren usar Objective-C.
Configuración de la integración
1. Configurar e importar CocoaPods
CocoaPods se usa para distribuir el SDK de Xandr e integrarlo en la aplicación. Use los vínculos siguientes para instalar CocoaPods y agregarlo al proyecto.
Puede usar el código siguiente en el archivo de especificación de pod:
Podfile de ejemplo:
target 'MyApp' do
pod 'AppNexusTVOSSDK', '~> 2.0.0'
end
2. Importar el módulo de AppleTV SDK
Xandr en UIViewController
Use los siguientes comandos:
import ANTVSDK
import AVKit //standard Audio Video Kit library
3. Agregar el AdControllerProtocol
protocolo a UIViewController
Use los siguientes comandos:
class VMAPViewController: UIViewController, AdControllerProtocol {
4. Hacer que las instancias de AVPlayerViewController
y AVPlayer
estén disponibles
Use los siguientes comandos:
let appContentVideoPlayer:AVPlayer? = AVPlayer(url: URL(string: "<URL to your content video>")!)
let appContentViewController:AVPlayerViewController? = AVPlayerViewController()
5. Create una instancia de AdController
El objeto adController debe tener como ámbito UIControllerVIew. Use el siguiente comando:
let adController = AdController()
6. (Opcional) Definir el objeto AdSlot
Proporcionamos el objeto AdSlot como parámetro para la comunicación entre la aplicación y el SDK. AdSlot representa un salto de anuncio (o "pod de anuncio") que contiene varios objetos VAST. Como puede ver en el ejemplo, la matriz VastData admite varios anuncios en un solo salto.
El método de "configuración" inicial devolverá Array<AdSlot>
que representa los saltos de anuncios de VMAP.
@objc public class AdSlot: NSObject, Codable {
public let breakId: String?;
public var timeOffset: String?;
public let breakType: String?;
public let vastDatas: Array<VastData>;
public let currentAdId: String?;
public let timeToShowAdBreak: Int?;
}
7. Implementar el método delegado necesario adPlaybackControllerDidSetup
Use este método delegado en UIViewController para tener en cuenta los anuncios de pre-inscripción antes de la reproducción de contenido.
func adPlaybackControllerDidSetup(adSlots: Array<AdSlot>?) {
if (adSlots == nil) {
/// fatal SDK error, start playback of your app content video here
} else {AdControllerProtocol
/// SDK called ad URL and got a response from the server and all internal properties are being set and ready to go
adController.play();//send play() signal to SDK
}
}
8. Implementar el método delegado necesario adPlaybackControllerShouldStartAd
Este método delegado debe implementarse en UIViewController para notificar al SDK que está listo para la reproducción de anuncios de vídeo. Cuando el SDK determine que es el momento de mostrar un anuncio de vídeo, pausará el vídeo de contenido e invocará este método con un único objeto "AdSlot". A continuación, la aplicación del publicador puede implementar cualquier comportamiento específico del anuncio. Tenga en cuenta que esta función debe devolver true
. Si devuelve false
, no se mostrará el anuncio.
func adPlaybackControllerShouldStartAd(adSlot: AdSlot?) -> Bool {
return true // if publisher application allows SDK to play video ad for the "adSlot"
}
9. Implementación del método delegado necesario adPlaybackControllerDidNotifyAdSlotEnded
Este método delegado debe implementarse en UIViewController para que el SDK pueda notificar al programa que la ranura del anuncio de vídeo ha terminado de reproducir todas las creatividades de anuncios. Cuando se llama a este delegado, el SDK reanudará la reproducción del vídeo de contenido.
func adPlaybackControllerDidNotifyAdSlotEnded(adSlot: AdSlot?) {
//do publisher application's internal work here
}
10. Implementar métodos delegados adicionales
Es necesario implementar estos métodos delegados. Sin embargo, pueden seguir siendo funciones auxiliares.
/// a delegate when sdk raised an error
///
/// - Parameters:
/// - adSlot: AdSlot where error occurred
/// - result: ANTVErrorProrotocol
/// - Returns: void
func adPlaybackControllerDidRaiseAnError(adSlot: AdSlot?, result: ANTVErrorProtocol?) {
//do stuff on publisher application when SDK reports an error
}
/// A delegate SDK triggered a event
///
/// - Parameters:
/// - adSlot: AdSlot where event triggered
/// - result: any object
/// - Returns: void
func adPlaybackControllerDidNotifyAdSlotEnded(adSlot: AdSlot?) {
//do stuff on publisher application when SDK notifies an event
}
Métodos de implementación
Llamar a setup()
Invoque el setup()
método para inicializar el SDK y solicitar un anuncio. Cuando el SDK esté listo, invocará el adPlaybackControllerDidSetup
método delegado. Tenga en cuenta que pasar contentVideoPlayerViewController
y contentVideoPlayer,
contentUIViewController
permite al SDK detener la reproducción de vídeo de contenido cuando es el momento de mostrar un salto de anuncios, así como mostrar marcas de interrupción de anuncios en la escala de tiempo del vídeo de contenido.
Nota:
Para inicializar el SDK de Apple TV, contentVideoPlayer
debe tener recursos de vídeo en el momento setup()
en que se llama a .
En los ejemplos siguientes se muestra cómo invocar la configuración para VMAP, para un conjunto de selección de ubicación Xandr, para una dirección URL VAST y para la ubicación de Xandr VAST.
// VMAP URL
adController.setup(vmapURL:String, contentVideoPlayerViewController: AVPlayerViewController, contentVideoPlayer: AVPlayer, contentUIViewController: UIViewController, delegate: AdControllerProtocol)
// Xandr Placement Set Id
adController.setup(appNexusPsetId: Int, contentVideoPlayerViewController: AVPlayerViewController?, contentVideoPlayer: AVPlayer?, contentUIViewController: UIViewController?, delegate: AdControllerProtocol)
// VAST URL
adController.setup(vastUrl: String, contentVideoPlayerViewController: AVPlayerViewController?, contentVideoPlayer: AVPlayer?, contentUIViewController: UIViewController?,delegate: AdControllerProtocol)
// Xandr VAST Placement ID
adController.setup(appNexusMemberId: Int, appNexusPlacementId: Int, contentVideoPlayerViewController: AVPlayerViewController?, contentVideoPlayer: AVPlayer?, contentUIViewController: UIViewController?,delegate: AdControllerProtocol
Pausar o reanudar el anuncio
Invoque pauseAd()/resumeAd()
para controlar el anuncio de vídeo. getPauseStatus()
devolverá el estado de pausa actual del anuncio.
adController.pauseAd() //pause video ad
adController.resumeAd() //resume video ad
adController.getPauseStatus() //true if video ad paused, false otherwise
Omitir anuncio
Para representar un botón omitir, implemente el adPlaybackControllerDidNotifyAnEvent()
método delegado. La lógica del SDK agrega un destino para controlar UIControlEvents.primaryActionTriggered
que llamará a una API skip()
. Esto VideoEvent.timeToShowSkip
confía en el atributo VAST skipoffset
.
func adPlaybackControllerDidNotifyAnEvent(adSlot: AdSlot?, event: VideoEvent?, data: String?) {
if (event == VideoEvent.timeToShowSkip) {
//render skip button
button.frame = CGRect(x: 0, y: 0, width: 450, height: 100)
button.setTitle("Click to Skip", for: .normal)
button.addTarget(self, action: #selector(self.skipClicked), for: .primaryActionTriggered)
self.view.addSubview(button)
//update focus engine to let user click a button
self.setNeedsFocusUpdate()
self.updateFocusIfNeeded()
}
}
@objc func skipClicked() {
self.adController.skip() //SDK skip call
//remove target and button
self.button.removeTarget(nil, action: nil, for: .allEvents)
self.button.removeFromSuperview()
}
Personalización del comportamiento del SDK
Puedes usar el setOptions()
método para especificar cómo quieres que se vea el SDK, qué texto quieres mostrar con anuncios, si el anuncio de vídeo muestra un botón omitir y otras características. Tenga en cuenta que setOptions()
debe invocarse antes de setup()
.
Todas estas opciones son opcionales. En el ejemplo siguiente se muestra cómo establecerlos:
adController.setOptions(
widthOfAdIndicator: 100,
leftMarginOfAdIndicator: 200,
bottomMarginOfAdIndicator: 300,
backgroundColor: UIColor.black,
heightOfAdIndicator: 400,
fontColor: UIColor.blue,
alphaOfAdIndicator: 0.5,
widthOfAdCountdown: 500,
heightOfAdCountdown: 600,
adText: "advertisement",
isSkippable: true);
...
Referencia del parámetro setOptions()
Parámetro | Tipo de datos | Description |
---|---|---|
adText |
String?=nil |
Texto del indicador de anuncio (por ejemplo Ad , ) |
alphaOfAdIndicator |
Double?=nil |
Valor del canal alfa (transparencia) del indicador de anuncio. - 1.0=no transparente - 0,5=50% transparente - 0=completamente transparente (y, por lo tanto, invisible) |
backgroundColor |
UIColor?=nil |
Color de fondo del indicador de anuncio. |
bottomMarginOfAdIndicator |
Int?=nil |
Alto del margen inferior del indicador de anuncio en píxeles. |
disableSelectGestureOverride |
Bool?=nil |
Si la aplicación del publicador, no Xandr, debe controlar la acción de gesto del trackpad remoto. Para permitir que Xandr invalide el gesto normal y habilite una acción de omisión, establezca este parámetro en false . Por ejemplo, true. |
fontColor |
UIColor?=nil |
Color de fuente del indicador de anuncio. |
heightOfAdCountdown |
Int?=nil |
Alto de la cuenta atrás del anuncio en píxeles. |
heightOfAdIndicator |
Int?=nil |
Alto del indicador de anuncio en píxeles. |
isSkippable |
Bool?=nil |
Si se muestra un botón omitir, lo que permite al visor omitir el anuncio. Por ejemplo, true. |
leftMarginOfAdIndicator |
Int?=nil |
Ancho del margen izquierdo del indicador de anuncio en píxeles. |
widthOfAdCountdown |
Int?=nil |
Ancho de la cuenta atrás del anuncio en píxeles. La cuenta atrás del anuncio es el área que muestra el número de segundos para los que se reproduce el anuncio. Si el anuncio se puede omitir, muestra el número de segundos hasta que el visor puede hacer clic en el botón omitir. |
widthOfAdIndicator |
Int?=nil |
Ancho del indicador de anuncio en píxeles. El indicador de anuncio es la sección del anuncio que indica que es publicidad y no contenido solicitado. |
Código de ejemplo para UIViewController
En este ejemplo se usa Swift.
import Foundation
import ANTVSDK
import AVKit
import os
class DevViewController: UIViewController, AdControllerProtocol {
static let contentURL: String = "<your content video url>"
let adController = AdController()
let appContentVideoPlayer:AVPlayer? = AVPlayer(url: URL(string: contentURL)!)
let appContentViewController:AVPlayerViewController? = AVPlayerViewController()
let button = UIButton.init(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
self.initANTVSDK()
}
deinit {
adController.dismiss() //dismiss all objects created on ANTVSDK
}
func initANTVSDK() -> Void {
//setup options
adController.setOptions(isSkippable: true, disableSelectGestureOverride: true)
adController.setup(vmapURL: "<your vmap url>", contentVideoPlayerViewController: appContentViewController!, contentVideoPlayer: appContentVideoPlayer!, contentUIViewController: self, delegate: self)
}
func adPlaybackControllerDidSetup(adSlots: Array<AdSlot>?) {
adController.play()
}
func adPlaybackControllerShouldStartAd(adSlot: AdSlot?) -> Bool {
return true;
}
@objc func skipClicked() {
self.adController.skip()
//remove target and button
self.button.removeTarget(nil, action: nil, for: .allEvents)
self.button.removeFromSuperview()
}
func adPlaybackControllerDidNotifyAdSlotEnded(adSlot: AdSlot?) {
Logger.debug("got adPlaybackControllerDidNotifyAdSlotEnded")
exit(0)
}
func adPlaybackControllerDidRaiseAnError(adSlot: AdSlot?, result: ANTVErrorProtocol?) {
Logger.error("got error from SDK: %@", (result?.description)!)
}
func adPlaybackControllerDidNotifyAnEvent(adSlot: AdSlot?, event: VideoEvent?, data: String?) {
if (event == VideoEvent.timeToShowSkip) {
//render skip button
button.frame = CGRect(x: 0, y: 0, width: 450, height: 100)
button.setTitle("Click to Skip", for: .normal)
button.addTarget(self, action: #selector(self.skipClicked), for: .primaryActionTriggered)
self.view.addSubview(button)
//update focus engine to let user click a button
self.setNeedsFocusUpdate()
self.updateFocusIfNeeded()
}
}
}
Sugerencias y procedimientos recomendados
Use los siguientes procedimientos recomendados al implementar el SDK en la aplicación.
Actualización del correlacionador DFP
Cuando se llama a una etiqueta DFP con ANTVSDK, el correlacionador garantiza que el publicador recibe una respuesta adecuada del servidor DFP. Asegúrese de cambiar el parámetro en la correlator
etiqueta cada vez que realice esta llamada, como se muestra en el ejemplo siguiente:
https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator={unique random number}
Permitir que el SDK inicie el vídeo de contenido
La aplicación no debe iniciar el vídeo de contenido por sí mismo. Debe esperar hasta que el SDK haya cargado anuncios y, posiblemente, muestre un anuncio previo a la publicación. La implementación adPlaybackControllerDidSetup
garantiza que el SDK inicia el vídeo de contenido. Al usar este método, los anuncios de pre-inscripción se mostrarán correctamente antes de que comience el vídeo de contenido de la aplicación.
Administración de memoria
tvOS ARC (Recuento automático de referencias) comprueba y limpia la mayoría de los objetos usados en ANTVSDK que no son necesarios en el momento en que se descarta UIViewController de la aplicación editora. Sin embargo, para admitir y garantizar la validez de ARC, es necesario llamar al adController.dismiss()
deinit
uiViewController de las aplicaciones del publicador (como se muestra en el ejemplo siguiente).
deinit {
adController.dismiss() //dismiss all objects created on ANTVSDK
}
Pruebas en modo no seguro
De forma predeterminada, Xcode no admite solicitudes HTTP no seguras. Algunas situaciones de depuración y pruebas en tiempo de desarrollo pueden requerir el uso de etiquetas HTTP no seguras. Para habilitar temporalmente el acceso completo al protocolo HTTP, compruebe la pestaña "Información del proyecto" para asegurarse de que el proyecto permite cargas arbitrarias.
Administración de versiones binarias de x86_64 y ARM64
Un marco "ANTVSDK.framework" incluye x86_64 y arm64 binario para admitir un emulador y un dispositivo Apple TV real. En caso de que no quiera incluir el binario x86_64 en la aplicación debido a las directrices de Apple AppStore, puede quitarlo simplemente mediante lipo
, como se muestra en el ejemplo siguiente:
cd ANTVSDK.framework
lipo -remove x86_64 ANTVSDK -o ANTVSDK
A continuación, puede comprobar si la biblioteca solo contiene el archivo binario ARM64:
<username>:ANTVSDK.framework $ file ANTVSDK
ANTVSDK: Mach-O universal binary with 1 architecture: [arm64: Mach-O 64-bit dynamically linked shared library arm64]
ANTVSDK (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
<username>:ANTVSDK.framework $
Requisitos del proyecto de Objective C
De forma predeterminada, XCode no tiene una configuración para usar las bibliotecas estándar de Swift para proyectos de Objective-C. En el caso de una aplicación de publicador basada en Objective-C, deberá establecer la opción "Insertar siempre bibliotecas estándar de Swift" en Sí en la configuración de compilación del IDE.