Статья – перевод вот этой официальной статьи: https://developer.chrome.com/multidevice/android/customtabs Опубликован оригинал был давно, ещё 30 августа 2015, но популярности клиентские табы пока не получили. Лично у меня пока только одно приложение их использует – Talon for Twitter. А между тем это реально удобная вещь, возможности который сильно превышают возможности системного WebView. К тому же эта фишка работает быстрее ВебВью и загружается быстрее Хрома.
Что такое клиентские табы Chrome?
Когда пользователь тапает на URL, разработчики приложений сталкиваются с выбором – запустить браузер или же загрузить данные внутри приложения, например во WebView. Оба варианта – тот ещё выбор: запуск браузера уводит пользователя из приложения, да к тому же им нельзя управлять, а WebView не имеет нормального сквозного взаимодействия с браузером, да ещё добавляет головной боли при его сопровождении.Клиентские табы Chrome дают приложениям значительный контроль над вебом внутри них и, кроме того, делают взаимодействие между данными приложения и веб контентом более тесным, не требуя использования WebView. Клиентские табы Chrome позволяют приложению настроить, как Chrome должен выглядеть и что должен уметь делать. Приложение может изменять такие вещи как:
- Цвет тулбара
- Анимации входа и выхода
- Добавлять собственные действия на тулбар Chrome и дополнительное меню (примечание: речь идёт об overflow menu. Это то самое, которое вываливается при нажатии на три точки, расположенные вертикально)
Вы сами можете протестировать наш пример клиентских табов: GitHub.
Когда мне стоит использовать клиентские табы Chrome вместо WebView?
WebView – это правильный выбор, если данные, которые нужно показать, находятся внутри ваших приложений. Если URL ведёт во вне, то мы рекомендуем использовать клиентские табы по этим причинам:
- Простое внедрение. Нет необходимости писать код для управления запросами, запросами разрешений, управления куками.
- Управление внешним видом:
- Цвет тулбара
- Кнопки действий
- Собственные элементы меню
- Собственные анимации входа/выхода
-
- Осведомлённость о сёрфинге: браузер предоставляет приложению обратные вызовы о действиях, происходящих в нём.
- Оптимизация производительности:
- Предзагрузка браузера в фоне за счёт ресурсов приложения
- Передача подходящего URL в браузер заранее, чтобы он смог предзагрузить данные, увеличив скорость загрузки страницы при обращении к ней
-
- “Выживаемость” приложения: пока браузер находится на переднем плане, он не даёт системе убить приложение, т. к. считается, что это оно на переднем плане.
- Общее (с Chrome) хранилище кук, а также модель управления разрешениями. Пользователю не нужно будет авторизовываться на сайтах, если он на них уже был ранее; не нужно предпринимать разрешения, если они уже запрашивались ранее.
- Если пользователь включал в Chrome сжатие данных, то здесь оно тоже будет работать.
- Синхронизация Автоподстановки между разными устройствами для удобства заполнения форм.
- Простая настройка.
- Быстрый возврат в приложение – одиночный тап.
- Последняя версия браузера доступна в том числе на устройствах под Android 4.4 и ниже (в 5.0 WebView стал обновляемым), в отличие от WebView.
Когда это будет доступно?
Клиентские табы Chrome предоставляет, начиная с версии 45. Т.е. это работает уже у всех, у кого установлен минимум Jellybean. Примечание: Последняя версия для ICS, напомню, была 42. Сейчас на ICS (API lvl15) приходится 2,9% устройств.
Инструкция по внедрению
Полноценный пример доступен по линку https://github.com/GoogleChrome/custom-tabs-client. Он содержит классы для управления UI, подключения к фоновому сервису и защиту от прибивания и для приложения, и для активити клиентского таба. Кроме того в нём есть AIDL файлы, необходимые для подключения к сервису, т.к. те, что содержатся в Cromium репозитории не могут быть использованы в Android Studio напрямую.
Если вы будете следовать инструкциям с этой страницы, то у вас всё получится.
- Настройка UI и взаимодействие с клиентскими табами.
- Ускорение загрузки страницы и защита приложения от прибивания.
Первое делается добавлением дополнительных сведений в интент ACTION_VIEW, отправляемый в Chrome. Второе – подключением к сервису, предоставляемому Хромом.
Замечание. Всё это работает, начиная с Chrome 45;
Включение клиентских табов Chrome
// Using a VIEW intent for compatibility with any other browsers on device. // Caller should not be setting FLAG_ACTIVITY_NEW_TASK or // FLAG_ACTIVITY_NEW_DOCUMENT. String url = ¨https://paul.kinlan.me/¨; Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// Must have. Extra used to match the session. Its value is an IBinder passed // whilst creating a news session. See newSession() below. Even if the service is not // used and there is no valid session id to be provided, this extra has to be present // with a null value to launch a custom tab. private static final String EXTRA_CUSTOM_TABS_SESSION = "android.support.customtabs.extra.SESSION"; Bundle extras = new Bundle; extras.putBinder(EXTRA_CUSTOM_TABS_SESSION, sessionICustomTabsCallback.asBinder() /* Set to null for no session */); intent.putExtras(extras);
Что случится, если у пользователя не установлено подходящих версий Chrome?
Мы используем интент ACTION_VIEW, что означает, что по умолчанию страница будет открыта в системном браузере или в браузере, выбранным пользователем основным. Если у пользователя браузером по умолчанию выбран Chrome, он автоматически отловит EXTRAS и отобразит модифицированный UI. Кроме того возможно, что сторонние браузеры смогут реагировать аналогично и тоже предоставлять модифицированный IU.Тем не менее, как я могу проверить, поддерживает ли Chrome клиентские табы?
Все версии Chrome, поддерживающие клиентские табы, предоставляют сервис (см. ниже “Подключение к сервису”). Для проверки поддержки клиентских табов в Chrome, попробуйте связаться с сервисом. Если удалось, то клиентские табы можно использовать.Настройка цвета адресной строки
Самое важное (и самое простое для внедрения) в клиентских табах – это возможность задать свой цвет адресной строки, чтобы он был таким же, как и в вашем основном приложении.// Extra that changes the background color for the omnibox. colorInt is an int // that specifies a Color. private static final String EXTRA_CUSTOM_TABS_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR"; intent.putExtra(EXTRA_CUSTOM_TABS_TOOLBAR_COLOR, colorInt);
Настройка действия собственной кнопки
Как разработчик, вы имеете полный контроль над кнопками, которые даёте пользователям внутри клиентского таба.
Самое популярное действие – это “Поделиться” или подобное взаимодействие, выполняемое пользователями.
Кнопки действий представляются как пакет с иконкой кнопки и pendingIntent’а, который будет вызван Хромом, если пользователь нажмёт на кнопку. Здесь иконка имеет 24dp в высоту и 24-48 в ширину.
// Key that specifies the Bitmap to be used as the image source for the // action button. private static final String KEY_CUSTOM_TABS_ICON = "android.support.customtabs.customaction.ICON"; // Key that specifies the PendingIntent to launch when the action button // or menu item was tapped. Chrome will be calling PendingIntent#send() on // taps after adding the url as data. The client app can call // Intent#getDataString() to get the url. public static final String KEY_CUSTOM_TABS_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT"; // Optional. Use a bundle for parameters if an the action button is specified. public static final String EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUNDLE_BUTTON"; Bundle actionButtonBundle = new Bundle(); actionButtonBundle.putParcelable(KEY_CUSTOM_TABS_ICON, icon); actionButtonBundle.putParcelable(KEY_CUSTOM_TABS_PENDING_INTENT, pendingIntent); intent.putExtra(EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE, actionButtonBundle);
Настраиваем меню
Меню в Chrome содержит полный набор действий, который пользователь может выполнить в браузере. Однако, далеко не все из них нужны в контексте вашего приложения.
Клиентские табы Chrome всё время имеют три колонки с кнопками “Вперёд”, “Информация о странице” и “Обновить” в верхней части меню и пункты “Найти на странице” и “Открыть в Chrome” в нижней части меню.
Как разработчик, вы можете добавить до трёх своих пунктов меню между верхними кнопками и двумя нижними пунктами.
Меню представляется как массив из совокупностей (сейчас без иконки) текста элемента меню и pendingIntent, который Chrome вызовет по вашему требованию, если пользователь тапнет на этот элемент меню.
// Key for the title string for a given custom menu item public static final String KEY_CUSTOM_TABS_MENU_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE"; // Optional. Use an ArrayList for specifying menu related params. There // should be a separate Bundle for each custom menu item. public static final String EXTRA_CUSTOM_TABS_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS"; ArrayList menuItemBundleList = new ArrayList<>(); // For each menu item do: Bundle menuItem = new Bundle(); menuItem.putString(KEY_CUSTOM_TABS_MENU_TITLE, menuItemTitle); menuItem.putParcelable(KEY_CUSTOM_TABS_PENDING_INTENT, pendingIntent); menuItemBundleList.add(menuItem); intent.putParcelableArrayList(EXTRA_CUSTOM_TABS_MENU_ITEMS, menuItemBundleList);
Настройка собственной анимации входа и выхода
Многие приложения под Android используют собственную анимацию перехода между разными активити. Клиентские табы Chrome не являются исключением. Вы можете задавать свои анимации входа и выхода (т.е. когда пользователь нажимает “Назад”) для сохранения общего стиля анимации во всём приложении.// Optional. Bundle constructed out of ActivityOptions that Chrome will be running when // it finishes CustomTabActivity. If you start the Custom Tab with // a customized animation, you can specify a matching animation when Custom Tab // returns to your app. public static final String EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE"; Bundle finishBundle = ActivityOptions.makeCustomAnimation(context, R.anim.clientEnterAnimResId, R.anim.CustomTabExitAnimResId).toBundle; intent.putExtra(EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE, finishBundle); Bundle startBundle = ActivityOptions.makeCustomAnimation(context, R.anim.CustomTabEnterAnimResId, R.anim.clientExitAnimResId).toBundle; startActivity(intent, startBundle);
Предварительная подготовка Chrome для ускорения загрузки страниц
Обычно, когда вызывается startActivity с заданным ACTION_VIEW Intent, происходит инициализация Chrome и затем обработка URL. Это занимает драгоценное время и негативно сказывается на плавности и общем восприятии поведения. Мы считаем, что пользователи хотят мгновенных результатов по своим запросам, потому сделали в Chrome сервис, к которому можно подключиться приложением и заставить Хром инициализировать движок и нативные компоненты. Также мы экспериментируем с тем, какие возможности предоставлять через сервис и, к примеру, разработчики могут передать Хрому набор веб страниц, которые пользователь может посетить. Хром же выполнит следующие действия:- Заранее разрезолвит DNS основного домена
- Заранее разрезолвит DNS наиболее подходящих ресурсов домена
- Заранее установит подключение к целевому ресурсу, включая HTTPS/TSL
- Подключение к сервису
- Прикрепление колбэка навигации с событием finishSetup, которое будет означать, что страница уже загрузилась
- Вызов warmup из сервиса для запуска Chrome в фоне
- Создание newSession. Эта сессия будет использоваться для всех запросов в API
- Сообщение Хрому, какие страницы пользователь, возможно, пожелает посетить, средствами mayLaunchUrl
- Запуск VIEW Intent с ID сессии
Подключение к сервису Chrome
Если вы не очень хорошо знакомы с тем, как подключаться к сервисам в Android, то для вас есть готовый интерфейс, созданный с AIDL, который автоматически создаст класс прокси для сервиса. AIDL, который определяет сервис, можно найти в нашем примере на GitHab.// Package name for the Chrome channel the client wants to connect to. This // depends on the channel name. // Stable = com.android.chrome // Beta = com.chrome.beta // Dev = com.chrome.dev public static final String CUSTOM_TAB_PACKAGE_NAME = "com.chrome.dev"; // Change when in stable // Action to add to the service intent. This action can be used as a way // generically pick apps that handle custom tabs for both activity and service // side implementations. public static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService"; Intent serviceIntent = new Intent(ACTION_CUSTOM_TABS_CONNECTION); serviceIntent.setPackage(CUSTOM_TAB_PACKAGE_NAME); context.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
Инициализация Chrome
boolean warmup(long flags) Инициализирует процесс браузера и загружает нативные библиотеки. Инициализация происходит асинхронно и значение возвращается, как только запрос может быть принят. Возвращает True в случае успеха. Множественные успешные вызовы также будут возвращать True.Создание новой сессии таба
boolean newSession(ICustomTabsCallback callback)Сессия используется для последующих вызовов ссылок из mayLaunchUrl для установки связи между VIEW интентом и созданным табом. Используемый здесь интерфейс обратного вызова связан с созданной сессией и должен передаваться во все последующие вызовы mayLaunchUrl. Любые изменения для созданной сессии (смотри ниже “Обратный вызов в клиентских табах”) также передаются через этот интерфейс. Возвращает, была ли сессия создана успешно. Множественные вызовы с одинаковым ICustomTabsCallback или нулевым значением возвращают False.
Сообщение Хрому URL, который пользователь, возможно, пожелает открыть
boolean mayLaunchUrl(ICustomTabsCallback sessionCallback, Uri url, Bundle extras,ListotherLikelyBundles)Сообщает браузеру URL, которые потенциально могут быть открыты в будущем. Настоятельно рекомендуем в первую очередь делать вызов метода warmup(). В первую очередь нужно сообщить наиболее вероятный URL. Дополнительно можно передать список вероятных URL. Они будут обработаны с меньшим приоритетом и их нужно отсортировать по уменьшению важности. Дополнительные URL могут быть проигнорированы. Все предыдущие вызовы этого метода будут понижены в приоритете. Возвращает успешность завершения операции.
Обратный вызов подключения в клиентских табах
void onNavigationEvent(int navigationEvent, Bundle extras)Будет вызван, если произойдёт какое-либо событие в клентском табе. “NavigationEvent int” – это одно из шести значений, которые определены для состояний страницы в табе.
/** * Sent when the tab has started loading a page. */ public static final int NAVIGATION_STARTED = 1; /** * Sent when the tab has finished loading a page. */ public static final int NAVIGATION_FINISHED = 2; /** * Sent when the tab couldn't finish loading due to a failure. */ public static final int NAVIGATION_FAILED = 3; /** * Sent when loading was aborted by a user action before it finishes like clicking on a link * or refreshing the page. */ public static final int NAVIGATION_ABORTED = 4; /** * Sent when the tab becomes visible. */ public static final int TAB_SHOWN = 5; /** * Sent when the tab becomes hidden. */ public static final int TAB_HIDDEN = 6;
Использование библиотеки поддержки с клиентской стороны
Смотри пример приложения.FAQ:
- Есть чё для iOS?
-
Нет. Вот этот проект позволит вам интегрировать Chrome в ваше приложение, но совсем другим путём
-
Когда это добро будет доступно на стабильном канале Хрома?
-
Уже давно
-
Где можно задавать вопросы?
-
На stackowerflow с тегом chrome-custom-tabs
Комментариев нет:
Отправить комментарий