جعل تطبيقات التلفزيون قابلة للبحث

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

يجب أن يزوِّد تطبيقك Android TV بحقول البيانات التي ينشئ منها نتائج البحث المقترَحة أثناء إدخال المستخدم أحرف في مربّع حوار البحث. لإجراء ذلك، يجب أن يستخدم تطبيقك طريقة عرض موفّر المحتوى الذي يعرض الاقتراحات مع ملف إعداد searchable.xml يصف مقدّم المحتوى ومعلومات مهمة أخرى حول Android TV. وتحتاج أيضًا إلى نشاط يتناول النية التي يتم تنشيطها عندما يختار المستخدم نتيجة بحث مقترحة. يمكنك الاطّلاع على مزيد من التفاصيل في القسم إضافة اقتراحات مخصّصة. في ما يلي توضيح للنقاط الرئيسية لتطبيقات Android TV.

يعتمد هذا الدرس على معرفتك باستخدام البحث في Android ليعرض لك كيفية جعل تطبيقك قابلاً للبحث في Android TV. قبل متابعة هذا الدرس، يجب الاطّلاع على المفاهيم الموضّحة في دليل Search API. راجِع أيضًا تدريب إضافة وظيفة بحث.

تصف هذه المناقشة بعض الرموز من نموذج تطبيق Android Leanback في مستودع GitHub الخاص بـ Android TV.

تحديد الأعمدة

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

تتضمن الفئة SearchManager عدة أعمدة لـ Android TV. يتم وصف بعض الأعمدة الأكثر أهمية أدناه.

القيمة الوصف
SUGGEST_COLUMN_TEXT_1 اسم المحتوى (مطلوب)
SUGGEST_COLUMN_TEXT_2 وصف نصي للمحتوى
SUGGEST_COLUMN_RESULT_CARD_IMAGE صورة/ملصق/غلاف للمحتوى الخاص بك
SUGGEST_COLUMN_CONTENT_TYPE نوع MIME للوسائط
SUGGEST_COLUMN_VIDEO_WIDTH عرض درجة دقة الوسائط
SUGGEST_COLUMN_VIDEO_HEIGHT ارتفاع درجة دقة الوسائط
SUGGEST_COLUMN_PRODUCTION_YEAR سنة إنتاج المحتوى (مطلوبة)
SUGGEST_COLUMN_DURATION المدة بالمللي ثانية من الوسائط (مطلوبة)

يتطلب إطار عمل البحث الأعمدة التالية:

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

قد تحدِّد فئة قاعدة البيانات لتطبيقك الأعمدة على النحو التالي:

لغة Kotlin

class VideoDatabase {
    companion object {
        // The columns we'll include in the video database table
        val KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1
        val KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2
        val KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE
        val KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE
        val KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE
        val KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH
        val KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT
        val KEY_AUDIO_CHANNEL_CONFIG = SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG
        val KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE
        val KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE
        val KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE
        val KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE
        val KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR
        val KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION
        val KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION
        ...
    }
    ...
}

جافا

public class VideoDatabase {
    //The columns we'll include in the video database table
    public static final String KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1;
    public static final String KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2;
    public static final String KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE;
    public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE;
    public static final String KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE;
    public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH;
    public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT;
    public static final String KEY_AUDIO_CHANNEL_CONFIG =
            SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG;
    public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE;
    public static final String KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE;
    public static final String KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE;
    public static final String KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE;
    public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR;
    public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION;
    public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION;
...

عند إنشاء الخريطة من أعمدة "SearchManager" إلى حقول البيانات، عليك أيضًا تحديد _ID لمنح كل صف معرّفًا فريدًا.

لغة Kotlin


companion object {
    ....

    private fun buildColumnMap(): Map<String, String> {
        return mapOf(
          KEY_NAME to KEY_NAME,
          KEY_DESCRIPTION to KEY_DESCRIPTION,
          KEY_ICON to KEY_ICON,
          KEY_DATA_TYPE to KEY_DATA_TYPE,
          KEY_IS_LIVE to KEY_IS_LIVE,
          KEY_VIDEO_WIDTH to KEY_VIDEO_WIDTH,
          KEY_VIDEO_HEIGHT to KEY_VIDEO_HEIGHT,
          KEY_AUDIO_CHANNEL_CONFIG to KEY_AUDIO_CHANNEL_CONFIG,
          KEY_PURCHASE_PRICE to KEY_PURCHASE_PRICE,
          KEY_RENTAL_PRICE to KEY_RENTAL_PRICE,
          KEY_RATING_STYLE to KEY_RATING_STYLE,
          KEY_RATING_SCORE to KEY_RATING_SCORE,
          KEY_PRODUCTION_YEAR to KEY_PRODUCTION_YEAR,
          KEY_COLUMN_DURATION to KEY_COLUMN_DURATION,
          KEY_ACTION to KEY_ACTION,
          BaseColumns._ID to ("rowid AS " + BaseColumns._ID),
          SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID to ("rowid AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID),
          SearchManager.SUGGEST_COLUMN_SHORTCUT_ID to ("rowid AS " + SearchManager.SUGGEST_COLUMN_SHORTCUT_ID)
        )
    }
}

جافا

...
  private static HashMap<String, String> buildColumnMap() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put(KEY_NAME, KEY_NAME);
    map.put(KEY_DESCRIPTION, KEY_DESCRIPTION);
    map.put(KEY_ICON, KEY_ICON);
    map.put(KEY_DATA_TYPE, KEY_DATA_TYPE);
    map.put(KEY_IS_LIVE, KEY_IS_LIVE);
    map.put(KEY_VIDEO_WIDTH, KEY_VIDEO_WIDTH);
    map.put(KEY_VIDEO_HEIGHT, KEY_VIDEO_HEIGHT);
    map.put(KEY_AUDIO_CHANNEL_CONFIG, KEY_AUDIO_CHANNEL_CONFIG);
    map.put(KEY_PURCHASE_PRICE, KEY_PURCHASE_PRICE);
    map.put(KEY_RENTAL_PRICE, KEY_RENTAL_PRICE);
    map.put(KEY_RATING_STYLE, KEY_RATING_STYLE);
    map.put(KEY_RATING_SCORE, KEY_RATING_SCORE);
    map.put(KEY_PRODUCTION_YEAR, KEY_PRODUCTION_YEAR);
    map.put(KEY_COLUMN_DURATION, KEY_COLUMN_DURATION);
    map.put(KEY_ACTION, KEY_ACTION);
    map.put(BaseColumns._ID, "rowid AS " +
            BaseColumns._ID);
    map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " +
            SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
    map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " +
            SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
    return map;
  }
...

في المثال أعلاه، لاحظ الربط بالحقل SUGGEST_COLUMN_INTENT_DATA_ID. وهو الجزء من URI الذي يشير إلى المحتوى الفريد الخاص بالبيانات في هذا الصف - أي الجزء الأخير من URI الذي يصف مكان تخزين المحتوى. يتم ضبط الجزء الأول من عنوان URL، عندما يكون شائعًا لجميع الصفوف في الجدول، في ملف searchable.xml على أنّه السمة android:searchSuggestIntentData، كما هو موضّح في معالجة اقتراحات البحث أدناه.

إذا كان الجزء الأول من عنوان URL مختلفًا في كل صف في الجدول، سيتم ربط هذه القيمة بالحقل SUGGEST_COLUMN_INTENT_DATA. عندما يختار المستخدم هذا المحتوى، فإن الغرض الذي يتم تنشيطه يقدم بيانات الغرض من تركيبة SUGGEST_COLUMN_INTENT_DATA_ID وإما السمة android:searchSuggestIntentData أو قيمة الحقل SUGGEST_COLUMN_INTENT_DATA.

تقديم بيانات اقتراح البحث

نفِّذ مزود المحتوى لعرض اقتراحات عبارات البحث في مربع حوار بحث Android TV. يطلب النظام من مقدِّم المحتوى الحصول على اقتراحات من خلال استدعاء الطريقة query() في كل مرة تتم فيها كتابة حرف. عند تنفيذ query()، يبحث موفّر المحتوى في بيانات الاقتراح ويعرض رمز Cursor الذي يشير إلى الصفوف التي خصصتها للاقتراحات.

لغة Kotlin

fun query(uri: Uri, projection: Array<String>, selection: String, selectionArgs: Array<String>,
        sortOrder: String): Cursor {
    // Use the UriMatcher to see what kind of query we have and format the db query accordingly
    when (URI_MATCHER.match(uri)) {
        SEARCH_SUGGEST -> {
            Log.d(TAG, "search suggest: ${selectionArgs[0]} URI: $uri")
            if (selectionArgs == null) {
                throw IllegalArgumentException(
                        "selectionArgs must be provided for the Uri: $uri")
            }
            return getSuggestions(selectionArgs[0])
        }
        else -> throw IllegalArgumentException("Unknown Uri: $uri")
    }
}

private fun getSuggestions(query: String): Cursor {
    val columns = arrayOf<String>(
            BaseColumns._ID,
            VideoDatabase.KEY_NAME,
            VideoDatabase.KEY_DESCRIPTION,
            VideoDatabase.KEY_ICON,
            VideoDatabase.KEY_DATA_TYPE,
            VideoDatabase.KEY_IS_LIVE,
            VideoDatabase.KEY_VIDEO_WIDTH,
            VideoDatabase.KEY_VIDEO_HEIGHT,
            VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG,
            VideoDatabase.KEY_PURCHASE_PRICE,
            VideoDatabase.KEY_RENTAL_PRICE,
            VideoDatabase.KEY_RATING_STYLE,
            VideoDatabase.KEY_RATING_SCORE,
            VideoDatabase.KEY_PRODUCTION_YEAR,
            VideoDatabase.KEY_COLUMN_DURATION,
            VideoDatabase.KEY_ACTION,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
    )
    return videoDatabase.getWordMatch(query.toLowerCase(), columns)
}

جافا

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
        String sortOrder) {
    // Use the UriMatcher to see what kind of query we have and format the db query accordingly
    switch (URI_MATCHER.match(uri)) {
        case SEARCH_SUGGEST:
            Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri);
            if (selectionArgs == null) {
                throw new IllegalArgumentException(
                        "selectionArgs must be provided for the Uri: " + uri);
            }
            return getSuggestions(selectionArgs[0]);
        default:
            throw new IllegalArgumentException("Unknown Uri: " + uri);
    }
}

private Cursor getSuggestions(String query) {
    query = query.toLowerCase();
    String[] columns = new String[]{
        BaseColumns._ID,
        VideoDatabase.KEY_NAME,
        VideoDatabase.KEY_DESCRIPTION,
        VideoDatabase.KEY_ICON,
        VideoDatabase.KEY_DATA_TYPE,
        VideoDatabase.KEY_IS_LIVE,
        VideoDatabase.KEY_VIDEO_WIDTH,
        VideoDatabase.KEY_VIDEO_HEIGHT,
        VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG,
        VideoDatabase.KEY_PURCHASE_PRICE,
        VideoDatabase.KEY_RENTAL_PRICE,
        VideoDatabase.KEY_RATING_STYLE,
        VideoDatabase.KEY_RATING_SCORE,
        VideoDatabase.KEY_PRODUCTION_YEAR,
        VideoDatabase.KEY_COLUMN_DURATION,
        VideoDatabase.KEY_ACTION,
        SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
    };
    return videoDatabase.getWordMatch(query, columns);
}
...

في ملف البيان الخاص بك، يتلقّى موفّر المحتوى معاملة خاصة. وبدلاً من وضع علامة على النشاط تشير إلى أنّه نشاط، يتم وصفه على أنّه <provider>. يتضمّن الموفِّر السمة android:authorities لإبلاغ النظام بمساحة اسم موفِّر المحتوى. وعليك أيضًا ضبط السمة android:exported على "true" ليتمكّن بحث Android الشامل من استخدام النتائج المعروضة.

<provider android:name="com.example.android.tvleanback.VideoContentProvider"
    android:authorities="com.example.android.tvleanback"
    android:exported="true" />

التعامل مع اقتراحات البحث

يجب أن يتضمن تطبيقك ملف res/xml/searchable.xml لضبط إعدادات اقتراحات البحث. وهي تشمل السمة android:searchSuggestAuthority التي تُعلم النظام بمساحة الاسم لموفّر المحتوى. يجب أن يتطابق هذا مع قيمة السلسلة التي تحدّدها في السمة android:authorities للعنصر <provider> في ملف AndroidManifest.xml.

يجب أن يتضمن تطبيقك تصنيفًا، وهو اسم التطبيق. تستخدم إعدادات بحث النظام هذا التصنيف عند تعداد التطبيقات القابلة للبحث.

يجب أن يتضمّن ملف searchable.xml أيضًا android:searchSuggestIntentAction بالقيمة "android.intent.action.VIEW" لتحديد الإجراء المطلوب من أجل تقديم اقتراح مخصّص. ويختلف هذا عن الغرض من تقديم عبارة بحث، كما هو موضح أدناه. راجِع أيضًا تحديد الإجراء المقصود للتعرّف على طرق أخرى لتوضيح الإجراء المطلوب تنفيذه على الاقتراحات.

بالإضافة إلى الإجراء المطلوب تنفيذه، يجب أن يقدِّم تطبيقك بيانات الغرض التي تحدّدها باستخدام سمة android:searchSuggestIntentData. هذا هو الجزء الأول من عنوان URI الذي يشير إلى المحتوى. فهو يصف جزء URI الشائع لجميع الصفوف في جدول التعيين لذلك المحتوى. ويتم إنشاء جزء معرّف الموارد المنتظم (URI) الفريد لكل صف باستخدام الحقل SUGGEST_COLUMN_INTENT_DATA_ID، كما هو موضّح أعلاه في تحديد الأعمدة. راجِع أيضًا: تعريف بيانات الغرض للتعرّف على طُرق أخرى للإعلان عن بيانات الغرض من أجل الاقتراحات

لاحِظ أيضًا السمة android:searchSuggestSelection=" ?" التي تحدد القيمة التي تم تمريرها كمَعلمة selection لطريقة query() حيث يتم استبدال قيمة علامة الاستفهام (?) بنص طلب البحث.

أخيرًا، عليك أيضًا تضمين السمة android:includeInGlobalSearch مع القيمة "true". إليك مثال على ملف searchable.xml:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint"
    android:searchSettingsDescription="@string/settings_description"
    android:searchSuggestAuthority="com.example.android.tvleanback"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchSuggestIntentData="content://com.example.android.tvleanback/video_database_leanback"
    android:searchSuggestSelection=" ?"
    android:searchSuggestThreshold="1"
    android:includeInGlobalSearch="true">
</searchable>

التعامل مع عبارات البحث

بعد أن يشتمِل مربّع حوار البحث على كلمة تتطابق مع القيمة في أحد أعمدة تطبيقك (الموضّحة في تحديد الأعمدة أعلاه)، يعمل النظام على تنشيط هدف ACTION_SEARCH. يشير النشاط في تطبيقك الذي يعالج المقصد إلى البحث في المستودع عن الأعمدة التي تتضمن كلمة معينة في قيمها، ويعرض قائمة بعناصر المحتوى مع هذه الأعمدة. في ملف AndroidManifest.xml، يمكنك تحديد النشاط الذي يعالج الغرض ACTION_SEARCH على النحو التالي:

...
  <activity
      android:name="com.example.android.tvleanback.DetailsActivity"
      android:exported="true">

      <!-- Receives the search request. -->
      <intent-filter>
          <action android:name="android.intent.action.SEARCH" />
          <!-- No category needed, because the Intent will specify this class component -->
      </intent-filter>

      <!-- Points to searchable meta data. -->
      <meta-data android:name="android.app.searchable"
          android:resource="@xml/searchable" />
  </activity>
...
  <!-- Provides search suggestions for keywords against video meta data. -->
  <provider android:name="com.example.android.tvleanback.VideoContentProvider"
      android:authorities="com.example.android.tvleanback"
      android:exported="true" />
...

يجب أن يصف النشاط أيضًا الإعدادات القابلة للبحث مع الإشارة إلى ملف searchable.xml. لاستخدام مربع حوار البحث العام، يجب أن يصف البيان النشاط الذي يجب أن يتلقى طلبات البحث. يجب أن يصف البيان أيضًا عنصر <provider> ، على النحو الموضح في ملف searchable.xml تمامًا.

رابط لصفحة في تطبيقك في شاشة التفاصيل

إذا ضبطت إعدادات البحث كما هو موضّح في التعامل مع اقتراحات البحث وربطت الحقول SUGGEST_COLUMN_TEXT_1 وSUGGEST_COLUMN_PRODUCTION_YEAR و SUGGEST_COLUMN_DURATION كما هو موضّح في تحديد الأعمدة، يظهر رابط لصفحة في التطبيق لإجراء مشاهدة للمحتوى الخاص بك في شاشة التفاصيل التي يتم تشغيلها عندما يختار المستخدم نتيجة بحث، كما هو موضّح في الشكل 1.

رابط لصفحة في التطبيق في شاشة التفاصيل

الشكل 1. تعرض شاشة التفاصيل رابطًا لصفحة في التطبيق لنموذج "الفيديوهات من Google" (Leanback). Sintel: © copyright Blender Foundation، www.sintel.org.

عندما يختار المستخدم رابط تطبيقك، الذي يشير إليه الزر "متاح على" في شاشة التفاصيل، يبدأ النظام النشاط الذي يعالج ACTION_VIEW (تم ضبطه على android:searchSuggestIntentAction مع القيمة "android.intent.action.VIEW" في ملف searchable.xml).

يمكنك أيضًا إعداد جمهور مخصّص حسب النية بالشراء لبدء نشاطك، ويمكنك توضيح ذلك في نموذج تطبيق Android Leanback في مستودع GitHub الخاص بـ Android TV . تجدر الإشارة إلى أنّ نموذج التطبيق يشغِّل LeanbackDetailsFragment الخاص به لعرض تفاصيل الوسائط المحدَّدة، ولكن عليك بدء النشاط الذي يُشغِّل الوسائط على الفور لحفظ المستخدِم نقرة أخرى أو نقرتَين.

سلوك البحث

يتوفّر البحث في Android TV من الشاشة الرئيسية ومن داخل التطبيق، وتختلف نتائج البحث عن هاتين الحالتين.

البحث من الشاشة الرئيسية

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

تشغيل نتيجة البحث على التلفزيون

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

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

نتائج البحث عن محتوى تلفزيوني

البحث من تطبيقك

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

نتائج البحث الآمن داخل التطبيق على التلفزيون

مزيد من المعلومات

لمعرفة المزيد من المعلومات حول البحث في تطبيق التلفزيون، يمكنك الاطّلاع على نظرة عامة على البحث وإضافة وظيفة بحث.

للحصول على مزيد من المعلومات حول طريقة تخصيص تجربة البحث داخل التطبيق باستخدام `SearchFragment`، يُرجى الاطّلاع على البحث ضمن تطبيقات التلفزيون.