Об Интентах
2015-11-14
Продолжаю хвастаться своими андроидными приложениями.
В своём сдкартопосылательном приложении я изрядно подружился с андроидными интентами. Intent — это, буквально, намерение. Интенты — это основа Андроида как операционной системы. Это способ межпроцессного взаимодействия. Это сообщения, которые приложения или система посылают другим приложениям, а те как-то реагируют.
В Андроид ничего не может произойти без Интента. Система может сообщить всем заинтересованным приложениям, что, например, появилось подключение к Сети. Одно приложение, скажем, Ланчер, в котором мы видим значки всех установленных приложений, может послать Интент другому приложению, с указанием отобразить определённый стартовый экран (в терминологиях Андроида — Активити), что приводит к запуску этого приложения и отображению этого самого экрана. Собственно, только для ответа на некий Интент приложения и могут запускаться.
Интент может содержать конкретное имя конкретного компонента (Активности или других) конкретного приложения. Может содержать URI, указывающий на некие данные других приложений, ресурсов в Сети или даже локальные файлы, с указанием MIME типа этих данных. Может содержать произвольный набор (ассоциативный массив) других данных, так называемые Extra, включая сериализованные объекты. Ну и Интент обязательно содержит действие (Action) и его категорию, которое ожидается быть выполненным на стороне получателя Интента.
Скажем,
запуск программы из Ланчера —
это ACTION_MAIN
в CATEGORY_LAUNCHER
.
Открытие файла или URL —
это ACTION_VIEW
в CATEGORY_DEFAULT
или CATEGORY_BROWSABLE
,
URI и MIME тип того,
что нужно открыть,
явно передаются в Интенте.
Расшарить/поделиться/послать что-то —
это ACTION_SEND
в CATEGORY_DEFAULT
,
а что именно посылается добавляется к Интенту
либо текстом как EXTRA_TEXT
,
либо как URI в EXTRA_STREAM
.
Это всё было бы не так интересно,
если бы приложения не сообщали бы,
какие Интенты они умеют принимать.
Каждое Андроид приложение объявляет в своём
манифесте,
из каких компонентов оно состоит,
и какие Интенты эти компоненты готовы принимать.
Например,
если приложение объявляет,
что у него есть Активность,
которая принимает Интенты с ACTION_MAIN
в CATEGORY_LAUNCHER
,
то значок именно этой Активности
появится в Ланчере,
и именно эта активность будет запущена
при тыкании по значку.
А если такой Активности в приложении нет,
то оно не появится в Ланчере,
и чтобы удалить его,
вам придётся залезть в настройки :)
Но сам Ланчер —
это обычная программа,
и он запрашивает у системы,
какие именно Активности умеют принимать ACTION_MAIN
,
и,
исходя из полученного списка,
рисует свой экран доступных приложений.
Любая другая программа тоже может проделать такой фокус.
Скажем,
запросить,
какие приложения умеют открывать URI,
начинающиеся на http://
.
Это,
в каком-то приближении,
будет список всех установленных в системе браузеров.
Получается,
что в Андроид,
после установки приложения,
всегда известно,
какого рода Интенты этим приложением обрабатываются.
И часто используются Интенты,
не адресованные конкретному приложению,
а,
например,
отсылающие http://
URI любым приложениям,
готовым его принять.
При этом отображается диалог выбора конкретного получателя,
наверняка часто такой видели.
Технически подобный диалог —
просто некоторая Активность,
принадлежащая некоемому системному приложению.
Итак, мои приложения.
Второе по популярности
(двадцать четыре тысячи активных пользователей) —
браузерооткрывательное приложение.
Дело в том,
что почти все
браузеры под Андроид,
естественно,
умеют открывать http://
URL,
а также,
что не всем известно,
открывать и file://
URL.
Поэтому,
если вы сохранили HTML версию какого-нибудь сайта локально,
вы на самом деле можете её открыть в любом удобном браузере и читать.
Но беда в том,
что если открытие http://
прописано у браузеров в манифесте,
то про file://
они типа не знают.
Единственным исключением была Опера.
Получается,
что,
чтобы открыть локальный файл в браузере,
вам приходится вбивать полный file://
URL в адресную строку вручную.
Жутко неудобно.
Функционал вроде есть,
но воспользоваться им нормально не получается.
А ведь нынешние браузеры весьма неплохо отображают картинки и даже видео.
Вот моё приложение и добавляет возможность открывать локальные html и текстовые файлы, а также файлы изображений и видео в любом установленном браузере. Чтобы непосредственно добраться до файла, вам ещё будет необходим какой-нибудь файловый менеджер.
Приложение в своём манифесте заявляет,
что умеет открывать файлы.
Ещё
оно составляет список браузеров в системе,
тех,
кто умеет открывать http://
.
Когда к нему приходит Интент,
оно просто отображает диалог выбора браузера,
либо молча выбирает заранее выбранный браузер,
и перенаправляет Интент браузеру.
Всё.
И пошла игра с Интентами.
Ненавижу сокращённые URL. По ним совершенно не ясно, куда они ведут. А ведь по доменному имени, по нормальному, согласно ЧПУ, пути, часто можно понять больше, чем даже из заголовка статьи. И вот, чтобы делиться из этих наших твиттеров или RSS лент нормальными читабельными URL я создал урлоудлинятельную программу. Между делом оказалось ещё очень удобным удалять всякие незначащие параметры из URL, которые используются исключительно для трекинга рекламных кампаний, но не несут смысла.
Программа получает Интент с ACTION_SEND
.
Извлекает из него расшаренный текст.
Ищет в тексте URL.
Резолвит все редиректы,
пока не получит финальный адрес страницы,
для этого нужен Интернет.
Удаляет из URL параметры,
согласно настройкам.
Заменяет в тексте URL на результат преобразования.
Расшаривает текст далее,
где его можно послать другой программе.
Просто вклиниваемся еще одним шагом
в стандартный процесс расшаривания ссылок.
Похожим образом работает и единственная (ну почти) программа, написанная на заказ — ебаеторговательная программа. Ебай — это, как вы знаете, такой интернет-аукцион. И есть такой, не вполне честный, способ выигрывать торги. Вы натравливаете на лот аукциона, от своего имени, некоего бота, который, за секунды до окончания торгов, внезапно делает ставку чуть-чуть выше текущей максимальной. Это называется sniping.
Так вот, нашлись ребята, которым очень нравился один такой снайперный бот. Только у создателей этого бота не было (и сейчас нет) мобильного приложения. Но зато был мобильный сайт. И вот для этих ребят я написал приложение. Оно получает Интент, которым стандартное приложение Ебая расшаривает ссылку на лот. Ведь это же вполне удобно и безобидно, куда-то ссылку отправить. Приложение находит идентификатор лота в пересылаемом тексте и формирует URL на мобильный сайт снайперного бота с идентификатором лота, чтобы бот сразу начал спайпить данный лот. Ну и формирует новый Интент, на открытие этого сайта. И сайт открывается в браузере. Опять вклиниваемся с процедуру расшаривания ссылки, и получаем новый удобный функционал.
Забавно, чем закончилось текущее существование этого приложения. При очередном обновлении его забанил Гугль в Гуглоплее. Мотивируя это тем, что я использую название и логотип этого самого снайперного бота. Это правда, но у меня было неформальное разрешение на их использование. Формального разрешения авторы бота мне так и не дали, может, не хотят светиться перед Гуглом. А переделать название и лого у меня еще руки не дошли.
Я обожаю PlantUML. Так, что даже захотел иметь возможность писать диаграммы на планшете. Делать полноценный текстовый редактор я не рискнул. Ведь уже есть достойные редакторы, нечего с ними бодаться. Поэтому я снова решил поиграть с Интентами.
Сценарий такой.
Редактируем текст в редакторе.
Когда нужно,
посылаем текст в наше приложение
посредством Интента с ACTION_SEND
.
Приложение формирует из текста диаграммы URL на картинку на plantuml.com.
Скачивает эту картинку.
Открывает картинку в Активности для предварительного просмотра,
откуда её можно переслать или открыть в другом приложении.
Используем Интенты,
чтобы как-то сынтегрироваться с другими приложениями,
которые даже не подозревают,
что с ними интегрируются.
Так получилось плантуэмэльное приложение.
А недавно я задумался о несправедливости.
Почему Интенты для расшаривания (ACTION_SEND
)
и Интенты для открывания (ACTION_VIEW
)
так неравнозначны?
Расшарить текущий документ
(или что там сейчас открыто)
можно почти из любого приложения.
А почему нельзя переоткрыть это же в другом приложении?
Почему нельзя открыть текущую страницу в другом браузере?
А почему,
наоборот,
нельзя послать куда-нибудь ссылку из текущего документа?
Это худо-бедно возможно в некоторых популярных почтовых клиентах и браузерах.
Но обычно ссылка может быть открыта только в этом же приложении.
И я начал делать расшаривательнооткрывательную программу. Она позволяет открывать то, что расшаривается, и расшаривать то, что открывается. На практике, если вы часто кидаете ссылки туда-сюда, оказалось очень удобно. Пока готово на 80%, уже можно пробовать. Пишу на Котлине.