Получение списка приложений в Android

Автор: | 02.11.2017

Android SDK предоставляет много средств для работы с системой. В том числе он позволяет получать список приложений, которые установлены на устройстве. Это может быть полезно, когда нужно получить сведения о сторонних приложениях (размер APK, путь до приложения, имя пакета и т.д.). Например, в наших приложениях получение списка, содержащего сторонние приложения, играет большую роль: в GreenBro с помощью этого списка выводятся сведения о приложениях, а также выполняются различные действия.

В Менеджере системных приложений и APK Extractor же список приложений необходим, чтобы удалять приложения и извлекать APK из приложений соответственно.

В этой статье мы рассмотрим, как можно получать список приложений, установленных на устройстве, а также как происходит установка приложений на устройство.

Класс PackageManager

PackageManager предоставляет API, который фактически управляет установкой, удалением и обновлением приложений. Когда мы устанавливаем файл APK, PackageManager анализирует этот APK и выводит результат.

Получить экземпляр класса PackageManager можно с помощью метода getPackageManager(). PackageManager предоставляет методы для запросов к установленным пакетам и соответствующим разрешениям.

Где хранятся файлы APK на Android?

В зависимости от типа данных, на Androiid файлы могут храниться в следующих местах:

  • Предустановленные и системные приложения (Камера, Браузер и т.д.) хранятся в /system/app/
  • Установленные пользователем приложения хранятся в /data/app/
  • PackageManager создаёт каталог /data/data/<имя пакета>/ для хранения базы данных, файлов с предпочтениями, нативных библиотек и кеша.

Как PackageManager хранит информацию о приложении?

Менеджер пакетов хранит информацию о приложении в трёх файлах, расположенных в /data/system.

packages.xml

Этот XML-файл содержит список разрешений и пакеты\приложения. Он хранит две вещи: разрешения и пакет. Например:

<packages>
  <last-platform-version external="15" internal="15">
  <permission-trees>
    <permissions>
    <item name="android.permission.CHANGE_WIFI_MULTICAST_STATE" package="android" protection="1">
    <item name="android.permission.CLEAR_APP_USER_DATA" package="android" protection="2">
  ...
  </item></item></permissions> 

  <package codepath="/system/app/Contacts.apk" flags="1" ft="136567b3990" it="136567b3990" name="com.android.contacts" nativelibrarypath="/data/data/com.android.contacts/lib" shareduserid="10001" ut="136567b3990" version="15">
  <sigs count="1">
  <cert index="2">
  </cert></sigs>
  </package>
  ...
  <package codepath="/data/app/com.project.t2i-2.apk" flags="0" ft="13a837c2068" it="13a83704ea3" name="com.project.t2i" nativelibrarypath="/data/data/com.project.t2i/lib" userid="10040" ut="13a837c2ecb" version="1">
  <sigs count="1">
  <cert index="3" key="308201e53082014ea0030201020204506825ae300d06092a86
    4886f70d01010505003037310b30090603550406130255533110300e060355040a13074
    16e64726f6964311630140603550403130d416e64726f6964204465627567301e170d31
    32303933303130353735305a170d3432303932333130353735305a3037310b300906035
    50406130255533110300e060355040a1307416e64726f6964311630140603550403130d
    416e64726f696420446562756730819f300d06092a864886f70d010101050003818d003
    08189028181009ce1c5fd64db794fd787887e8a2dccf6798ddd2fd6e1d8ab04cd8cdd9e
    bf721fb3ed6be1d67c55ce729b1e1d32b200cbcfc91c798ef056bc9b2cbc66a396aed6b
    a3629a18e4839353314252811412202500f11a11c3bf4eb41b2a8747c3c791c89391443
    39036345b15b5e080469ac5f536fd9edffcd52dcbdf88cf43c580abd0203010001300d0
    6092a864886f70d01010505000381810071fa013b4560f16640ed261262f32085a51fca
    63fa6c5c46fde9a862b56b6d6f17dd49643086a39a06314426ba9a38b784601197246f8
    d568e349a93bc6af315455de7a8923f40d4051a51e1658ee34aca41494ab94ce978ae38
    609803dfb3004806634e6e78dd0be26fe75843958711935ffc85f9fcf81523ce23c86bc
    c5c7a">
  </cert></sigs>
  <perms>
    <item name="android.permission.WRITE_EXTERNAL_STORAGE">
  </item></perms>
  </package>
  ...
</permission-trees></last-platform-version></packages>

Разрешения хранятся в теге <permissions>. Каждое разрешение имеет три атрибута: name, package и protection. Атрибут name это имя разрешения, которое мы используем в AndroidManifest.xml. Атрибут package указывает на пакет, которому принадлежит разрешение, в большинстве случаев это «android». Атрибут protection указывает на уровень безопасности.

Тег <package> содержит 10 атрибутов и несколько подтегов.

Атрибут Описание
name Имя пакета
codePath Путь установки APK
nativeLibraryPath Нативная библиотека, расположенная по умолчанию в /data/data/<имя пакета>/lib
flag Хранит флаги ApplicationInfo
ft Время в шестнадцатtричном формате
lt Время установки в шестнадцатеричном формате
ut Время последнего обновления в шестнадцатеричном формате
version Код версии из AndroidManifest.xml
sharedUserId Идентификатор пользователя Linux, который будет использоваться совместно с другими приложениями.
userId Идентификатор пользователя Linux

Подтеги же здесь следующие:

  • <sigs> представляет собой информацию о сигнатуре, атрибут count — количество тегов <cert>.
  • <cert> это ключ сертификата, атрибут index представляет собой глобальный индекс сертификата.
  • <perms> содержат разрешения, которые разработчик установил в AndroidManifest.xml

packages.list

Это простой текстовый файл, содержащий имя пакета, идентификатор пользователя, флаги и каталог data.

com.android.launcher 10013 0 /data/data/com.android.launcher
com.android.quicksearchbox 10033 0 /data/data/com.android.quicksearchbox
com.android.contacts 10001 0 /data/data/com.android.contacts
com.android.inputmethod.latin 10006 0 /data/data/com.android.inputmethod.latin

package-stopped.xml

Этот файл содержит список пакетов, которые были остановлены. Остановленные приложения не могут принимать широковещательные сообщения.

<stopped-packages>
<pkg name="com.android.widgetpreview" nl="1"></pkg>
<pkg name="com.example.android.livecubes" nl="1"></pkg>
<pkg name="com.android.gesture.builder" nl="1"></pkg>
<pkg name="com.example.android.softkeyboard" nl="1"></pkg>
</stopped-packages>

Получаем список приложений

Рассмотрим получение списка установленных приложений на примере GreenBro.

При запуске приложения запускается AsyncTask, внутри которого получаем экземпляр PackageManager и затем копируем в список List<ApplicationInfo> все данные об установленных приложениях.

final PackageManager pm = context.getPackageManager();
List<AppInfo> apps = new ArrayList<>();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);

Метод getInstalledApplications() принимает в качестве параметра флаг GET_META_DATA, который определяет, что нам нужные метаданные каждого пакета.

Результатом является список объектов ApplicationInfo для каждого установленного приложения. Класс ApplicationInfo предоставляет подробную информацию о пакете, собранную из тега <application> в AndroidManifest.xml, нам оттуда нужны лишь самые важные данные.

Поэтому в цикле проверяем каждый объект из полученного списка и записывать данные в собственный класс AppInfo, чтобы затем использовать в основном потоке.

for (ApplicationInfo appInfo : packages) {
  PackageInfo packageInfo;
  try {
    packageInfo = pm.getPackageInfo(appInfo.packageName, 0);
    File file = new File(appInfo.publicSourceDir);
    String size = formatFileSize(context, file.length());

    AppInfo newApp =
        new AppInfo(applicationLabel(context, appInfo), appInfo.packageName, appInfo.sourceDir,
            appInfo.publicSourceDir, packageInfo.versionName, packageInfo.versionCode,
            isSystemPackage(packageInfo), size, file.length(), appInfo.dataDir,
            appInfo.nativeLibraryDir, file.lastModified(), packageInfo.firstInstallTime,
            packageInfo.lastUpdateTime, appInfo.enabled);
    apps.add(newApp);
    publishProgress(newApp);
  } catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
  }
}

Здесь с помощью метода getPackageInfo() класса PackageManager мы получаем общую информацию о приложении по заданному имени пакета. После эта информация объединяется с информацией, полученной от getInstalledApplications() и сохраняется в объекте AppInfo со следующими полями:

  • title — название приложения
  • packageName — имя пакета
  • sourceDir — полный путь до APK приложения
  • publicSourceDir — путь до общедоступных частей sourceDir
  • versionName — имя версии
  • isSystem — определяет, является ли приложение системным
  • size — размер приложения (в удобной форме)
  • longSize — размер приложения в long
  • dataDir — полный путь к каталогу data
  • nativeLibraryDir — путь до нативных библиотек
  • modified — дата последнего изменения
  • firstInstallTime — дата установки
  • lastUpdateTime — дата последнего обновления
  • enabled — определяет, включено ли приложение

Чтобы узнать название приложения, можно также воспользоваться PackageManager, как показано ниже.

private String applicationLabel(Context con, ApplicationInfo packageInfo) {
  PackageManager p = con.getPackageManager();
  return p.getApplicationLabel(packageInfo).toString();
}

Проверка же на то, является ли приложение системным, тоже достаточно проста и показана ниже.

private boolean isSystemPackage(PackageInfo pkgInfo) {
  return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
}

В конце работы AsyncTask возвращает результат обратно в основной поток. Вот и всё, мы загрузили себе список всех установленных на устройстве приложений и можем продолжить с ним работу.

Получение списка приложений в Android: 4 комментария

  1. Tim

    Подскажите пожалуйста, в конструкции:
    final PackageManager pm = context.getPackageManager();
    List apps = new ArrayList();
    List packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
    Чем является «context»?

    1. Владимир

      Это локальная переменная, Вы можете передавать контекст из активити или фрагмента

  2. Медоед

    » List packages = pm.getInstalledApplications( »

    а есть ли функция наподобие getRunnedApplications(), которая выдает список запущенных последних приложений?

  3. Lms

    как отличить приложение от сервиса? Проверка на системное приложение не помогает

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *