Android TV از رابط جستجوی Android برای بازیابی اطلاعات محتوا از برنامه های نصب شده و ارائه نتایج جستجو به کاربر استفاده می کند. دادههای محتوای برنامه شما را میتوان با این نتایج گنجاند تا به کاربر امکان دسترسی فوری به محتوای برنامه شما را بدهد.
برنامه شما باید Android TV را با فیلدهای داده ارائه کند که از آن Android TV میتواند نتایج جستجوی پیشنهادی را ایجاد کند، زیرا کاربر نویسههایی را در گفتگوی جستجو وارد میکند. برای انجام این کار، برنامه شما باید یک Content Provider اجرا کند که پیشنهادات را به همراه یک فایل پیکربندی searchable.xml
ارائه دهد که ارائهدهنده محتوا و سایر اطلاعات حیاتی را برای Android TV توصیف میکند. همچنین به فعالیتی نیاز دارید که هدفی را که هنگام انتخاب کاربر یک نتیجه جستجوی پیشنهادی ایجاد میشود، کنترل کند. برای جزئیات بیشتر، به افزودن پیشنهادهای جستجوی سفارشی مراجعه کنید. این راهنما نکات اصلی ویژه برنامه های Android TV را پوشش می دهد.
قبل از خواندن این راهنما، مطمئن شوید که با مفاهیم توضیح داده شده در راهنمای جستجوی API آشنا هستید. همچنین، قابلیت افزودن جستجو را مرور کنید.
کد نمونه در این راهنما از برنامه نمونه Leanback آمده است.
ستون ها را شناسایی کنید
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 مطابقت دارد، سیستم یک پیوند عمیق به برنامه شما در نمای جزئیات محتوا همراه با پیوندهایی به برنامههای دیگر ارائهدهندگان ارائه میکند. . این مورد در پیوند عمیق به برنامه شما در بخش صفحه جزئیات بیشتر مورد بحث قرار گرفته است.
کلاس پایگاه داده برنامه شما ممکن است ستون ها را به صورت زیر تعریف کند:
کاتلین
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
نیز مشخص کنید تا به هر ردیف یک شناسه منحصر به فرد بدهید.
کاتلین
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، جایی که محتوا ذخیره میشود. قسمت اول URI، زمانی که برای همه ردیفهای جدول مشترک است، در فایل searchable.xml
بهعنوان ویژگی android:searchSuggestIntentData
تنظیم میشود، همانطور که در بخش پیشنهادات جستجوی Handle توضیح داده شده است.
اگر قسمت اول URI برای هر ردیف در جدول متفاوت است، آن مقدار را با فیلد SUGGEST_COLUMN_INTENT_DATA
ترسیم کنید. وقتی کاربر این محتوا را انتخاب میکند، هدفی که شلیک میشود، دادههای هدف را از ترکیب SUGGEST_COLUMN_INTENT_DATA_ID
و ویژگی android:searchSuggestIntentData
یا مقدار فیلد SUGGEST_COLUMN_INTENT_DATA
ارائه میکند.
داده های پیشنهادی جستجو را ارائه دهید
برای بازگرداندن پیشنهادات عبارت جستجو به گفتگوی جستجوی Android TV، یک ارائه دهنده محتوا پیاده کنید. سیستم با فراخوانی query()
هر بار که یک حرف تایپ میشود، از ارائهدهنده محتوای شما برای پیشنهادات درخواست میکند. در اجرای query()
ارائهدهنده محتوای شما دادههای پیشنهادی شما را جستجو میکند و Cursor
را برمیگرداند که به ردیفهایی که برای پیشنهادات تعیین کردهاید اشاره میکند.
کاتلین
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"
تنظیم کنید تا جستجوی جهانی اندروید بتواند از نتایج برگردانده شده از آن استفاده کند.
<provider android:name="com.example.android.tvleanback.VideoContentProvider" android:authorities="com.example.android.tvleanback" android:exported="true" />
به پیشنهادات جستجو رسیدگی کنید
برنامه شما باید شامل یک فایل res/xml/searchable.xml
برای پیکربندی تنظیمات پیشنهادات جستجو باشد.
در فایل res/xml/searchable.xml
، ویژگی android:searchSuggestAuthority
را وارد کنید تا فضای نام ارائهدهنده محتوای خود را به سیستم بگویید. این باید با مقدار رشته ای که در ویژگی android:authorities
عنصر <provider>
در فایل AndroidManifest.xml
خود مشخص کرده اید مطابقت داشته باشد.
همچنین یک برچسب ، که نام برنامه است، اضافه کنید. تنظیمات جستجوی سیستم هنگام شمارش برنامه های قابل جستجو از این برچسب استفاده می کند.
فایل searchable.xml
همچنین باید حاوی android:searchSuggestIntentAction
با مقدار "android.intent.action.VIEW"
باشد تا اکشن قصد برای ارائه یک پیشنهاد سفارشی تعریف شود. این با اقدام قصد برای ارائه یک عبارت جستجو که در بخش زیر توضیح داده شده است متفاوت است. برای سایر روشهای اعلام کنش قصد برای پیشنهادات، به اعلام اقدام قصد مراجعه کنید.
همراه با کنش intent، برنامه شما باید دادههای intent را نیز ارائه کند که با ویژگی android:searchSuggestIntentData
مشخص میکنید. این اولین قسمت از URI است که به محتوا اشاره می کند، که بخشی از URI مشترک در همه ردیف های جدول نگاشت آن محتوا را توصیف می کند. بخشی از URI که برای هر ردیف منحصر به فرد است با فیلد SUGGEST_COLUMN_INTENT_DATA_ID
ایجاد می شود، همانطور که در بخش Identify columns توضیح داده شده است. برای سایر روشهای اعلام دادههای هدف برای پیشنهادها، به اعلام دادههای قصد مراجعه کنید.
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>
عبارات جستجو را مدیریت کنید
به محض اینکه در گفتگوی جستجو کلمه ای وجود داشته باشد که با مقدار یکی از ستون های برنامه شما مطابقت داشته باشد، همانطور که در بخش Identify columns توضیح داده شده است، سیستم قصد 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
توضیح داده شده است، توصیف کند.
پیوند عمیق به برنامه شما در صفحه جزئیات
اگر پیکربندی جستجو را همانطور که در بخش پیشنهادات جستجوی Handle توضیح داده شده است تنظیم کرده باشید و فیلدهای SUGGEST_COLUMN_TEXT_1
، SUGGEST_COLUMN_PRODUCTION_YEAR
و SUGGEST_COLUMN_DURATION
را همانطور که در قسمت شناسایی ستونها توضیح داده شده است، نقشهبرداری کردهاید، صفحه پیوند عمیق را برای مشاهده جزئیات محتوا در صفحه نمایش مشاهده میکنید. هنگامی که کاربر یک نتیجه جستجو را انتخاب می کند راه اندازی می شود:
هنگامی که کاربر پیوندی را برای برنامه شما انتخاب می کند که با دکمه **در دسترس روشن** در صفحه جزئیات مشخص می شود، سیستم فعالیتی را که مجموعه ACTION_VIEW
را به عنوان android:searchSuggestIntentAction
با مقدار "android.intent.action.VIEW"
مدیریت می کند" راه اندازی می کند. "android.intent.action.VIEW"
در فایل searchable.xml
.
همچنین می توانید یک قصد سفارشی برای راه اندازی فعالیت خود تنظیم کنید. این در برنامه نمونه Leanback نشان داده شده است. توجه داشته باشید که برنامه نمونه LeanbackDetailsFragment
خود را راه اندازی می کند تا جزئیات رسانه انتخاب شده را نشان دهد. در برنامه های خود، فعالیتی را که رسانه را پخش می کند، بلافاصله اجرا کنید تا کاربر یک یا دو کلیک دیگر ذخیره کند.
رفتار جستجو
جستجو در Android TV از صفحه اصلی و از داخل برنامه شما در دسترس است. نتایج جستجو برای این دو مورد متفاوت است.
از صفحه اصلی جستجو کنید
هنگامی که کاربر از صفحه اصلی جستجو می کند، اولین نتیجه در یک کارت موجودیت ظاهر می شود. اگر برنامههایی وجود دارند که میتوانند محتوا را پخش کنند، پیوندی به هر کدام در پایین کارت ظاهر میشود:
نمیتوانید برنامهای را بهصورت برنامهریزی در کارت نهاد قرار دهید. برای گنجاندن به عنوان گزینه پخش، نتایج جستجوی برنامه باید با عنوان، سال و مدت محتوای جستجو شده مطابقت داشته باشد.
ممکن است نتایج جستجوی بیشتری در زیر کارت موجود باشد. برای دیدن آنها، کاربر باید کنترل از راه دور را فشار داده و به پایین اسکرول کند. نتایج برای هر برنامه در یک ردیف جداگانه ظاهر می شود. شما نمی توانید ترتیب ردیف را کنترل کنید. برنامههایی که از کنشهای ساعت پشتیبانی میکنند ابتدا فهرست میشوند.
از برنامه خود جستجو کنید
کاربر همچنین می تواند با راه اندازی میکروفون از کنترل از راه دور یا صفحه بازی، جستجو را از داخل برنامه شما آغاز کند. نتایج جستجو در یک ردیف در بالای محتوای برنامه نمایش داده می شود. برنامه شما نتایج جستجو را با استفاده از ارائه دهنده جستجوی جهانی خود ایجاد می کند.
بیشتر بدانید
برای کسب اطلاعات بیشتر درباره جستجوی یک برنامه تلویزیونی، ادغام ویژگیهای جستجوی Android در برنامه خود و افزودن قابلیت جستجو را بخوانید.
برای اطلاعات بیشتر درباره نحوه سفارشی کردن تجربه جستجوی درون برنامه با SearchFragment
، جستجو در برنامه های تلویزیون را بخوانید.