Мне время от времени приходится решать задачи, связанные с работой с пакетами в Android. В этой статье я приведу несколько сниппетов для решения этих задач.
AndroidManifest
В любом приложении под Android есть файл AndroidManifect.xml
. В нём публикуется вся необходимая системе информация о приложении и его компонентах. Кроме того, при необходимости можно обратиться к системе и получить эти данные. Для этого в SDK существует класс PackageManager
.
Объектная модель
Объектная модель манифеста содержится в пакете android.content.pm
. Обозначу несколько классов:
PackageInfo
- Содержит данные о пакете приложения. Здесь: список активностей, сервисов, разрешений, имя и версия пакета и прочая информация, опубликованная в манифесте.
ComponentInfo
- Базовый класс для хранения информации о различных компонентах приложения: активности (
ActivityInfo
), сервиса (ServiceInfo
), контент-провайдера (ProviderInfo
) ResolveInfo
- Класс для хранения информации об интентах, соответствующих компонентам приложения
PackageManager
Получить экземпляр PackageManager
можно с помощью метода getPackageManager
контекста. Обозначу методы этого класса, которые будут использоваться в статье:
PackageInfo getPackageInfo(String packageName, int flags)
- Возвращает данные об установленном приложении с заданным packageName. Если приложение не установлено, будет выброшено исключение.
List<ResolveInfo> queryIntentActivities(Intent intent, int flags)
- Возвращает список активностей, соответствующих заданному Intent-у.
Проверка существования приложения в системе
Это наиболее часто встречающаяся задача. Нужно узнать, установлено ли в системе приложение с заданным package name.
boolean isPackageInstalled(Context context, String packageName) { PackageManager pm = context.getPackageManager(); boolean available = false; try { pm.getPackageInfo(packageName, 0); available = true; } catch (NameNotFoundException e) { } return available; }
Не самое изящное решение, но единственно возможное.
Запуск приложения
С помощью этой копипасты можно запустить приложение с заданным package name:
boolean startApplication(Context context, String packageName) { Intent intent = new Intent() .setPackage(packageName) .addCategory(Intent.CATEGORY_LAUNCHER) .setAction(Intent.ACTION_MAIN) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); PackageManager pm = activity.getPackageManager(); List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); if (list != null) { for (ResolveInfo ri : list) { intent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name); break; } } else { Log.e(TAG, String.format("Cannot resolve application '%s' activities", packageName)); } try { startActivity(intent); } catch (ActivityNotFoundException ex) { Log.e(TAG, e); } }
Тут дело такое. Мы запускаем приложение при помощи метода startActivity
, и потому обязательно должны указать имя класса активности, который должен быть запущен. Но внутренняя структура приложения может быть нам незнакома. Поэтому мы сначала формируем Intent
, указав ему имя пакета, категорию CATEGORY_LAUNCHER
и экшен ACTION_MAIN
(необходимые значения для главной активности приложения), а потом получаем список всех возможных активностей с помощью вызова метода queryIntentActivities
. В результате либо ничего не будет, либо будет всего одна активность. Имя этой активности мы и зададим как className нашему intent-у. А после этого его и запускать можно.
Проверка наличия Android Market
Бывает, что хочется узнать, установлен ли в системе маркет. Тут возможно два решения:
- По предложенной выше схеме проверить пакет
com.google.process.gapps
. Однако, не могу утверждать, что такое решение будет работать на всех устройствах. - Решение, предложенное на Stackoverflow:Здесь мы пытаемся получить список приложений, обрабатывающих запрос на маркет. Если в этом списке хоть что-то есть — значит, маркет на месте.
boolean isMarketAvailable(Context context) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("market://search?q=foo")); PackageManager pm = context.getPackageManager(); List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); boolean installed = !(list == null || list.isEmpty()); return installed; }
Заключение
Мы кратко разобрали наиболее часто встречающиеся задачи, связанные с работой менеджера пакетов. Исходников не прилагаю, ибо вся полезная копипаста и так в статье.
2 комментария:
>> boolean isPackageInstalled(Context context, String packageName) { ...
>> Не самое изящное решение, но единственно возможное.
На самом деле можно реализовать поиск пакетов с помощью методов
getInstalledPackages (getInstalledpplications) или воспользоваться перебором List'ов, полученных при помощи
queryIntentActivities, queryBroadcastReceivers, queryContentProvider и т.д. Но так, как у Вас короче :)
>>boolean startApplication(Context context, String packageName) { ...
А для запуска приложений, имхо, лучше бы использовать getLaunchIntentForPackage.
P.S. Это я так, просто поумничать:) Удачи!
Отправить комментарий