Condividere i diritti di app con Google TV utilizzando l'SDK Engage

Questa guida contiene le istruzioni per gli sviluppatori per condividere i dati relativi agli abbonamenti e ai diritti delle app con Google TV utilizzando l'SDK Engage. Gli utenti possono trovare i contenuti a cui hanno diritto e consentire a Google TV di fornire consigli sui contenuti altamente pertinenti, direttamente all'interno delle esperienze Google TV su TV, dispositivi mobili e tablet.

Prerequisiti

L'onboarding del feed di azioni multimediali è necessario prima di poter utilizzare l'API Diritti dispositivo. Se non l'hai ancora fatto, completa la procedura di onboarding del feed di azioni media.

Preparazione

Prima di iniziare, completa i seguenti passaggi: Verifica che l'app abbia come target il livello API 19 o versioni successive per questa integrazione

  1. Aggiungi la raccolta com.google.android.engage alla tua app:

    Nell'integrazione sono disponibili SDK separati: uno per le app mobile e uno per le app per TV.

    Per dispositivi mobili

    
      dependencies {
        implementation 'com.google.android.engage:engage-core:1.5.5
      }
    

    per TV

    
      dependencies {
        implementation 'com.google.android.engage:engage-tv:1.0.2
      }
    
  2. Imposta l'ambiente di servizio Engage su produzione nel file AndroidManifest.xml.

    Per apk mobile

    
    <meta-data
          android:name="com.google.android.engage.service.ENV"
          android:value="PRODUCTION">
    </meta-data>
    

    APK per TV

    
    <meta-data
        android:name="com.google.android.engage.service.ENV"
        android:value="PRODUCTION">
    </meta-data>
    
  3. Prima di inviare l'APK a Google, imposta l'ambiente di servizio Engage su produzione nel file AndroidManifest.xml. Per prestazioni ottimali e compatibilità futura, pubblica i dati solo quando l'app è in primo piano e l'utente interagisce attivamente con essa, ad esempio al momento dell'avvio dell'app, dopo l'accesso o durante l'utilizzo attivo. La pubblicazione da processi in background è sconsigliata.

  4. Pubblica le informazioni sull'abbonamento per i seguenti eventi:

    1. L'utente accede alla tua app.
    2. L'utente passa da un profilo all'altro (se i profili sono supportati).
    3. L'utente acquista un nuovo abbonamento.
    4. L'utente esegue l'upgrade di un abbonamento esistente.
    5. L'abbonamento dell'utente scade.

Integrazione

Questa sezione fornisce gli esempi di codice e le istruzioni necessarie per implementare AccountProfile e SubscriptionEntity per gestire vari tipi di abbonamenti.

Account e profilo utente

Per consentire le funzionalità personalizzate su Google TV, fornisci le informazioni sull'account. Utilizza AccountProfile per fornire:

  1. ID account: un identificatore univoco che rappresenta l'account dell'utente. Può essere l'ID account effettivo o una versione offuscata in modo appropriato.
// Set the account ID to which the subscription applies.
// Don't set the profile ID because subscription applies to account level.
val accountProfile = AccountProfile.Builder()
  .setAccountId("user_account_id")
  .setProfileId("user_profile id")
  .build();

Abbonamento di livello comune

Per gli utenti con abbonamenti di base ai servizi di fornitori di contenuti multimediali, ad esempio un servizio con un livello di abbonamento che consente l'accesso a tutti i contenuti a pagamento, fornisci i seguenti dettagli essenziali:

  1. Tipo di abbonamento: indica chiaramente il piano di abbonamento specifico di cui dispone l'utente.

    1. SUBSCRIPTION_TYPE_ACTIVE: l'utente ha un abbonamento a pagamento attivo.
    2. SUBSCRIPTION_TYPE_ACTIVE_TRIAL: l'utente ha un abbonamento di prova.
    3. SUBSCRIPTION_TYPE_INACTIVE: l'utente ha un account, ma non ha un abbonamento o una prova attivi.
  2. Scadenza:tempo facoltativo in millisecondi. Specifica quando scade l'abbonamento.

  3. Nome del pacchetto del fornitore:specifica il nome del pacchetto dell'app che gestisce l'abbonamento.

Esempio per il feed del provider di contenuti multimediali di Sample.

"actionAccessibilityRequirement": [
  {
    "@type": "ActionAccessSpecification",
    "category": "subscription",
    "availabilityStarts": "2022-06-01T07:00:00Z",
    "availabilityEnds": "2026-05-31T07:00:00Z",
    "requiresSubscription": {
    "@type": "MediaSubscription",
    // Don't match this string,
    // ID is only used to for reconciliation purpose
    "@id": "https://www.example.com/971bfc78-d13a-4419",
    // Don't match this, as name is only used for displaying purpose
    "name": "Basic common name",
    "commonTier": true
  }

Nell'esempio seguente viene creato un SubscriptionEntity per un utente:

val subscription = SubscriptionEntity
  .Builder()
  setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .build();

Abbonamento Premium

Se l'app offre pacchetti di abbonamenti premium a più livelli, che includono contenuti o funzionalità espansi oltre il livello comune, indicalo aggiungendo uno o più diritti ad Abbonamento.

Questo diritto ha i seguenti campi:

  1. Identificatore:stringa dell'identificatore obbligatoria per questo diritto. Deve corrispondere a uno degli identificatori dei diritti (tieni presente che non si tratta del campo ID) fornito nel feed del fornitore di contenuti multimediali pubblicato su Google TV.
  2. Nome: si tratta di informazioni ausiliarie utilizzate per la corrispondenza dei diritti. Sebbene facoltativo, fornire un nome leggibile per i diritti consente di comprendere meglio i diritti utente sia per gli sviluppatori sia per i team di assistenza. Ad esempio: Sling Orange.
  3. Expiration TimeMillis: se vuoi, specifica la scadenza in millisecondi per questo diritto, se è diversa dalla scadenza dell'abbonamento. Per impostazione predefinita, il diritto scade con la scadenza dell'abbonamento.

Per il seguente snippet di feed del fornitore di contenuti multimediali di esempio:

"actionAccessibilityRequirement": [
  {
    "@type": "ActionAccessSpecification",
    "category": "subscription",
    "availabilityStarts": "2022-06-01T07:00:00Z",
    "availabilityEnds": "2026-05-31T07:00:00Z",
    "requiresSubscription": {
    "@type": "MediaSubscription",
    // Don't match this string,
    // ID is only used to for reconciliation purpose
    "@id": "https://www.example.com/971bfc78-d13a-4419",

    // Don't match this, as name is only used for displaying purpose
    "name": "Example entitlement name",
    "commonTier": false,
    // match this identifier in your API. This is the crucial
    // entitlement identifier used for recommendation purpose.
    "identifier": "example.com:entitlementString1"
  }

L'esempio seguente crea un SubscriptionEntity per un utente iscritto:

// Subscription with entitlements.
// The entitlement expires at the same time as its subscription.
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds
  .setExpirationTimeMillis(1767052800000)
  .addEntitlement(
    SubscriptionEntitlement.Builder()
    // matches with the identifier in media provider feed
    .setEntitlementId("example.com:entitlementString1")
    .setDisplayName("entitlement name1")
    .build()
  )
  .build();
// Subscription with entitlements
// The entitement has different expiration time from its subscription
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds
  .setExpirationTimeMillis(1767052800000)
  .addEntitlement(
    SubscriptionEntitlement.Builder()
    .setEntitlementId("example.com:entitlementString1")
    .setDisplayName("entitlement name1")
    // You may set the expiration time for entitlement
    // December 15, 2025 10:00:00 AM in milliseconds
    .setExpirationTimeMillis(1765792800000)
    .build())
  .build();

Abbonamento per il pacchetto di servizi collegati

Sebbene in genere gli abbonamenti appartengano al provider multimediale dell'app di origine, un abbonamento può essere attribuito a un pacchetto di servizi collegato specificandone il nome all'interno dell'abbonamento.

Il seguente esempio di codice mostra come creare l'abbonamento dell'utente.

// Subscription for linked service package
val subscription = SubscriptionEntity
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("com.google.android.example")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .build();

Inoltre, se l'utente ha un altro abbonamento a un servizio secondario, aggiungi un altro abbonamento e imposta di conseguenza il nome del pacchetto del servizio collegato.

// Subscription for linked service package
val linkedSubscription = Subscription
  .Builder()
  .setSubscriptionType(
    SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE
  )
  .setProviderPackageName("linked service package name")
  // Optional
  // December 30, 2025 12:00:00AM in milliseconds since epoch
  .setExpirationTimeMillis(1767052800000)
  .addBundledSubscription(
    BundledSubscription.Builder()
      .setBundledSubscriptionProviderPackageName(
        "bundled-subscription-package-name"
      )
      .setSubscriptionType(SubscriptionType.SUBSCRIPTION_TYPE_ACTIVE)
      .setExpirationTimeMillis(111)
      .addEntitlement(
        SubscriptionEntitlement.Builder()
        .setExpirationTimeMillis(111)
        .setDisplayName("Silver subscription")
        .setEntitlementId("subscription.tier.platinum")
        .build()
      )
      .build()
  )
    .build();

Se vuoi, aggiungi anche i diritti a un abbonamento a un servizio collegato.

Fornisci l'insieme di abbonamenti

Esegui il job di pubblicazione dei contenuti mentre l'app è in primo piano.

Utilizza il metodo publishSubscriptionCluster() della classe AppEngagePublishClient per pubblicare un oggetto SubscriptionCluster.

Utilizza isServiceAvailable per verificare se il servizio è disponibile per l'integrazione.

client.publishSubscription(
  PublishSubscriptionRequest.Builder()
    .setAccountProfile(accountProfile)
    .setSubscription(subscription)
    .build();
  )

Utilizza setSubscription() per verificare che l'utente debba avere un solo abbonamento al servizio.

Utilizza addLinkedSubscription() o addLinkedSubscriptions(), che accettano un elenco di abbonamenti collegati, per consentire all'utente di avere zero o più abbonamenti collegati.

Quando il servizio riceve la richiesta, viene creata una nuova voce e quella precedente viene eliminata automaticamente dopo 60 giorni. Il sistema utilizza sempre l'ultima voce. In caso di errore, l'intera richiesta viene rifiutata e lo stato esistente viene mantenuto.

Mantenere aggiornato l'abbonamento

  1. Per fornire aggiornamenti immediati in caso di modifiche, chiama publishSubscriptionCluster() ogni volta che cambia lo stato dell'abbonamento di un utente, come attivazione, disattivazione, upgrade e downgrade.
  2. Per garantire una convalida regolare della precisione continua, chiamapublishSubscriptionCluster() almeno una volta al mese.

  3. Per eliminare i dati di scoperta video, elimina manualmente i dati di un utente dal server Google TV prima del periodo di conservazione standard di 60 giorni, utilizzando il metodo client.deleteClusters(). Verranno eliminati tutti i dati esistenti sulla scoperta dei video per il profilo dell'account o per l'intero account, a seconda del valore specificato per DeleteReason.

    Snippet di codice per rimuovere l'abbonamento dell'utente

      // If the user logs out from your media app, you must make the following call
      // to remove subscription and other video discovery data from the current
      // google TV device.
      client.deleteClusters(
        new DeleteClustersRequest.Builder()
          .setAccountProfile(
            AccountProfile
              .Builder()
              .setAccountId()
              .setProfileId()
              .build()
          )
        .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
        .build()
        )
      ```
    Following code snippet demonstrates removal of user subscription
    when user revokes the consent.
    
    ```Kotlin
      // If the user revokes the consent to share across device, make the call
      // to remove subscription and other video discovery data from all google
      // TV devices.
      client.deleteClusters(
        new DeleteClustersRequest.Builder()
          .setAccountProfile(
            AccountProfile
            .Builder()
            .setAccountId()
            .setProfileId()
            .build()
          )
          .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
          .build()
      )
      ```
    
    Following code demonstrates how to remove subscription data on user profile
    deletion.
    
    ```Kotlin
    // If the user delete a specific profile, you must make the following call
    // to remove subscription data and other video discovery data.
    client.deleteClusters(
      new DeleteClustersRequest.Builder()
      .setAccountProfile(
        AccountProfile
        .Builder()
        .setAccountId()
        .setProfileId()
        .build()
      )
      .setReason(DeleteReason.DELETE_REASON_ACCOUNT_PROFILE_DELETION)
      .build()
    )
    

Test

Questa sezione fornisce una guida passo passo per testare l'implementazione dell'abbonamento. Verifica l'accuratezza dei dati e la funzionalità corretta prima del lancio.

Elenco di controllo per la pubblicazione dell'integrazione

  1. La pubblicazione deve avvenire quando l'app è in primo piano e l'utente interagisce attivamente con essa.

  2. Pubblica quando:

    • L'utente accede per la prima volta.
    • L'utente cambia profilo (se i profili sono supportati).
    • L'utente acquista un nuovo abbonamento.
    • L'utente esegue l'upgrade dell'abbonamento.
    • L'abbonamento dell'utente scade.
  3. Controlla se l'app chiama correttamente le API isServiceAvailable() e publishClusters() in logcat, negli eventi di pubblicazione.

  4. Verifica che i dati siano visibili nell'app di verifica. L'app di verifica dovrebbe mostrare l'abbonamento come riga separata. Quando viene invocata l'API di pubblicazione, i dati dovrebbero essere visualizzati nell'app di verifica.

    • Verifica che il flag del servizio Engage NON sia impostato su produzione nel file Android Manifest dell'app.
    • Installa e apri l'app Engage Verification.
    • Se il valore di isServiceAvailable è false nell'app di verifica, fai clic sul pulsante Toggle all'interno dell'app di verifica per impostarlo su true.
    • Inserisci il nome del pacchetto dell'app. Verranno visualizzati automaticamente i dati pubblicati.
  5. Vai all'app ed esegui ciascuna delle seguenti azioni:

    • Accedi.
    • Passare da un profilo all'altro (se supportato).
    • Acquista un nuovo abbonamento.
    • Esegui l'upgrade di un abbonamento esistente.
    • Far scadere l'abbonamento.

Verificare l'integrazione

Per testare l'integrazione, utilizza l'app di verifica.

L'app di verifica è un'applicazione per Android che gli sviluppatori possono utilizzare per verificare che l'integrazione funzioni. L'app include funzionalità per aiutare gli sviluppatori a verificare i dati e trasmettere le intenzioni. Consente di verificare l'accuratezza dei dati e la funzionalità corretta prima del lancio.

  1. Per ciascuno degli eventi, controlla se l'app ha invocato l'API publishSubscription. Verifica i dati pubblicati nell'app di verifica. Verifica che tutto sia verde nell'app di verifica
  2. Se tutte le informazioni dell'entità sono corrette, viene visualizzato un segno di spunta verde "Tutto a posto" in tutte le entità.

    Screenshot dell&#39;app di verifica riuscita
    Figura 1. Abbonamento riuscito
  3. I problemi vengono evidenziati anche nell'app di verifica

    Screenshot dell&#39;errore dell&#39;app di verifica
    Figura 2.Abbonamento non riuscito
  4. Per visualizzare i problemi dell'abbonamento in bundle, usa il telecomando della TV per concentrarti su quell'abbonamento specifico in bundle e fai clic per visualizzare i problemi. Potresti dover prima mettere in primo piano la riga e spostarti verso destra per trovare la scheda Abbonamento combinato. I problemi vengono evidenziati in rosso, come mostrato nella Fig. 3. Inoltre, utilizza il telecomando per spostarti verso il basso per visualizzare i problemi relativi ai diritti all'interno dell'abbonamento in bundle

    Screenshot dei dettagli dell&#39;errore dell&#39;app di verifica
    Figura 3.Errori di abbonamento
  5. Per visualizzare i problemi relativi al diritto, utilizza il telecomando della TV per concentrarti su quel diritto specifico e fai clic per visualizzare i problemi. I problemi sono evidenziati in rosso.

    Screenshot dell&#39;errore dell&#39;app di verifica
    Figura 4.Dettagli errore relativo all'abbonamento