يجب أن يوفّر مصدر الإدخال التلفزيوني بيانات دليل البرنامج الإلكتروني (EPG) لمدة لا تقل عن قناة واحدة في نشاط الإعداد الخاص بها. كما يجب عليك تحديث ذلك بشكل دوري مع مراعاة حجم التحديث وسلسلة عمليات المعالجة. التي تعالجه. يمكنك أيضًا تقديم روابط تطبيق للقنوات توجه المستخدم إلى المحتوى والأنشطة ذات الصلة. يناقش هذا الدرس إنشاء بيانات القناة والبرنامج وتحديثها باستخدام قاعدة بيانات النظام مع وضع هذه الاعتبارات في الاعتبار.
جرِّب نموذج تطبيق "خدمة إدخال التلفزيون"
الحصول على الإذن
لكي يعمل إدخال التلفزيون مع بيانات وضع EPG، يجب توضيح أنّ إذن الكتابة في ملف بيان Android على النحو التالي:
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
تسجيل القنوات في قاعدة البيانات
تحتفظ قاعدة بيانات نظام Android TV بسجلات بيانات القناة لمدخلات التلفزيون. في إعداداتك
لكل قناة من قنواتك، يجب ربط بيانات القناة بالحقول التالية في
صف واحد (TvContract.Channels
):
COLUMN_DISPLAY_NAME
- الاسم المعروض القناةCOLUMN_DISPLAY_NUMBER
- القناة المعروضة الرقمCOLUMN_INPUT_ID
- معرّف خدمة إدخال التلفزيونCOLUMN_SERVICE_TYPE
- نوع الخدمة التي تقدّمها القناةCOLUMN_TYPE
- معيار البث الخاص بالقناة النوعCOLUMN_VIDEO_FORMAT
- التنسيق التلقائي للفيديو للقناة
رغم أن إطار إدخال التلفزيون عام بما يكفي للتعامل مع كل من البث التقليدي للمحتوى المباشر دون أي اختلاف، يمكنك تحديد الأعمدة التالية بالإضافة إلى ما ورد أعلاه لتحديد قنوات البث التقليدية بشكل أفضل:
COLUMN_ORIGINAL_NETWORK_ID
- التلفزيون رقم تعريف الشبكةCOLUMN_SERVICE_ID
- معرّف الخدمةCOLUMN_TRANSPORT_STREAM_ID
- مصدر وسيلة النقل رقم التعريف
إذا أردت تقديم تفاصيل رابط التطبيق لقنواتك، يجب: لتحديث بعض الحقول الإضافية. لمزيد من المعلومات عن حقول رابط التطبيق، راجع إضافة معلومات رابط التطبيق
بالنسبة إلى إدخالات التلفزيون القائمة على بث الإنترنت، يجب تعيين القيم الخاصة بك لما سبق وفقًا لذلك يمكن تحديد كل قناة بشكل فريد.
سحب البيانات الوصفية لقناتك (بتنسيق XML أو JSON أو غير ذلك) من خادم الخلفية وفي الإعدادات يقوم النشاط بتعيين القيم إلى قاعدة بيانات النظام على النحو التالي:
Kotlin
val values = ContentValues().apply { put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, channel.number) put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.name) put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId) put(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId) put(TvContract.Channels.COLUMN_SERVICE_ID, channel.serviceId) put(TvContract.Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat) } val uri = context.contentResolver.insert(TvContract.Channels.CONTENT_URI, values)
Java
ContentValues values = new ContentValues(); values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.number); values.put(Channels.COLUMN_DISPLAY_NAME, channel.name); values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.originalNetworkId); values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.transportStreamId); values.put(Channels.COLUMN_SERVICE_ID, channel.serviceId); values.put(Channels.COLUMN_VIDEO_FORMAT, channel.videoFormat); Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
في المثال أعلاه، channel
هو عنصر يحتفظ بالبيانات الوصفية للقناة من
خادم الخلفية.
عرض معلومات عن القناة والبرنامج
يعرض تطبيق البث التلفزيوني الخاص بالنظام معلومات عن القنوات والبرامج للمستخدمين أثناء تصفّح القنوات كما هو موضح في الشكل 1. للتأكّد من أنّ معلومات القناة والبرنامج متوافقة مع نظام تشغيل تطبيق التلفزيون مقدّم معلومات القناة والبرنامج، يُرجى اتّباع الإرشادات أدناه.
- رقم القناة (
COLUMN_DISPLAY_NUMBER
) - الرمز
(
android:icon
في بيان إدخال التلفزيون) - وصف البرنامج (
COLUMN_SHORT_DESCRIPTION
) - عنوان البرنامج (
COLUMN_TITLE
) - شعار القناة (
TvContract.Channels.Logo
)- استخدِم اللون #EEEEEE لمطابقة النص المحيط.
- عدم تضمين مساحة متروكة
- فن الملصق (
COLUMN_POSTER_ART_URI
)- نسبة العرض إلى الارتفاع بين 16:9 و4:3
يوفّر تطبيق البث التلفزيوني الخاص بالنظام المعلومات نفسها من خلال دليل البرنامج، بما في ذلك صورة الملصق كما هو موضح في الشكل 2.
تعديل بيانات القناة
عند تعديل بيانات قناة حالية، استخدِم
update()
بدلاً من حذف البيانات وإعادة إضافتها. يمكنك تحديد الإصدار الحالي من البيانات
باستخدام Channels.COLUMN_VERSION_NUMBER
وPrograms.COLUMN_VERSION_NUMBER
عند اختيار السجلات المراد تحديثها.
ملاحظة: عند إضافة بيانات القناة إلى ContentProvider
بعض الوقت. إضافة البرامج الحالية (تلك التي تقع خلال ساعتين من الوقت الحالي)
عند إعداد "EpgSyncJobService
" لتحديث باقي الأجهزة
لبيانات القناة في الخلفية. عرض
نموذج تطبيق Android TV Live TV كمثال.
تحميل مُجمَّع لبيانات القناة
عند تعديل قاعدة بيانات النظام من خلال إضافة قدر كبير من بيانات القناة، استخدِم السمة ContentResolver
applyBatch()
أو
bulkInsert()
. إليك مثال على استخدام السمة applyBatch()
:
Kotlin
val ops = ArrayList<ContentProviderOperation>() val programsCount = channelInfo.mPrograms.size channelInfo.mPrograms.forEachIndexed { index, program -> ops += ContentProviderOperation.newInsert( TvContract.Programs.CONTENT_URI).run { withValues(programs[index]) withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000) withValue( TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, (programStartSec + program.durationSec) * 1000 ) build() } programStartSec += program.durationSec if (index % 100 == 99 || index == programsCount - 1) { try { contentResolver.applyBatch(TvContract.AUTHORITY, ops) } catch (e: RemoteException) { Log.e(TAG, "Failed to insert programs.", e) return } catch (e: OperationApplicationException) { Log.e(TAG, "Failed to insert programs.", e) return } ops.clear() } }
Java
ArrayList<ContentProviderOperation> ops = new ArrayList<>(); int programsCount = channelInfo.mPrograms.size(); for (int j = 0; j < programsCount; ++j) { ProgramInfo program = channelInfo.mPrograms.get(j); ops.add(ContentProviderOperation.newInsert( TvContract.Programs.CONTENT_URI) .withValues(programs.get(j)) .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS, programStartSec * 1000) .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS, (programStartSec + program.durationSec) * 1000) .build()); programStartSec = programStartSec + program.durationSec; if (j % 100 == 99 || j == programsCount - 1) { try { getContentResolver().applyBatch(TvContract.AUTHORITY, ops); } catch (RemoteException | OperationApplicationException e) { Log.e(TAG, "Failed to insert programs.", e); return; } ops.clear(); } }
معالجة بيانات القناة بشكل غير متزامن
ينبغي أن تحدث معالجة البيانات، مثل جلب البث من الخادم أو الوصول إلى قاعدة البيانات،
عدم حظر مؤشر ترابط واجهة المستخدم. إن استخدام AsyncTask
هو واحد
لإجراء التحديثات بشكل غير متزامن. على سبيل المثال، عند تحميل معلومات القناة من خادم خلفية،
يمكنك استخدام AsyncTask
على النحو التالي:
Kotlin
private class LoadTvInputTask(val context: Context) : AsyncTask<Uri, Unit, Unit>() { override fun doInBackground(vararg uris: Uri) { try { fetchUri(uris[0]) } catch (e: IOException) { Log.d("LoadTvInputTask", "fetchUri error") } } @Throws(IOException::class) private fun fetchUri(videoUri: Uri) { context.contentResolver.openInputStream(videoUri).use { inputStream -> Xml.newPullParser().also { parser -> try { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) parser.setInput(inputStream, null) sTvInput = ChannelXMLParser.parseTvInput(parser) sSampleChannels = ChannelXMLParser.parseChannelXML(parser) } catch (e: XmlPullParserException) { e.printStackTrace() } } } } }
Java
private static class LoadTvInputTask extends AsyncTask<Uri, Void, Void> { private Context mContext; public LoadTvInputTask(Context context) { mContext = context; } @Override protected Void doInBackground(Uri... uris) { try { fetchUri(uris[0]); } catch (IOException e) { Log.d("LoadTvInputTask", "fetchUri error"); } return null; } private void fetchUri(Uri videoUri) throws IOException { InputStream inputStream = null; try { inputStream = mContext.getContentResolver().openInputStream(videoUri); XmlPullParser parser = Xml.newPullParser(); try { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(inputStream, null); sTvInput = ChannelXMLParser.parseTvInput(parser); sSampleChannels = ChannelXMLParser.parseChannelXML(parser); } catch (XmlPullParserException e) { e.printStackTrace(); } } finally { if (inputStream != null) { inputStream.close(); } } } }
إذا كنت بحاجة إلى تعديل بيانات وضع EPG بشكل منتظم، ننصحك باستخدام
WorkManager
لتشغيل عملية التحديث أثناء وقت عدم النشاط، على سبيل المثال كل يوم في الساعة 3:00 صباحًا
تشمل الأساليب الأخرى لفصل مهام تحديث البيانات من سلسلة واجهة المستخدم استخدام
صف واحد (HandlerThread
)، أو يمكنك تنفيذ صفك الخاص باستخدام Looper
.
وHandler
صفًا. عرض
العمليات وسلاسل المحادثات للاطّلاع على مزيد من المعلومات
إضافة معلومات رابط التطبيق
يمكن للقنوات استخدام روابط التطبيقات لكي تتيح للمستخدمين إطلاق تطبيق ذي صلة بسهولة. نشاطهم أثناء مشاهدة محتوى القناة. استخدام تطبيقات القناة روابط التطبيقات لتعزيز تفاعل المستخدمين من خلال إطلاق أنشطة تعرض المعلومات ذات الصلة أو المحتوى الإضافي. على سبيل المثال، يمكنك استخدام روابط التطبيقات لإجراء ما يلي:
- توجيه المستخدم لاكتشاف وشراء المحتوى ذي الصلة.
- تقديم معلومات إضافية عن المحتوى الذي يتم تشغيله حاليًا
- ابدأ عرض الحلقة التالية في قسم أثناء عرض محتوى مؤلف من حلقات. السلسلة.
- السماح للمستخدم بالتفاعل مع المحتوى، على سبيل المثال، التقييم أو المراجعة بدون مقاطعة تشغيل المحتوى
يتم عرض روابط التطبيق عندما يضغط المستخدم على اختيار لعرض قائمة التلفزيون أثناء مشاهدة محتوى القناة
عندما ينقر المستخدم على رابط التطبيق، يبدأ النظام نشاطًا باستخدام معرّف موارد منتظم (URI) مقصود يحدده تطبيق القناة. ما زال محتوى القناة يعمل عندما يكون نشاط رابط التطبيق نشطًا يمكن للمستخدم العودة إلى القناة المحتوى بالضغط على رجوع.
تقديم بيانات قناة رابط التطبيق
ينشئ Android TV تلقائيًا رابط تطبيق لكل قناة
باستخدام معلومات من بيانات القناة. لتقديم معلومات حول رابط التطبيق،
التفاصيل التالية في
حقلان (TvContract.Channels
):
COLUMN_APP_LINK_COLOR
- لون التمييز لرابط التطبيق الخاص بهذه القناة. للحصول على مثال على لون التمييز، راجع الشكل 2، وسيلة الشرح 3.COLUMN_APP_LINK_ICON_URI
- معرّف الموارد المنتظم (URI) لرمز شارة التطبيق لرابط التطبيق الخاص بهذه القناة. بالنسبة إلى مثال على رمز شارة التطبيق، انظر الشكل 2، وسيلة الشرح 2.COLUMN_APP_LINK_INTENT_URI
- معرّف الموارد المنتظم (URI) المقصود لرابط التطبيق الخاص بهذه القناة. يمكنك إنشاء عنوان URI يتم استخدام "toUri(int)
" معURI_INTENT_SCHEME
و يمكنك إعادة تحويل عنوان URI إلى الغرض الأصلي باستخدامparseUri()
COLUMN_APP_LINK_POSTER_ART_URI
- معرف الموارد المنتظم (URI) لصورة الملصق المستخدمة كخلفية لرابط التطبيق لهذه القناة للحصول على مثال على صورة الملصق، يُرجى الاطّلاع على الشكل 2، وسيلة الشرح 1.COLUMN_APP_LINK_TEXT
- نص الرابط الوصفي لرابط التطبيق لهذه القناة. مثال وصف رابط التطبيق، شاهد النص في الشكل 2، وسيلة الشرح 3.
إذا لم تحدِّد بيانات القناة معلومات رابط التطبيق، سيجري النظام يؤدي إلى إنشاء رابط تطبيق تلقائي. ويختار النظام التفاصيل التلقائية كما يلي:
- لمعرّف الموارد المنتظم (URI) المقصود
(
COLUMN_APP_LINK_INTENT_URI
), يستخدم النظامACTION_MAIN
نشاط الفئةCATEGORY_LEANBACK_LAUNCHER
، الذي يتم تحديده عادةً في بيان التطبيق. إذا لم يتم تحديد هذا النشاط، يظهر رابط تطبيق لا يعمل - إذا عندما ينقر المستخدم فوقه، لا يحدث شيء. - بالنسبة إلى النص الوصفي
(
COLUMN_APP_LINK_TEXT
)، النظام يستخدم "فتح app-name". إذا لم يتم تحديد معرّف موارد منتظم (URI) صالح لرابط التطبيق، يستخدم النظام الرسالة "لا يتوفر رابط". - للون التمييز
(
COLUMN_APP_LINK_COLOR
), يستخدم النظام لون التطبيق الافتراضي. - لصورة الملصق
(
COLUMN_APP_LINK_POSTER_ART_URI
), يستخدم النظام بانر الشاشة الرئيسية للتطبيق. إذا لم يوفِّر التطبيق بانر، يستخدم النظام صورة تلقائية لتطبيق البث التلفزيوني. - لرمز الشارة
(
COLUMN_APP_LINK_ICON_URI
) و شارة تعرض اسم التطبيق. إذا كان النظام يستخدم أيضًا بانر التطبيق أو صورة التطبيق التلقائية لصورة الملصق، لا يتم عرض أي شارة تطبيق.
يمكنك تحديد تفاصيل رابط التطبيق لقنواتك في
نشاط الإعداد. يمكنك تعديل تفاصيل رابط التطبيق هذه في أي وقت، وبالتالي
إذا كان رابط التطبيق بحاجة إلى أن يتطابق مع تغييرات القناة، يُرجى تحديث التطبيق
تفاصيل الرابط والمكالمة
ContentResolver.update()
حسب الحاجة. لمزيد من التفاصيل حول تحديث
بيانات القناة، راجع تحديث بيانات القناة.