Встроить приложение в Android (Сделать приложение системным)
Как сделать обычное приложение на Android системным
Если вы только начали осваивать ОС Android и уже думаете над тем, чтобы внести свои собственные изменения, например сделать приложение системным на Android, то вы попали по адресу.
Сейчас мы разберемся, как встроить пользовательское приложение в Android и сделать его системным. Но сперва давайте же разберемся для чего нужно встраивать программы:
- Создание кастомных прошивок.
- Замена внешнего лаунчера
- Замена встроенных менее функциональных приложений на более усовершенствованные.
- Освободить память для установки других программ
Для того чтобы встроить программу в Android вам понадобится Root права.
Преобразование обычных приложений в системные с утилитой Link2SD
Пишем приложения с поддержкой плагинов для Android. Часть 1
Сделал игру… но там везде реклама!
Приложения с расширяемой функциональностью — обыденная вещь в настольных ОС. Большинство сложных, узкоспециализированных приложений позволяют подключать дополнения в виде плагинов или скриптов. Это удобная, важная и легко реализуемая функция, которая в простейшем случае может быть встроена в приложение с помощью нескольких строк, всего лишь загружающих внешнюю библиотеку. Но как с этим обстоят дела в Android, где каждое приложение замкнуто в свою собственную песочницу, а распространять «просто библиотеки» через маркет нельзя?
Введение
Есть как минимум три способа создать приложение с поддержкой плагинов для Android.
Первый способ заключается в том, чтобы встроить в приложение интерпретатор простого скриптового языка (Lua лучше всего годится на эту роль). Главная фишка этого способа — простота разработки плагинов. Но есть и ряд недостатков:
- Необходимо реализовать биндинги к функциям своего приложения и коллбэки в обратную сторону, что может оказаться совсем не простой задачей.
- Невозможно распространять плагины через маркет, придется либо просить пользователей самостоятельно копировать скрипты в память устройства, либо кодить свой собственный репозиторий и платить за хостинг.
- Производительность скриптов не самая высокая.
- Тебе, скорее всего, придется иметь дело с интерпретатором, написанным на C/C++, и самостоятельно собирать его для разных процессорных архитектур.
В общем, не самый удачный, но имеющий право на существование способ.
Второй способ основан на встроенном в среду исполнения механизме динамической загрузки классов. Он позволяет разбить приложение на множество модулей, которые будут подгружены прямо во время его работы. По сути этот способ очень похож на тот, что используется в приложениях для настольных ОС, и имеет те же недостатки:
- Модули не получится распространять через маркет.
- После загрузки модули становятся частью приложения, а значит, тебе придется самостоятельно ограничивать их права, вводить квоты на время исполнения и написать много другого кода, следящего за поведением модуля и ограничивающего его возможности.
- Необходимо будет не только тщательно продумать API модулей, но и следить за его соблюдением. Система подключит модуль, невзирая на любые несостыковки в API, а попытка вызвать несуществующую функцию или функцию, принимающую другой тип аргумента, приведет к падению всего приложения.
Тем не менее модули могут быть очень полезны при разработке разного рода бэкдоров и троянов (в образовательных целях, естественно), поэтому тему разработки модульных приложений, основанных на прямой загрузке классов, мы все-таки рассмотрим, но в следующий раз. А сегодня поговорим о третьем способе, самом удобном и полностью соответствующем идеологии Android. Это плагины, подключаемые с помощью RPC-механизма Binder.
ОЧЕНЬ Быстрая ЗАРЯДКА на Айфон и Андроид | СКРЫТАЯ ФУНКЦИЯ 2023 года
Другие статьи в выпуске:
Xakep #208. Атака на сигналку
- Содержание выпуска
- Подписка на «Хакер» -60%
Плагины и Binder
Binder — это механизм, с помощью которого в Android реализована система обмена сообщениями и вызова методов между приложениями и системными компонентами. Подробно о Binder я писал в статье, посвященной логированию звонков, однако рассказал только об обмене данными с его помощью. Если же мы хотим применить его для реализации плагинов, нам необходимо разобраться, как использовать возможность удаленного вызова процедур (RPC). Но сначала определимся с архитектурой нашего приложения.
Допустим, у нас есть гипотетическая софтина, к которой нужно прикрутить поддержку плагинов. Каждый плагин должен быть полноценным приложением для Android (с собственным графическим интерфейсом или без, на усмотрение разработчика), так что его тоже можно будет распространять через маркет. Плагины должны поддерживать определенный нами API, с помощью которого приложение сможет вызвать его функции. Приложение должно уметь само находить установленные плагины и добавлять их в список.
С учетом сказанного нам необходимо внести в код приложения следующие изменения:
- Определить API, с помощью которого приложение будет общаться с плагинами.
- Реализовать механизм поиска плагинов и вести их «учет».
API
Самый удобный и простой способ реализации плагинов — в виде сервисов, запускаемых по запросу. Наше приложение будет находить установленные в системе приложения-плагины, в нужные моменты запускать реализованные в них сервисы и вызывать их функции. При этом сервисы будут запущены только тогда, когда они действительно нужны, а система сама позаботится об их завершении и менеджменте ресурсов. Именно так, кстати, работает система плагинов виджета DashClock и многих других приложений.
Вызов функций будет происходить с помощью Binder, а это, как я уже сказал, RPC-механизм, и он требует описания API (интерфейса) с каждой из сторон (приложения и плагинов) с помощью языка AIDL (Android Interface Definition Language). Сам AIDL очень прост, и описание интерфейса на нем почти ничем не отличается от Java. Для нашего примера создадим простой интерфейс, определяющий две функции: run() и name() :
package com.example.plugin interface IPlugin < // Возвращает имя плагина String name(); // Запускает плагин и возвращает результат работы String run(int seconds); >
Создай файл IPlugin.aidl с помощью New → AIDL → AIDL file и помести в него эти строки. Затем выполни Build → Make Project, чтобы Android Studio преобразовал AIDL в обычный код на Java.
Простейший плагин
Теперь реализуем сам плагин. Для этого создаем новый проект (пусть его имя будет com.example.plugin1 ), добавляем в него файл IPlugin.aidl (обрати внимание, что он должен точно совпадать с аналогичным файлом из предыдущего раздела) и файл Plugin.java со следующим содержимым:
Это простейший плагин, который просто засыпает при запуске. Наиболее важная его часть — это метод onBind , который возвращает объект класса Binder, реализующий наш интерфейс IPlugin, в момент подключения к сервису. Другими словами, при подключении к плагину наше приложение получит объект, с помощью которого сможет вызывать определенные в плагине функции name() и run() .
Поиск плагинов
Теперь нам необходимо реализовать систему поиска установленных плагинов. Проще (и правильнее) всего сделать это с помощью интентов, о которых можно прочитать в упомянутой выше статье. Для этого сначала внесем изменения в файл Manifest нашего плагина, добавив в него следующие строки (в раздел application):
Данные строки означают, что сервис Plugin должен быть открыт для доступа извне и «отвечать» на интент com.example.action.PLUGIN , однако нам этот интент нужен вовсе не для этого, а для того, чтобы найти плагин в системе среди сотен установленных приложений.
Сам механизм поиска плагинов реализовать довольно просто. Для этого достаточно обратиться к PackageManager с просьбой вернуть список всех приложений, отвечающих на интент com.example.action.PLUGIN :
PackageManager packageManager = getPackageManager(); Intent intent = new Intent(«com.example.action.PLUGIN»); List list = packageManager.queryIntentServices(intent, 0);
Чтобы с плагинами было удобнее работать, создадим HashMap и поместим в него имена приложений-плагинов в качестве ключей, а имена их сервисов — в качестве значений:
HashMap plugins = new HashMap<>(); if (list.size() > 0) < for (ResolveInfo info : list) < ServiceInfo serviceInfo = info.serviceInfo; plugins.put(serviceInfo.applicationInfo.packageName, serviceInfo.name); >>
Запуск функций плагина
Теперь, когда у нас есть готовый плагин, а приложение умеет его находить, мы можем вызвать его функции. Для этого мы должны подключиться к сервису плагина с помощью bindService , передав ему обработчик подключения, который будет вызван, когда соединение с сервисом установится. В коде все это будет выглядеть примерно так:
IPlugin plugin; // Определяем наш «обработчик» подключения class MyServiceConnection implements ServiceConnection < // Коллбэк, который будет вызван при подключении к сервису public void onServiceConnected(ComponentName className, IBinder boundService ) < // Получаем объект для взаимодействия с сервисом plugin = IPlugin.Stub.asInterface(boundService); // Пробуем вызвать метод run() и логируем его вывод в консоль (это должна быть строка plugin1 done) try < String result = plugin.run(2); Log.d(TAG, «result: » + result); >catch (RemoteException e) <> > // Коллбэк, который будет вызван при потере связи с сервисом public void onServiceDisconnected(ComponentName className) < plugin = null; Log.d(TAG, «onServiceDisconnected» ); >>; // Создаем Intent для вызова сервиса, определенного в приложении com.example.plugin1 ComponentName name = new ComponentName(«com.example.plugin1», plugins.get(«com.example.plugin1»)); Intent i = new Intent(); i.setComponent(name); // Подключаемся к сервису, запуская его в случае необходимости MyServiceConnection myServiceConnection = new MyServiceConnection(); bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE); . // Отключаемся от сервиса unbindService(myServiceConnection);