Rekomendacje na Androidzie N i starszych

Podczas interakcji z telewizorami użytkownicy wolą nie podejmować żadnych działań przed obejrzeniem filmu. Idealny scenariusz dla wielu użytkowników telewizji to: usiądź, włącz się i oglądaj. Aby zachęcić użytkowników do obejrzenia treści, które im się podobają, zwykle stosuje się preferowaną przez nich ścieżkę.

Uwaga: opisane tutaj interfejsy API pozwalają tworzyć rekomendacje tylko w aplikacjach działających na urządzeniach z Androidem w wersji do 7.1 (poziom interfejsu API 25) włącznie. Aby udostępniać rekomendacje aplikacji działających w Androidzie 8.0 (poziom interfejsu API 26) i nowszych, aplikacja musi używać kanałów rekomendacji.

Platforma Android ułatwia interakcję z minimalną ilością danych, wyświetlając wiersz rekomendacji na ekranie głównym. Rekomendacje treści pojawiają się jako pierwszy wiersz na ekranie głównym telewizora po pierwszym użyciu urządzenia. Rekomendacje z katalogu treści aplikacji mogą pomóc użytkownikom wrócić do Twojej aplikacji.

Rysunek 1. Przykład wiersza rekomendacji.

Z tego przewodnika dowiesz się, jak tworzyć rekomendacje i udostępniać je w ramach platformy Androida, aby użytkownicy mogli łatwo odkrywać i korzystać z treści Twojej aplikacji. Zobacz też przykładową implementację w przykładowej aplikacji funkcji TalkBack.

Sprawdzone metody dotyczące rekomendacji

Rekomendacje pomagają użytkownikom szybko znajdować interesujące ich treści i aplikacje. Tworzenie rekomendacji wysokiej jakości, które są przydatne dla użytkowników, ma duże znaczenie dla zapewnienia użytkownikom wygody korzystania z aplikacji na telewizorze. Dlatego należy dokładnie przemyśleć, jakie rekomendacje przekazujesz użytkownikowi, i dokładnie nimi zarządzać.

Typy rekomendacji

Tworząc rekomendacje, odsyłaj użytkowników do niezakończonych działań związanych z oglądaniem lub sugeruj działania, które mogą rozszerzyć o powiązane treści. Oto kilka konkretnych rekomendacji, które warto wziąć pod uwagę:

  • Rekomendacje dotyczące dalszych treści dotyczące następnego odcinka, aby użytkownicy mogli wznowić oglądanie serii. Możesz też użyć rekomendacji kontynuacji w przypadku wstrzymanych filmów, seriali i podcastów, aby użytkownicy mogli za pomocą kilku kliknięć wrócić do wstrzymanych treści.
  • rekomendacje nowych treści (np. nowego odcinka serialu), jeśli użytkownik zakończył oglądanie innego serialu. Jeśli Twoja aplikacja umożliwia użytkownikom subskrybowanie, obserwowanie lub śledzenie treści, możesz też korzystać z rekomendacji nowych treści dotyczących nieobejrzanych elementów na ich liście śledzonych treści.
  • Rekomendacje podobnych treści oparte na wcześniejszych zachowaniach użytkowników.

Więcej informacji o projektowaniu kart rekomendacji, które zapewniają użytkownikom najlepsze wrażenia, znajdziesz w wierszu rekomendacji w specyfikacji projektu Androida TV.

Odśwież rekomendacje

Przy odświeżaniu rekomendacji nie tylko nie usuwaj ich i publikuj ponownie, ponieważ dzięki temu rekomendacje pojawiają się na końcu wiersza rekomendacji. Po odtworzeniu elementu treści, na przykład filmu, usuń go z rekomendacji.

Dostosuj rekomendacje

Możesz dostosować karty rekomendacji, aby przekazywały informacje o marce, ustawiając elementy interfejsu, takie jak obraz na pierwszym planie i w tle, kolor, ikona aplikacji, tytuł i podtytuł. Więcej informacji znajdziesz w sekcji Wiersz rekomendacji w specyfikacji projektu Androida TV.

Rekomendacje dotyczące grupy

Opcjonalnie możesz grupować rekomendacje na podstawie źródła rekomendacji. Aplikacja może na przykład przedstawiać 2 grupy rekomendacji: rekomendacje dotyczące treści, które subskrybuje, oraz rekomendacje dotyczące nowych treści zyskujących popularność, których użytkownik może nie znać.

System klasyfikuje i sortuje rekomendacje dla każdej grupy oddzielnie podczas tworzenia lub aktualizowania wiersza rekomendacji. Podając informacje o grupach na potrzeby rekomendacji, możesz zadbać o to, aby rekomendacje nie były uporządkowane poniżej niepowiązanych rekomendacji.

Użyj operatora NotificationCompat.Builder.setGroup(), aby ustawić ciąg klucza grupy rekomendacji. Aby na przykład oznaczyć rekomendację jako należącą do grupy zawierającej nowe treści zyskujące popularność, możesz wywołać setGroup("trending").

Tworzenie usługi rekomendacji

Rekomendacje treści są tworzone podczas przetwarzania w tle. Aby aplikacja mogła brać udział w rekomendacjach, utwórz usługę, która okresowo dodaje informacje z katalogu aplikacji do listy rekomendacji systemu.

Poniższy przykładowy kod ilustruje, jak rozszerzyć IntentService, aby utworzyć usługę rekomendacji dla Twojej aplikacji:

Kotlin

class UpdateRecommendationsService : IntentService("RecommendationService") {
    override protected fun onHandleIntent(intent: Intent) {
        Log.d(TAG, "Updating recommendation cards")
        val recommendations = VideoProvider.getMovieList()
        if (recommendations == null) return

        var count = 0

        try {
            val builder = RecommendationBuilder()
                    .setContext(applicationContext)
                    .setSmallIcon(R.drawable.videos_by_google_icon)

            for (entry in recommendations.entrySet()) {
                for (movie in entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle())

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build()
                    if (++count >= MAX_RECOMMENDATIONS) {
                        break
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break
                }
            }
        } catch (e: IOException) {
            Log.e(TAG, "Unable to update recommendation", e)
        }
    }

    private fun buildPendingIntent(movie: Movie): PendingIntent {
        val detailsIntent = Intent(this, DetailsActivity::class.java)
        detailsIntent.putExtra("Movie", movie)

        val stackBuilder = TaskStackBuilder.create(this)
        stackBuilder.addParentStack(DetailsActivity::class.java)
        stackBuilder.addNextIntent(detailsIntent)

        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(movie.getId().toString())

        val intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
        return intent
    }

    companion object {
        private val TAG = "UpdateRecommendationsService"
        private val MAX_RECOMMENDATIONS = 3
    }
}

Java

public class UpdateRecommendationsService extends IntentService {
    private static final String TAG = "UpdateRecommendationsService";
    private static final int MAX_RECOMMENDATIONS = 3;

    public UpdateRecommendationsService() {
        super("RecommendationService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "Updating recommendation cards");
        HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList();
        if (recommendations == null) return;

        int count = 0;

        try {
            RecommendationBuilder builder = new RecommendationBuilder()
                    .setContext(getApplicationContext())
                    .setSmallIcon(R.drawable.videos_by_google_icon);

            for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) {
                for (Movie movie : entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle());

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build();

                    if (++count >= MAX_RECOMMENDATIONS) {
                        break;
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to update recommendation", e);
        }
    }

    private PendingIntent buildPendingIntent(Movie movie) {
        Intent detailsIntent = new Intent(this, DetailsActivity.class);
        detailsIntent.putExtra("Movie", movie);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(DetailsActivity.class);
        stackBuilder.addNextIntent(detailsIntent);
        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(Long.toString(movie.getId()));

        PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        return intent;
    }
}

Aby system rozpoznał i uruchomił tę usługę, zarejestruj ją za pomocą pliku manifestu aplikacji. Ten fragment kodu pokazuje, jak zadeklarować tę klasę jako usługę:

<manifest ... >
  <application ... >
    ...

    <service
            android:name="com.example.android.tvleanback.UpdateRecommendationsService"
            android:enabled="true" />
  </application>
</manifest>

Rekomendacje dotyczące kompilacji

Po uruchomieniu usługi rekomendacji musi ona tworzyć rekomendacje i przekazywać je do platformy Androida. Platforma otrzymuje rekomendacje jako obiekty Notification, które korzystają z określonego szablonu i są oznaczone konkretną kategorią.

Ustawianie wartości

Aby ustawić wartości elementów interfejsu na karcie rekomendacji, utwórz klasę konstruktora zgodną z wzorcem konstruktora opisanym poniżej. Najpierw ustaw wartości elementów karty rekomendacji.

Kotlin

class RecommendationBuilder {
    ...

    fun setTitle(title: String): RecommendationBuilder {
        this.title = title
        return this
    }

    fun setDescription(description: String): RecommendationBuilder {
        this.description = description
        return this
    }

    fun setImage(uri: String): RecommendationBuilder {
        imageUri = uri
        return this
    }

    fun setBackground(uri: String): RecommendationBuilder {
        backgroundUri = uri
        return this
    }

...

Java

public class RecommendationBuilder {
    ...

    public RecommendationBuilder setTitle(String title) {
            this.title = title;
            return this;
        }

        public RecommendationBuilder setDescription(String description) {
            this.description = description;
            return this;
        }

        public RecommendationBuilder setImage(String uri) {
            imageUri = uri;
            return this;
        }

        public RecommendationBuilder setBackground(String uri) {
            backgroundUri = uri;
            return this;
        }
...

Tworzenie powiadomienia

Po ustawieniu wartości utwórz powiadomienie, przypisując do niego wartości z klasy konstruktora i wywołując NotificationCompat.Builder.build().

Zadzwoń też pod numer setLocalOnly(), aby powiadomienie z aplikacji NotificationCompat.BigPictureStyle nie pojawiło się na innych urządzeniach.

Poniższy przykładowy kod pokazuje, jak utworzyć rekomendację.

Kotlin

class RecommendationBuilder {
    ...

    @Throws(IOException::class)
    fun build(): Notification {
        ...

        val notification = NotificationCompat.BigPictureStyle(
        NotificationCompat.Builder(context)
                .setContentTitle(title)
                .setContentText(description)
                .setPriority(priority)
                .setLocalOnly(true)
                .setOngoing(true)
                .setColor(context.resources.getColor(R.color.fastlane_background))
                .setCategory(Notification.CATEGORY_RECOMMENDATION)
                .setLargeIcon(image)
                .setSmallIcon(smallIcon)
                .setContentIntent(intent)
                .setExtras(extras))
                .build()

        return notification
    }
}

Java

public class RecommendationBuilder {
    ...

    public Notification build() throws IOException {
        ...

        Notification notification = new NotificationCompat.BigPictureStyle(
                new NotificationCompat.Builder(context)
                        .setContentTitle(title)
                        .setContentText(description)
                        .setPriority(priority)
                        .setLocalOnly(true)
                        .setOngoing(true)
                        .setColor(context.getResources().getColor(R.color.fastlane_background))
                        .setCategory(Notification.CATEGORY_RECOMMENDATION)
                        .setLargeIcon(image)
                        .setSmallIcon(smallIcon)
                        .setContentIntent(intent)
                        .setExtras(extras))
                .build();

        return notification;
    }
}

Uruchom usługę rekomendacji

Usługa rekomendacji aplikacji musi działać okresowo, aby utworzyć bieżące rekomendacje. Aby uruchomić usługę, utwórz klasę, która uruchamia licznik czasu i wywołuje go w regularnych odstępach czasu. Ten przykładowy kod rozszerza klasę BroadcastReceiver tak, aby co pół godziny uruchamiać okresowe wykonywanie usługi rekomendacji:

Kotlin

class BootupActivity : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "BootupActivity initiated")
        if (intent.action.endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context)
        }
    }

    private fun scheduleRecommendationUpdate(context: Context) {
        Log.d(TAG, "Scheduling recommendations update")
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val recommendationIntent = Intent(context, UpdateRecommendationsService::class.java)
        val alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0)
        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent
        )
    }

    companion object {
        private val TAG = "BootupActivity"
        private val INITIAL_DELAY:Long = 5000
    }
}

Java

public class BootupActivity extends BroadcastReceiver {
    private static final String TAG = "BootupActivity";

    private static final long INITIAL_DELAY = 5000;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "BootupActivity initiated");
        if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context);
        }
    }

    private void scheduleRecommendationUpdate(Context context) {
        Log.d(TAG, "Scheduling recommendations update");

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class);
        PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0);

        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent);
    }
}

Ta implementacja klasy BroadcastReceiver musi być uruchomiona po uruchomieniu urządzenia telewizyjnego, na którym jest zainstalowana. Aby to zrobić, zarejestruj tę klasę w pliku manifestu aplikacji za pomocą filtra intencji, który nasłuchuje ukończenia procesu uruchamiania urządzenia. Ten przykładowy kod pokazuje, jak dodać tę konfigurację do pliku manifestu:

<manifest ... >
  <application ... >
    <receiver android:name="com.example.android.tvleanback.BootupActivity"
              android:enabled="true"
              android:exported="false">
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
    </receiver>
  </application>
</manifest>

Ważne: aby otrzymać powiadomienie o zakończeniu uruchamiania, aplikacja musi poprosić o uprawnienie RECEIVE_BOOT_COMPLETED. Więcej informacji: ACTION_BOOT_COMPLETED.

Opublikuj rekomendację dla menedżera w metodzie onHandleIntent() klasy usługi rekomendacji w ten sposób:

Kotlin

val notification = notificationBuilder.build()
notificationManager.notify(id, notification)

Java

Notification notification = notificationBuilder.build();
notificationManager.notify(id, notification);