В этом уроке мы рассмотрим менеджер приложений, и увидим какую информацию можно получить о приложении используя его. Также внесем изменения в наше приложение заменив использование менеджера пакетов на менеджер приложений.
Менеджер приложений предоставляет информацию об установленных и запущенных приложениях. Он предоставляет набор функции для получения имени приложения, абсолютного пути к общедоступной папке приложения и т.д.
Для использования функции и типов данных менеджера приложений, необходимо включить следующий заголовочный файл в приложение
#include <app_manager.h>
Стоит отличать менеджер приложений от менеджера пакетов, разница в том что несколько приложений может находиться в одном пакете. То есть пакет это более крупная сущность. Вы можете создать 3 приложения: ui-приложение, виджет-приложение и сервис, а затем объединить их в один пакет, который будет загружаться в магазин приложений.
Если необходимо использовать функции для получения информации о запущенных приложений, не используя функции менеджера приложений, то необходимо включить в проэкт следующий заголовочный файл.
#include <app_context.h>
Наиболее часто используемой функцией является функция для получения всех запущенных приложений на устройстве:
int app_manager_foreach_app_context(app_manager_app_context_cb callback, void *user_data);
Первый параметр - это указатель на обработчик выборки приложений, второй параметр это указатель на данные пользователя. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Давайте рассмотрим обьявления обработчика выборки приложения
typedef bool (*app_manager_app_context_cb) (app_context_h app_context, void *user_data);
Первый параметр - это обьект для получения информации о контексте приложения, второй параметр это указатель на данные пользователя. Функция возвращает логический признак для продолжения перечислинения запущенных приложений (true) или его остановки (false).
Получив указатель на контекст приложения, рассмотрим наиболее часто используемые функции для получения информации.
Для получения идентификатора приложения рассмотрим следующую функцию
int app_context_get_app_id(app_context_h app_context, char **app_id);
Первый параметр - это обьект содержащий контекст запущенного приложения, второй параметр это двойной указатель на идентификатор приложения, который будет заполнен внутри функции. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки. Стоит отметить, что после вызова функции и завершения работы со строкой содержащей идентификатор приложения необходимо освождать выделенную под нее память.
Рассмотрим интересную функцию для получения идентификатора процесса приложения.
int app_context_get_pid(app_context_h app_context, pid_t *pid);
Первый параметр - это обьект содержащий контекст запущенного приложения, второй параметр это указатель на идентификатор процесса, который будет заполнен внутри функции. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Приведем перечень еще нескольких функций для получения информации о запущенных приложениях.
Чтобы получить информацию о пакете к которому принадлежит запущеное приложение, необходимо вызвать следующую функцию
int app_context_get_package(app_context_h app_context, char **package);
Первый параметр - это обьект содержащий контекст запущенного приложения, второй параметр это двойной указатель на идентификатор пакета, который будет заполнен внутри функции. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Также необходимо освобождать память выделенную под строку после завершения работы с ней.
Следущая функция используется если нам необходимо проверить завершена ли работа приложения.
int app_context_is_terminated(app_context_h app_context, bool *terminated);
Первый параметр - это обьект содержащий контекст приложения, второй параметр это указатель на логический признак завершения приложения, который будет заполнен внутри функции. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Тут стоит заметить один важный момент, т.к. данная функция исользуется на протяжении работы приложения, и если указатель на контекст получен в обработчике выборки, то необходимо клонировать его вызвав следующую функцию
int app_context_clone(app_context_h *clone, app_context_h app_context);
Первый параметр - это указатель на обьект в который будет скопирован контекст запущенного приложения, второй параметр это обьект который будет скопирован. Функция возвращает код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Для удаления скопированного обьекта контекста запущеного приложения рассмотрим следующую функцию
int app_context_destroy(app_context_h app_context);
Функция принимает единственный параметр - удаляемый обьект.
Функция также возвращает код 0 в случае успешного выполнения, и отрицательно число в случае ошибки.
При необходимости использования функций для получения информации об установленных приложениях, не используя при этом функционал менеджера пакетов, необходимо включить в проэкт следующий заголовочный файл
#include <app_info.h>
Количество функций для получения информации об установленых приложениях, немного больше чем для запущенных приложениях. Давайте рассмотрим основные из них.
Для выборки всех установленных приложений на устройстве рассмотрим следующую функцию
int app_manager_foreach_app_info(app_manager_app_info_cb callback, void *user_data);
Первый параметр - это указатель на обработчик выборки приложений, второй параметр - это указатель на данные пользователя.
Рассмотрим обьявление обработчика выборки
typedef bool (*app_manager_app_info_cb) (app_info_h app_info, void *user_data);
Первый параметр - это обьект необходимый для получения информации о приложении, второй параметр это указатель на данные пользователя которые мы задавали при регистрации обработчика. Функция возвращает логический признак для продолжения обработки установленных приложений.
Теперь приведем перечень найболее полезных функций для получение информации о приложении. Так как набор и типы параметров в этих функциях одинаковые, то описаниие параметров опишем ниже после перечисления всех функций.
Следующая функция необходима для получения идентификатора приложения
int app_info_get_app_id(app_info_h app_info, char **app_id);
Следующая функция необходима для получения названия приложения
int app_info_get_label(app_info_h app_info, char **label);
Следующая функция необходима для получения абсолютного пути к иконке приложения
int app_info_get_icon(app_info_h app_info, char **path);
Следующая функция необходима для получения названия пакета, к которому принадлежит приложение
int app_info_get_package(app_info_h app_info, char **package);
Следующая функция необходима для получения типа приложения (нативное или веб приложение)
int app_info_get_type(app_info_h app_info, char **type);
Первый параметр перечисленных функций это обьект для получения информации о приложении, второй параметр это двойной указатель на строку, которая будет заполнена внутри функции. Надо не забывать удалять выделенные строки.
Теперь перечислим функции которые носят логический характер информации о приложении
Следующая функция необходима для проверки имеет ли приложение графический пользовательский интерфейс
int app_info_is_nodisplay(app_info_h app_info, bool *nodisplay);
Следующая функция необходима для проверки является ли приложение предустановленным
int app_info_is_preload(app_info_h app_info, bool *preload);
Первый параметр перечисленных функций это указатель на структуру о приложении, второй параметр это указатель на логическую переменную.
Давайте перейдем к практике, добавив выше перечисленные функции в наше приложение и результат их работы выведем в окно лога.
Добавим в проект заголовочный файл для использования функций и типов данных менеджера приложений.
#include <app_manager.h>
Добавим вызов функции для регистрации обработчика выборки запущенных приложений вместо созданной в прошлом уроке package_manager_foreach_package_info().
static bool
_app_create_cb(void *data)
{
...
app_manager_foreach_app_context(_app_manager_app_context_cb, NULL);
...
}
Ну и реализуем сам обработчик выборки запущенных приложений, и вызовем внутри функции для получения идентификатора приложения и идентификатора процесса.
static bool
_app_manager_app_context_cb(app_context_h app_context, void *user_data)
{
char *app_id = NULL;
pid_t pid;
app_context_get_app_id(app_context, &app_id);
app_context_get_pid(app_context, &pid);
dlog_print(DLOG_INFO, "lesson26", "ID приложения: %s", app_id);
dlog_print(DLOG_INFO, "lesson26", "ID процесса: %d", pid);
free(app_id);
return true;
}
Запустим приложение и откроем окно логирования. В нем мы увидим список идентификаторов запущенных приложений и идентификаторы процесса
Теперь добавим рассмотренные выше функции получения информации о приложениях в наш проэкт.
Удалим все функции и обработчики добавленные в прошлом уроке связанные с пакетным менеджером и добавленные выше функции, связанные с запущенными приложениями, будем добавлять только информацию о установленных приложениях.
Изменим название нашей структуры содержащую информацию о приложении, и добавим в нее одно поле содержащее идентификатор приложения, он нам понадобится в следующем уроке.
Также необходимо удалить в этой структуре поле char *version, содержавшее версию пакета, а также удалить освобождение памяти для этого уже не существующего поля в функции _app_terminate_cb().
typedef struct _Application_Info {
char *label;
char *path_icon;
char *app_id;
} Application_Info;
Необходимо во всем проекте заменить название структуры Install_Package_Info на Application_Info, для успешной компиляции.
Теперь вместо функции выборки запущенных приложений, вызовем функцию для регистрации выборки установленных приложений.
static bool
_app_create_cb(void *data)
{
...
app_manager_foreach_app_info(_app_manager_app_info_cb, ui);
...
}
Удалим предыдущий обработчик _app_manager_app_context_cb() во избежание получения предупреждения о неиспользуемых функциях от компилятора.
Теперь реализуем обработчик выборки приложений. Внутри обработчика мы выведем в лог имя приложения, идентификатор приложения, абсолютный путь к иконке и идентификатор пакета. Но при этом будем добавлять в наш список только те приложения у которых есть пользовательский графический интерфейс (ui-приложения).
static bool
_app_manager_app_info_cb(app_info_h app_info, void *user_data)
{
UIData *ui = user_data;
Application_Info *application_info = calloc(1, sizeof(Application_Info));
if (!application_info) return false;
memset(application_info, 0x0, sizeof(Application_Info));
app_info_get_app_id(app_info, &(application_info->app_id));
app_info_get_label(app_info, &(application_info->label));
app_info_get_icon(app_info, &(application_info->path_icon));
bool is_nodisplay = false;
app_info_is_nodisplay(app_info, &is_nodisplay);
if (!is_nodisplay)
ui->list_package = eina_list_append(ui->list_package, application_info);
char *str_app_info = NULL;
app_info_get_type(app_info, &str_app_info);
dlog_print(DLOG_INFO, "lesson26", "Тип приложения: %s", str_app_info);
free(str_app_info);
str_app_info = NULL;
app_info_get_package(app_info, &str_app_info);
dlog_print(DLOG_INFO, "lesson26", "ID пакета: %s", str_app_info);
free(str_app_info);
dlog_print(DLOG_INFO, "lesson26", "Название: %s", application_info->label);
dlog_print(DLOG_INFO, "lesson26", "Путь к иконке: %s", application_info->path_icon);
dlog_print(DLOG_INFO, "lesson26", "ID приложения: %s", application_info->app_id);
return true;
}
И последнее, что нам необходимо сделать для успешного запуска приложения - удалить вызов функции для установки строки версии в качестве дополнительного текста в элемент в функции создания rotary selector.
Удаляем следующий вызов.
eext_rotary_selector_item_part_text_set(item,
"selector,sub_text",
install_package_info->version);
Запустим приложение. У нас получилось следующее на устройстве Samsung Gear S3.
Как видим в качестве элементов виджета отображаются установленные приложения имеющие графический интерфейс, а если мы откроем окно логирования, то увидем большой перечень всех установленных приложений и информацию о них
Рассмотрим перечень наиболее полезных функций менеджера приложений, на которые стоит обратить внимание.
Следующая функция необходима для получение идентификатора приложения, используя идентификатор запущеного процесса
int app_manager_get_app_id(pid_t pid, char **app_id);
Первый параметр это идентификатор процесса (полученный двумя путями или с использованием функции с использованием контекста запущеного приложения или с использованием вызова системной функции), второй параметр это двойной указатель на строку содержащую идентификатор приложения, который надо не забывать освобождать. Функции возвращают код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Для получения абсолютного пути к поддиректориям общедоступной директории приложения рассмотрим следующие функции.
Следующая функция необходима для получание абсолютного пути к общедоступной директории с данными shared/data вашего проекта
int app_manager_get_shared_data_path(const char *app_id, char **path);
Следующая функция необходима для получение абсолютного пути к общедоступной директории с ресурсами shared/res вашего проекта
int app_manager_get_shared_resource_path(const char *app_id, char **path);
Следующая функция необходима для получение абсолютного пути к общедоступной доверенной директории shared/trusted вашего проекта
int app_manager_get_shared_trusted_path(const char *app_id, char **path);
Первый параметр это указатель на строку содержащий идентификатор приложения, второй параметр это двойной указатель на абсольютный путь к запрашиваемой директории, строку потом необходимо будет освободить. Функции возвращают код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Для того чтобы проверить запущено ли приложение имея его индитификатор, необходимо вызвать следующую функцию
int app_manager_is_running(const char *app_id, bool *running);
Первый параметр это указатель на идентификатор приложения, второй это указатель на булевую переменную содержащуюю статус приложения. Функции возвращают код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Еще очень не мало важные фунции.
Первая из них возобновляет работу приложения
int app_manager_resume_app(app_context_h app_context);
Входной параметр этой функции это обьект содержащий контекст запущенного приложения. Функции возвращают код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Вторая функция, открывает по указанному идентификатору приложение
int app_manager_open_app(const char *app_id);
Входной параметр это указатель на строку содержащий уникальный идентификатор приложения. Функции возвращают код 0 в случае успешного выполнения, и отрицательное число в случае ошибки.
Вы можете скачать полный исходный код урока здесь WearLesson026.