القنوات على الشاشة الرئيسية

توفّر الشاشة الرئيسية في Android TV واجهة مستخدم تعرض المحتوى المقترَح على شكل جدول يتضمّن القنوات والبرامج. يمثّل كل صف قناة. تحتوي القناة على بطاقات لكل برنامج متاح على تلك القناة:

شاشة Android TV الرئيسية
الشاشة الرئيسية في Android TV

يوضّح هذا المستند كيفية إضافة القنوات والبرامج إلى الشاشة الرئيسية وتعديل المحتوى والتعامل مع إجراءات المستخدمين وتقديم أفضل تجربة لهم. (إذا أردت التعمّق أكثر في واجهة برمجة التطبيقات، يمكنك تجربة الدرس التطبيقي حول الترميز للشاشة الرئيسية ومشاهدة جلسة Android TV في مؤتمر I/O لعام 2017)

واجهة مستخدم الشاشة الرئيسية

يمكن للتطبيقات إنشاء قنوات جديدة وإضافة البرامج وإزالتها وتحديثها في قناة معيّنة، والتحكّم في ترتيب البرامج في القناة. على سبيل المثال، يمكن لأحد التطبيقات إنشاء قناة باسم "آخر الأخبار" وعرض بطاقات للبرامج المتاحة حديثًا.

لا يمكن للتطبيقات التحكّم في ترتيب ظهور القنوات في الشاشة الرئيسية. عندما ينشئ تطبيقك قناة جديدة، تضيفها الشاشة الرئيسية إلى أسفل قائمة القنوات. يمكن للمستخدم إعادة ترتيب القنوات وإخفائها وإظهارها.

قناة "اقتراحات أخرى"

قناة "اقتراحات أخرى" هي الصف الثاني الذي يظهر في الشاشة الرئيسية بعد صف التطبيقات. ينشئ النظام هذه القناة ويحافظ عليها. يمكن لتطبيقك إضافة برامج إلى قناة "اقتراحات أخرى". لمزيد من المعلومات، يُرجى الاطّلاع على إضافة برامج إلى قناة "اقتراحات أخرى".

قنوات التطبيقات

تتّبع القنوات التي ينشئها تطبيقك مراحل النشاط التالية:

  1. يكتشف المستخدم قناة في تطبيقك ويطلب إضافتها إلى الشاشة الرئيسية.
  2. ينشئ التطبيق القناة ويضيفها إلى TvProvider (في هذه المرحلة، لا تكون القناة مرئية).
  3. يطلب التطبيق من النظام عرض القناة.
  4. يطلب النظام من المستخدم الموافقة على القناة الجديدة.
  5. تظهر القناة الجديدة في الصف الأخير من الشاشة الرئيسية.

القناة التلقائية

يمكن أن يوفّر تطبيقك أي عدد من القنوات للمستخدم لإضافتها إلى الشاشة الرئيسية. وعادةً ما يتعيّن على المستخدم اختيار كل قناة والموافقة عليها قبل أن تظهر في الشاشة الرئيسية. يتوفّر لكل تطبيق خيار إنشاء قناة تلقائية واحدة. تُعدّ القناة التلقائية مميزة لأنّها تظهر تلقائيًا في الشاشة الرئيسية، ولا يحتاج المستخدم إلى طلبها صراحةً.

المتطلبات الأساسية

تستخدم شاشة Android TV الرئيسية واجهات برمجة تطبيقات TvProvider في Android لإدارة القنوات والبرامج التي ينشئها تطبيقك. للوصول إلى بيانات مقدّم الخدمة، أضِف الإذن التالي إلى بيان تطبيقك:

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />

تسهّل مكتبة دعم TvProvider استخدام الموفّر. أضِفها إلى التبعيات في ملف build.gradle:

أنيق

implementation 'androidx.tvprovider:tvprovider:1.0.0'

Kotlin

implementation("androidx.tvprovider:tvprovider:1.0.0")

للعمل مع القنوات والبرامج، تأكَّد من تضمين عمليات استيراد مكتبة الدعم التالية في برنامجك:

Kotlin

import android.support.media.tv.Channel
import android.support.media.tv.TvContractCompat
import android.support.media.tv.ChannelLogoUtils
import android.support.media.tv.PreviewProgram
import android.support.media.tv.WatchNextProgram

Java

import android.support.media.tv.Channel;
import android.support.media.tv.TvContractCompat;
import android.support.media.tv.ChannelLogoUtils;
import android.support.media.tv.PreviewProgram;
import android.support.media.tv.WatchNextProgram;

القنوات

تصبح القناة الأولى التي ينشئها تطبيقك هي القناة التلقائية. تظهر القناة التلقائية تلقائيًا في الشاشة الرئيسية. ويجب أن يختار المستخدم جميع القنوات الأخرى التي تنشئها ويقبلها قبل أن تظهر في الشاشة الرئيسية.

كيفية إنشاء قناة

يجب أن يطلب تطبيقك من النظام عرض القنوات المُضافة حديثًا فقط عندما يكون قيد التشغيل في المقدّمة. يمنع ذلك تطبيقك من عرض مربّع حوار يطلب الموافقة على إضافة قناتك أثناء تشغيل المستخدم لتطبيق مختلف. إذا حاولت إضافة قناة أثناء التشغيل في الخلفية، ستعرض طريقة onActivityResult() للنشاط رمز الحالة RESULT_CANCELED.

لإنشاء قناة، اتّبِع الخطوات التالية:

  1. أنشئ أداة إنشاء قنوات واضبط سماتها. يُرجى العِلم أنّ نوع القناة يجب أن يكون TYPE_PREVIEW. أضِف المزيد من السمات حسب الحاجة.

    Kotlin

    val builder = Channel.Builder()
    // Every channel you create must have the type `TYPE_PREVIEW`
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri)
    

    Java

    Channel.Builder builder = new Channel.Builder();
    // Every channel you create must have the type `TYPE_PREVIEW`
    builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
            .setDisplayName("Channel Name")
            .setAppLinkIntentUri(uri);
    
  2. أدخِل القناة في الموفّر:

    Kotlin

    var channelUri = context.contentResolver.insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues())
    

    Java

    Uri channelUri = context.getContentResolver().insert(
            TvContractCompat.Channels.CONTENT_URI, builder.build().toContentValues());
    
  3. يجب حفظ معرّف القناة لإضافة البرامج إلى القناة لاحقًا. استخرِج معرّف القناة من معرّف الموارد المنتظم (URI) الذي تم عرضه:

    Kotlin

    var channelId = ContentUris.parseId(channelUri)
    

    Java

    long channelId = ContentUris.parseId(channelUri);
    
  4. يجب إضافة شعار لقناتك. استخدِم Uri أو Bitmap. يجب أن يكون حجم رمز الشعار 80 بكسل مستقل الكثافة × 80 بكسل مستقل الكثافة، ويجب أن يكون معتمًا. ويتم عرضه تحت قناع دائري:

    قناع رمز الشاشة الرئيسية للتلفزيون

    Kotlin

    // Choose one or the other
    storeChannelLogo(context: Context, channelId: Long, logoUri: Uri) // also works if logoUri is a URL
    storeChannelLogo(context: Context, channelId: Long, logo: Bitmap)
    

    Java

    // Choose one or the other
    storeChannelLogo(Context context, long channelId, Uri logoUri); // also works if logoUri is a URL
    storeChannelLogo(Context context, long channelId, Bitmap logo);
    
  5. إنشاء القناة التلقائية (اختياري): عندما ينشئ تطبيقك قناته الأولى، يمكنك جعلها القناة التلقائية لتظهر على الشاشة الرئيسية على الفور بدون أي إجراء من المستخدم. وأي قنوات أخرى تنشئها لن تظهر إلى أن يختارها المستخدم صراحةً.

    Kotlin

    TvContractCompat.requestChannelBrowsable(context, channelId)
    

    Java

    TvContractCompat.requestChannelBrowsable(context, channelId);
    
  6. اجعل قناتك التلقائية تظهر قبل فتح تطبيقك. يمكنك تنفيذ هذا السلوك من خلال إضافة BroadcastReceiver يستمع إلى الإجراء android.media.tv.action.INITIALIZE_PROGRAMS الذي ترسله الشاشة الرئيسية بعد تثبيت التطبيق:

    <receiver
      android:name=".RunOnInstallReceiver"
      android:exported="true">
        <intent-filter>
          <action android:name="android.media.tv.action.INITIALIZE_PROGRAMS" />
          <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>
    

    عند تثبيت تطبيقك من مصدر غير معروف أثناء عملية التطوير، يمكنك اختبار هذه الخطوة من خلال تفعيل الغرض من خلال adb، حيث your.package.name/.YourReceiverName هو BroadcastReceiver لتطبيقك:

    adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n \
        your.package.name/.YourReceiverName
    

    في حالات نادرة، قد يتلقّى تطبيقك البث في الوقت نفسه الذي يبدأ فيه المستخدم تشغيل تطبيقك. تأكَّد من أنّ الرمز البرمجي لا يحاول إضافة القناة التلقائية أكثر من مرة.

تعديل قناة

تتشابه عملية تعديل القنوات إلى حد كبير مع عملية إنشائها.

استخدِم Channel.Builder آخر لضبط السمات التي يجب تغييرها.

استخدِم ContentResolver لتعديل القناة. استخدِم معرّف القناة الذي حفظته عند إضافة القناة في الأصل:

Kotlin

context.contentResolver.update(
        TvContractCompat.buildChannelUri(channelId),
        builder.build().toContentValues(),
        null,
        null
)

Java

context.getContentResolver().update(TvContractCompat.buildChannelUri(channelId),
    builder.build().toContentValues(), null, null);

لتعديل شعار قناة، استخدِم storeChannelLogo().

حذف قناة

Kotlin

context.contentResolver.delete(TvContractCompat.buildChannelUri(channelId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildChannelUri(channelId), null, null);

البرامج

البرامج هي بطاقات المحتوى الفردية التي يتم عرضها ضمن قناة. يمكنك نشر البرامج على كل من القنوات المخصّصة لتطبيقك وقناة "اقتراحات أخرى" التي يديرها النظام.

إضافة برامج إلى قناة تطبيق

أنشئ PreviewProgram.Builder واضبط سماته:

Kotlin

val builder = PreviewProgram.Builder()
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId)

Java

PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
        .setType(TvContractCompat.PreviewPrograms.TYPE_CLIP)
        .setTitle("Title")
        .setDescription("Program description")
        .setPosterArtUri(uri)
        .setIntentUri(uri)
        .setInternalProviderId(appProgramId);

أضِف المزيد من السمات حسب نوع البرنامج. (للاطّلاع على السمات المتاحة لكل نوع من البرامج، يُرجى الرجوع إلى الجداول أدناه).

أدخِل البرنامج في الموفّر:

Kotlin

var programUri = context.contentResolver.insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
        builder.build().toContentValues())

Java

Uri programUri = context.getContentResolver().insert(TvContractCompat.PreviewPrograms.CONTENT_URI,
      builder.build().toContentValues());

استرِدّ معرّف البرنامج للرجوع إليه لاحقًا:

Kotlin

val programId = ContentUris.parseId(programUri)

Java

long programId = ContentUris.parseId(programUri);

إضافة برامج إلى قناة "اقتراحات أخرى"

لإدراج برامج في قناة "اقتراحات أخرى"، يُرجى الاطّلاع على إضافة برامج إلى قناة "اقتراحات أخرى".

تعديل برنامج

يمكنك تغيير معلومات البرنامج. على سبيل المثال، قد تحتاج إلى تعديل سعر استئجار فيلم أو تعديل شريط تقدّم يعرض مقدار ما شاهده المستخدم من برنامج.

استخدِم PreviewProgram.Builder لضبط السمات التي تريد تغييرها، ثم استدعِ getContentResolver().update لتعديل البرنامج. حدِّد رقم تعريف البرنامج الذي حفظته عند إضافة البرنامج في الأصل:

Kotlin

context.contentResolver.update(
        TvContractCompat.buildPreviewProgramUri(programId),
                builder.build().toContentValues(), null, null
)

Java

context.getContentResolver().update(TvContractCompat.buildPreviewProgramUri(programId),
    builder.build().toContentValues(), null, null);

حذف برنامج

Kotlin

context.contentResolver
        .delete(TvContractCompat.buildPreviewProgramUri(programId), null, null)

Java

context.getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(programId), null, null);

التعامل مع إجراءات المستخدمين

يمكن أن يساعد تطبيقك المستخدمين في اكتشاف المحتوى من خلال توفير واجهة مستخدم لعرض القنوات وإضافتها. يجب أن يتعامل تطبيقك أيضًا مع التفاعلات مع قنواتك بعد ظهورها في الشاشة الرئيسية.

استكشاف القنوات وإضافتها

يمكن أن يوفّر تطبيقك عنصرًا في واجهة المستخدم يتيح للمستخدم اختيار قنواته وإضافتها (على سبيل المثال، زر يطلب إضافة القناة).

بعد أن يطلب المستخدم قناة معيّنة، نفِّذ هذا الرمز للحصول على إذن المستخدم لإضافتها إلى واجهة مستخدم الشاشة الرئيسية:

Kotlin

val intent = Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE)
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId)
try {
  activity.startActivityForResult(intent, 0)
} catch (e: ActivityNotFoundException) {
  // handle error
}

Java

Intent intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
try {
   activity.startActivityForResult(intent, 0);
} catch (ActivityNotFoundException e) {
  // handle error
}

يعرض النظام مربّع حوار يطلب من المستخدم الموافقة على القناة. يمكنك معالجة نتيجة الطلب في إجراء onActivityResult الخاص بنشاطك (Activity.RESULT_CANCELED أو Activity.RESULT_OK).

أحداث شاشة Android TV الرئيسية

عندما يتفاعل المستخدم مع البرامج والقنوات التي ينشرها التطبيق، ترسل الشاشة الرئيسية طلبات إلى التطبيق:

  • ترسل الشاشة الرئيسية Uri المخزَّن في سمة APP_LINK_INTENT_URI للقناة إلى التطبيق عندما يختار المستخدم شعار القناة. يجب أن يشغّل التطبيق واجهة المستخدم الرئيسية أو طريقة عرض ذات صلة بالقناة المحدّدة.
  • ترسل الشاشة الرئيسية Uri المخزَّن في سمة INTENT_URI الخاصة ببرنامج إلى التطبيق عندما يختار المستخدم برنامجًا. من المفترض أن يشغّل التطبيق المحتوى المحدّد.
  • يمكن للمستخدم الإشارة إلى أنّه لم يعُد مهتمًا ببرنامج معيّن ويريد إزالته من واجهة المستخدم في الشاشة الرئيسية. يزيل النظام البرنامج من واجهة المستخدم ويرسل إلى التطبيق الذي يملك البرنامج هدفًا (android.media.tv.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED أو android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED) مع رقم تعريف البرنامج. يجب أن يزيل التطبيق البرنامج من الموفّر وألا يعيد إدراجه.

تأكَّد من إنشاء intent filters لجميع Uris التي ترسلها الشاشة الرئيسية لتفاعلات المستخدمين، على سبيل المثال:

<receiver
   android:name=".WatchNextProgramRemoved"
   android:enabled="true"
   android:exported="true">
   <intent-filter>
       <action android:name="android.media.tv.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
   </intent-filter>
</receiver>

اعتبارات أخرى

  • تتطلّب العديد من تطبيقات البث التلفزيوني من المستخدمين تسجيل الدخول. في هذه الحالة، يجب أن يقترح BroadcastReceiver الذي يستمع إلى android.media.tv.action.INITIALIZE_PROGRAMS محتوى القناة للمستخدمين غير المصادق عليهم. على سبيل المثال، يمكن لتطبيقك في البداية عرض أفضل محتوى أو المحتوى الرائج حاليًا. بعد تسجيل المستخدم الدخول، يمكنه عرض محتوى مخصص. هذه فرصة رائعة للتطبيقات لزيادة المبيعات للمستخدمين قبل تسجيل الدخول.
  • عندما لا يكون تطبيقك في المقدّمة وتحتاج إلى تعديل قناة أو برنامج، استخدِم JobScheduler لجدولة العمل (راجِع JobScheduler وJobService).
  • يمكن للنظام إبطال أذونات مقدّم الخدمة لتطبيقك إذا أساء تطبيقك التصرّف (على سبيل المثال: إرسال بيانات غير مرغوب فيها باستمرار إلى مقدّم الخدمة). تأكَّد من تضمين الرمز الذي يصل إلى الموفِّر في عبارات try-catch للتعامل مع استثناءات الأمان.
  • قبل تعديل البرامج والقنوات، يمكنك الاستعلام من الموفّر عن البيانات التي تحتاج إلى تعديلها وتسويتها. على سبيل المثال، ليست هناك حاجة إلى تحديث برنامج يريد المستخدم إزالته من واجهة المستخدم. استخدِم مهمة في الخلفية تُدرج بياناتك أو تعدّلها في الموفّر بعد الاستعلام عن البيانات الحالية ثم طلب الموافقة على قنواتك. يمكنك تشغيل هذه المهمة عند بدء تشغيل التطبيق وكلما احتاج التطبيق إلى تحديث بياناته.

Kotlin

context.contentResolver
      .query(
          TvContractCompat.buildChannelUri(channelId),
              null, null, null, null).use({
                  cursor-> if (cursor != null and cursor.moveToNext()) {
                                val channel = Channel.fromCursor(cursor)
                                if (channel.isBrowsable()) {
                                    //update channel's programs
                                }
                            }
              })

Java

try (Cursor cursor = context.getContentResolver()
          .query(
              TvContractCompat.buildChannelUri(channelId),
              null,
              null,
              null,
              null)) {
                  if (cursor != null &amp;&amp; cursor.moveToNext()) {
                      Channel channel = Channel.fromCursor(cursor);
                      if (channel.isBrowsable()) {
                          //update channel's programs
                      }
                  }
              }
  • استخدِم معرّفات موارد منتظمة (URI) فريدة لجميع الصور (الشعارات والرموز وصور المحتوى). احرص على استخدام معرّف موارد منتظم (URI) مختلف عند تعديل صورة. يتم تخزين جميع الصور مؤقتًا. إذا لم تغيّر معرّف الموارد المنتظم (URI) عند تغيير الصورة، ستستمر الصورة القديمة في الظهور.

  • يُرجى العِلم أنّه لا يُسمح باستخدام عبارات WHERE، وسيؤدي إرسال طلبات إلى مقدّمي الخدمات تتضمّن عبارات WHERE إلى ظهور استثناء أمان.

السمات

يصف هذا القسم سمات القناة والبرنامج بشكل منفصل.

سمات القناة

يجب تحديد هذه السمات لكل قناة:

السمة ملاحظات
النوع على TYPE_PREVIEW.
DISPLAY_NAME على اسم القناة
APP_LINK_INTENT_URI عندما يختار المستخدم شعار القناة، يرسل النظام طلبًا لبدء نشاط يعرض محتوى ذا صلة بالقناة. اضبط هذه السمة على معرّف الموارد المنتظم (URI) المستخدَم في intent filter لهذا النشاط.

بالإضافة إلى ذلك، تتضمّن القناة أيضًا ستة حقول محجوزة لاستخدام التطبيق الداخلي. يمكن استخدام هذه الحقول لتخزين المفاتيح أو القيم الأخرى التي يمكن أن تساعد التطبيق في ربط القناة ببنية البيانات الداخلية:

  • INTERNAL_PROVIDER_ID
  • INTERNAL_PROVIDER_DATA
  • INTERNAL_PROVIDER_FLAG1
  • INTERNAL_PROVIDER_FLAG2
  • INTERNAL_PROVIDER_FLAG3
  • INTERNAL_PROVIDER_FLAG4

سمات البرنامج

اطّلِع على الصفحات الفردية للسمات الخاصة بكل نوع من البرامج:

نموذج التعليمات البرمجية

لمزيد من المعلومات حول إنشاء تطبيقات تتفاعل مع الشاشة الرئيسية وإضافة قنوات وبرامج إلى شاشة Android TV الرئيسية، يمكنك الاطّلاع على الدرس التطبيقي حول الترميز الخاص بالشاشة الرئيسية.