تمثل خدمة الإدخال التلفزيوني مصدر بث وسائط، وتتيح لك عرض محتوى الوسائط في شكل قنوات وبرامج تلفزيونية بشكل خطي. باستخدام خدمة إدخال التلفزيون، يمكنك توفير أدوات الرقابة الأبوية ومعلومات دليل البرامج وتقييمات المحتوى. تعمل خدمة إدخال التلفزيون مع تطبيق Android TV. يتحكم هذا التطبيق في نهاية المطاف في محتوى القناة ويعرضه على التلفزيون. تم تطوير تطبيق بث تلفزيوني من النظام خصيصًا للجهاز، وهو غير قابل للتغيير عند استخدام تطبيقات تابعة لجهات خارجية. للحصول على مزيد من المعلومات حول بنية إطار عمل إدخال التلفزيون (TIF) ومكوّناته، يمكنك مراجعة إطار عمل إدخال التلفزيون.
إنشاء خدمة إدخال تلفزيون باستخدام المكتبة المصاحبة في TIF
مكتبة TIF المصاحبة هي إطار عمل يوفر عمليات تنفيذ قابلة للتوسُّع لميزات خدمة إدخال التلفزيون الشائعة. من المفترض أن يستخدمه المصنّعون الأصليون للأجهزة لإنشاء قنوات من Android 5.0 (مستوى واجهة برمجة التطبيقات 21) إلى Android 7.1 (المستوى 25 من واجهة برمجة التطبيقات) فقط.
تعديل مشروعك
إنّ "مكتبة TIF المصاحبة" متاحة للاستخدام القديم من قِبل المصنّعين الأصليين للأجهزة في مستودع androidtv-sample-inputs. راجع هذا المستودع للحصول على مثال حول كيفية تضمين المكتبة في أحد التطبيقات.
تعريف خدمة إدخال التلفزيون في البيان
يجب أن يوفّر تطبيقك خدمة متوافقة مع TvInputService
يستخدمها النظام للوصول إلى تطبيقك. توفّر
TIF Companion Library الفئة BaseTvInputService
التي توفّر تنفيذًا تلقائيًا لـ TvInputService
يمكنك تخصيصه. أنشئ فئة فرعية من BaseTvInputService
،
وحدِّد الفئة الفرعية في ملف البيان كخدمة.
ضمن بيان البيان، حدِّد الإذن
BIND_TV_INPUT
للسماح
للخدمة بتوصيل إدخال التلفزيون بالنظام. وتنفّذ إحدى خدمات النظام عملية الربط ولديها
إذن BIND_TV_INPUT
.
يرسل تطبيق تلفزيون النظام الطلبات إلى خدمات إدخال التلفزيون
من خلال واجهة TvInputManager
.
في بيان الخدمة، عليك تضمين فلتر أهداف يحدّد
TvInputService
باعتباره الإجراء المطلوب تنفيذه مع
النية. يجب أيضًا تعريف البيانات الوصفية للخدمة كمورد XML منفصل. يتم عرض بيان الخدمة وفلتر الأهداف وبيان البيانات الوصفية للخدمة في المثال التالي:
<service android:name=".rich.RichTvInputService" android:label="@string/rich_input_label" android:permission="android.permission.BIND_TV_INPUT"> <!-- Required filter used by the system to launch our account service. --> <intent-filter> <action android:name="android.media.tv.TvInputService" /> </intent-filter> <!-- An XML file which describes this input. This provides pointers to the RichTvInputSetupActivity to the system/TV app. --> <meta-data android:name="android.media.tv.input" android:resource="@xml/richtvinputservice" /> </service>
حدِّد البيانات الوصفية للخدمة في ملف XML منفصل. يجب أن يتضمّن ملف XML للبيانات الوصفية الخاصة بالخدمة واجهة إعداد توضّح الإعدادات الأولية لإدخال التلفزيون والبحث عن القنوات. يجب أن يحتوي ملف البيانات الوصفية أيضًا على علامة توضح ما إذا كان المستخدمون قادرين على تسجيل المحتوى أم لا. لمزيد من المعلومات حول طريقة إتاحة تسجيل المحتوى في تطبيقك، يُرجى الاطّلاع على مقالة دعم تسجيل المحتوى.
يمكن العثور على ملف البيانات الوصفية للخدمة في دليل موارد XML
لتطبيقك ويجب أن يتطابق مع اسم المورد الذي اخترته في
البيان. باستخدام إدخالات البيان من المثال السابق، يمكنك إنشاء ملف XML على res/xml/richtvinputservice.xml
، مع المحتوى التالي:
<?xml version="1.0" encoding="utf-8"?> <tv-input xmlns:android="http://schemas.android.com/apk/res/android" android:canRecord="true" android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />
تحديد القنوات وإنشاء نشاط الإعداد
يجب أن تحدّد خدمة إدخال التلفزيون قناة واحدة على الأقل يمكن للمستخدمين الوصول إليها من خلال تطبيق YouTube TV. ويجب تسجيل قنواتك في قاعدة بيانات النظام، وتقديم نشاط إعداد يستدعي النظام عندما يتعذّر عليه العثور على قناة لتطبيقك.
أولاً، احرص على تمكين التطبيق من القراءة والكتابة في دليل البرمجة الإلكتروني (EPG) للنظام، والذي تتضمن بياناته القنوات والبرامج المتاحة للمستخدم. لتمكين تطبيقك من تنفيذ هذه الإجراءات ومزامنته مع EPG بعد إعادة تشغيل الجهاز، أضِف العناصر التالية إلى بيان التطبيق:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>
أضِف العنصر التالي لضمان ظهور تطبيقك في "متجر Google Play" كتطبيق يوفّر قنوات المحتوى في Android TV:
<uses-feature android:name="android.software.live_tv" android:required="true" />
الخطوة التالية هي إنشاء صف يوسّع صف EpgSyncJobService
. هذا الفصل المجرّد يجعل من السهل إنشاء خدمة عمل
تؤدي إلى إنشاء القنوات وتحديثها في قاعدة بيانات النظام.
في الفئة الفرعية، أنشئ قائمة كاملة من القنوات وأعد إرسالها في
getChannels()
. إذا كان مصدر قنواتك ملف XMLTV،
استخدِم الفئة XmlTvParser
. ويمكنك بدلاً من ذلك إنشاء
القنوات آليًا باستخدام الفئة Channel.Builder
.
بالنسبة إلى كل قناة، يستدعي النظام getProgramsForChannel()
عندما يحتاج إلى قائمة بالبرامج التي يمكن مشاهدتها خلال فترة زمنية معيّنة
على القناة. عرض قائمة من عناصر Program
للقناة. استخدِم الفئة XmlTvParser
للحصول على برامج من
ملف XMLTV أو إنشاؤها آليًا باستخدام الفئة
Program.Builder
.
بالنسبة إلى كل عنصر Program
، استخدِم عنصر InternalProviderData
لتحديد معلومات البرنامج، مثل نوع فيديو البرنامج. إذا كان لديك عدد محدود من البرامج التي
تريد أن تتكرّرها القناة بشكل متكرّر، استخدِم القيمة
InternalProviderData.setRepeatable()
مع القيمة true
عند إعداد معلومات عن برنامجك.
بعد تنفيذ خدمة العمل، أضِفها إلى بيان التطبيق:
<service android:name=".sync.SampleJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
وأخيرًا، أنشئ نشاط إعداد. يوفر نشاط الإعداد طريقة لمزامنة بيانات القناة والبرنامج. تتمثل إحدى طرق القيام بذلك في قيام المستخدم بذلك عبر واجهة المستخدم في النشاط. قد تجعل التطبيق يقوم بذلك تلقائيًا عند بدء النشاط. عندما يحتاج نشاط الإعداد إلى مزامنة معلومات القناة والبرنامج، يجب أن يبدأ التطبيق خدمة المهمة:
Kotlin
val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID) EpgSyncJobService.cancelAllSyncRequests(getActivity()) EpgSyncJobService.requestImmediateSync( getActivity(), inputId, ComponentName(getActivity(), SampleJobService::class.java) )
Java
String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID); EpgSyncJobService.cancelAllSyncRequests(getActivity()); EpgSyncJobService.requestImmediateSync(getActivity(), inputId, new ComponentName(getActivity(), SampleJobService.class));
استخدِم الطريقة requestImmediateSync()
لمزامنة خدمة المهام. يجب على المستخدم الانتظار حتى تنتهي المزامنة، لذا عليك
إبقاء فترة الطلب قصيرة نسبيًا.
استخدِم طريقة setUpPeriodicSync()
لضبط خدمة العمل على مزامنة بيانات القناة والبرنامج
بشكل دوري في الخلفية:
Kotlin
EpgSyncJobService.setUpPeriodicSync( context, inputId, ComponentName(context, SampleJobService::class.java) )
Java
EpgSyncJobService.setUpPeriodicSync(context, inputId, new ComponentName(context, SampleJobService.class));
توفّر TIF Companion Library طريقة إضافية لتحميل البيانات بشكل زائد requestImmediateSync()
، ما يتيح لك تحديد مدة بيانات القناة المطلوب مزامنتها بالمللي ثانية. تعمل الطريقة الافتراضية على مزامنة
ما يعادل ساعة واحدة من بيانات القناة.
توفّر TIF Companion Library أيضًا طريقة تحميل زائدة في
setUpPeriodicSync()
تتيح لك تحديد مدة
بيانات القناة المطلوب مزامنتها وعدد المرات التي يجب أن تتم المزامنة الدورية فيها. تعمل الطريقة التلقائية
على مزامنة 48 ساعة من بيانات القناة كل 12 ساعة.
لمزيد من التفاصيل حول بيانات القناة وميزة EPG، يُرجى الاطّلاع على مقالة استخدام بيانات القناة.
التعامل مع طلبات الضبط وتشغيل الوسائط
عندما يختار المستخدم قناة معيّنة، يستخدم تطبيق YouTube TV
Session
الذي أنشأه تطبيقك لضبط القناة المطلوبة
وتشغيل المحتوى. توفر TIF Companion Library العديد من الفئات التي يمكنك توسيعها للتعامل مع مكالمات القناة والجلسات من النظام.
تنشئ الفئة الفرعية BaseTvInputService
جلسات تعالج طلبات الضبط. يمكنك إلغاء طريقة
onCreateSession()
وإنشاء جلسة موسّعة من
الصف BaseTvInputService.Session
وطلب جلستك الجديدة بـ
super.sessionCreated()
. في المثال التالي، تعرض onCreateSession()
كائن RichTvInputSessionImpl
يمتدّ BaseTvInputService.Session
:
Kotlin
override fun onCreateSession(inputId: String): Session = RichTvInputSessionImpl(this, inputId).apply { setOverlayViewEnabled(true) }
Java
@Override public final Session onCreateSession(String inputId) { RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId); session.setOverlayViewEnabled(true); return session; }
عندما يستخدم المستخدم تطبيق التلفزيون الخاص بالنظام لبدء مشاهدة إحدى قنواتك،
يستدعي النظام طريقة onPlayChannel()
لجلستك. يمكنك إلغاء
هذه الطريقة إذا كنت تحتاج إلى أي إعداد خاص للقناة قبل
بدء تشغيل البرنامج.
بعد ذلك، يحصل النظام على البرنامج المجدول حاليًا ويُستدعي طريقة onPlayProgram()
الخاصة بالجلسة، مع تحديد معلومات البرنامج ووقت البدء بالمللي ثانية. استخدِم واجهة
TvPlayer
لبدء تشغيل البرنامج.
يجب أن يستخدم رمز مشغّل الوسائط TvPlayer
للتعامل مع
أحداث تشغيل محددة. تتعامل فئة TvPlayer
مع ميزات
مثل عناصر التحكّم في عملية التسجيل على الوقت بدون إضافة تعقيد إلى عملية تنفيذ
BaseTvInputService
.
في طريقة getTvPlayer()
لجلستك، اعرض
مشغّل الوسائط الذي ينفّذ TvPlayer
. يستخدم نموذج تطبيق
TV Enter Service مشغّل وسائط يستخدم
ExoPlayer.
إنشاء خدمة إدخال تلفزيون باستخدام إطار عمل إدخال التلفزيون
إذا لم تتمكن خدمة إدخال التلفزيون من استخدام المكتبة المصاحبة TIF، فستحتاج إلى تنفيذ المكونات التالية:
- يوفر
TvInputService
التوفّر لفترة طويلة والمتاحة في الخلفية لإدخال التلفزيون. - يحافظ
TvInputService.Session
على حالة إدخال التلفزيون ويتواصل مع التطبيق المضيف. - يصف
TvContract
القنوات والبرامج المتاحة لإدخال التلفزيون. - تمثل
TvContract.Channels
معلومات عن قناة تلفزيونية - تصف السمة
TvContract.Programs
برنامج تلفزيوني باستخدام بيانات مثل عنوان البرنامج ووقت بدئه. - تشير السمة
TvTrackInfo
إلى مقطع صوتي أو فيديو أو مقطع ترجمة. - يصف الحقل
TvContentRating
تقييمًا للمحتوى، ويسمح بأنظمة تقييم المحتوى المخصّصة. - يوفّر
TvInputManager
واجهة برمجة تطبيقات لتطبيق التلفزيون على النظام ويدير التفاعل مع إدخالات التلفزيون وتطبيقاته.
عليك أيضًا إجراء ما يلي:
- يُرجى تعريف خدمة إدخال التلفزيون في البيان، على النحو الموضَّح في تعريف خدمة إدخال التلفزيون في البيان.
- أنشِئ ملف البيانات الوصفية للخدمة.
- إنشاء معلومات عن قناتك والبرنامج وتسجيلها
- أنشئ نشاط الإعداد.
تحديد خدمة إدخال التلفزيون
بالنسبة إلى خدمتك، يمكنك تمديد الفئة TvInputService
. عملية تنفيذ
TvInputService
هي
خدمة مرتبطة حيث تكون خدمة النظام
هي العميل الذي يرتبط بها. يتم توضيح طرق دورة حياة الخدمة
التي تحتاج إلى تنفيذها في الشكل 1.
تعمل الطريقة onCreate()
على إعداد وتبدأ عملية HandlerThread
التي توفّر سلسلة عمليات منفصلة عن سلسلة تعليمات واجهة المستخدم لمعالجة الإجراءات المستندة إلى النظام. في المثال التالي، تُعِدّ الطريقة onCreate()
CaptioningManager
وتستعدّ للتعامل مع الإجراءَين ACTION_BLOCKED_RATINGS_CHANGED
وACTION_PARENTAL_CONTROLS_ENABLED_CHANGED
. وتصف هذه الإجراءات أهداف النظام التي يتم تنشيطها عندما يغيّر المستخدم إعدادات أدوات الرقابة الأبوية، وعند حدوث تغيير في قائمة التقييمات المحظورة.
Kotlin
override fun onCreate() { super.onCreate() handlerThread = HandlerThread(javaClass.simpleName).apply { start() } dbHandler = Handler(handlerThread.looper) handler = Handler() captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager setTheme(android.R.style.Theme_Holo_Light_NoActionBar) sessions = mutableListOf<BaseTvInputSessionImpl>() val intentFilter = IntentFilter().apply { addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED) addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED) } registerReceiver(broadcastReceiver, intentFilter) }
Java
@Override public void onCreate() { super.onCreate(); handlerThread = new HandlerThread(getClass() .getSimpleName()); handlerThread.start(); dbHandler = new Handler(handlerThread.getLooper()); handler = new Handler(); captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE); setTheme(android.R.style.Theme_Holo_Light_NoActionBar); sessions = new ArrayList<BaseTvInputSessionImpl>(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(TvInputManager .ACTION_BLOCKED_RATINGS_CHANGED); intentFilter.addAction(TvInputManager .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED); registerReceiver(broadcastReceiver, intentFilter); }
راجع صفحة
التحكم في المحتوى للحصول على مزيد من المعلومات حول التعامل مع المحتوى المحظور وتوفير أدوات الرقابة الأبوية. يمكنك مراجعة TvInputManager
لمعرفة المزيد من الإجراءات المستندة إلى النظام
التي قد تريد معالجتها في خدمة إدخال التلفزيون.
تنشئ TvInputService
عنصر TvInputService.Session
ينفّذ Handler.Callback
للتعامل مع تغييرات حالة اللاعب. في حال استخدام
onSetSurface()
،
تضبط السمة TvInputService.Session
السمة Surface
بمحتوى الفيديو. راجِع دمج المشغّل مع السطح
للحصول على مزيد من المعلومات حول استخدام Surface
لعرض الفيديو.
تعالج TvInputService.Session
حدث
onTune()
عندما يختار المستخدم قناة، وتُبلغ تطبيق YouTube TV بأي تغييرات تطرأ على المحتوى
والبيانات الوصفية للمحتوى. يمكن الاطّلاع أيضًا على طريقة notify()
هذه في قسم
التحكّم في المحتوى واختيار مسار الاسم المعرِّف
في مزيد من المعلومات في هذا التدريب.
تحديد نشاط الإعداد
يعمل تطبيق YouTube TV مع نشاط الإعداد الذي تحدِّده لإدخال التلفزيون. يكون نشاط الإعداد مطلوبًا ويجب أن يوفر سجل قناة واحدًا على الأقل لقاعدة بيانات النظام. يستدعي تطبيق YouTube TV نشاط الإعداد عندما يتعذّر عليه العثور على قناة لإدخال التلفزيون.
يصف نشاط الإعداد لتطبيق YouTube TV الذي وفّرته القنوات من خلال إدخال التلفزيون، كما هو موضَّح في الدرس التالي، إنشاء بيانات القناة وتعديلها.