Делегировать преобразование текста в "плагины" приложений для Android, не известных заранее
Контекст
Наше приложение показывает пользователю флеш-карту HTML.
Мы добавили несколько слоев "фильтров" для удовлетворения различных групп пользователей:
- Чтобы удовлетворить энтузиастов chess, мы конвертируем любой блок
{FEN:rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2}
в таблицу HTML, представляющую шахматную доску с фигурами в правильной позиции.
- Чтобы удовлетворить китайский язык, мы преобразуем
字
в <ruby>字<rt>zì</rt></ruby>
- ...
Оригинальный HTML → Шахматная трансформация → Китайская трансформация →... → Окончательный HTML для отображения
Проблема
Число фильтров растет, что приводит к проблемам:
- Более медленное исполнение
- Более тяжелая загрузка
- Более высокий исходный код для поддержки
- Дополнительные ошибки/сбои
- Бремя обслуживания
Вопрос
Итак, мы хотели бы сделать эти отдельно устанавливаемые приложения.
Например, шахматный + китайский энтузиаст установил бы 3 приложения:
- TheApp
- Плагин TheApp Chess
- TheApp Chinese plugin
TheApp автоматически обнаружит, какие плагины установлены, и вызовите их по очереди (порядок не имеет значения).
Я думал об использовании намерения THEAPPTRANSFORM
, но как получить список приложений с <intent-filter>
для THEAPPTRANSFORM
и вызвать их по очереди?
Скорость является основным требованием. Я читал, что Намерения в 10+ раз медленнее прямых вызовов... Parcelable помощь здесь?
Если это невозможно, есть ли другое решение?
Ответы
Ответ 1
Чтобы узнать, какие приложения имеют широковещательный приемник с фильтром THEAPPTRANSFORM, вы можете использовать ниже код
PackageManager pm = getPackageManager();
Intent intent = new Intent("THEAPPTRANSFORM");
List<ResolveInfo> info = pm.queryBroadcastReceivers(intent, 0);
for (ResolveInfo resolveInfo : info) {
Log.e("apps", "packages = " + resolveInfo.activityInfo.packageName);
}
Ответ 2
Вам нужен динамически установленный плагин, который не является частью вашего приложения. Я думаю, у вас есть несколько вариантов для этого.
Решение 1: Сценарии
Отправьте интерпретатор языка сценариев с вашим приложением. (например, ruby - http://ruboto.org/). Создайте интерфейс для выполнения этих сценариев. Создайте центральную базу данных таких скриптов или загрузите их из внешнего хранилища. Теперь вы можете выполнить эти сценарии и получить требуемый результат.
Решение 2: AIDL
Использовать удаленную службу в приложениях плагина. Предоставьте AIDL третьим сторонам для разработки приложений с удаленной службой с этим AIDL. Такие службы также должны соответствовать установленному вами фильтру намерений. Теперь вы можете использовать packagemanager для поиска таких сервисов, выбрать один и подключиться к нему. Теперь вы можете вызвать все методы AIDL. Это будет взаимодействие между процессами с использованием связующего, для вашего приложения это будет синхронный вызов. (подробнее см. этот вопрос SO - Доступ к удаленному сервису в другом приложении)
Даунсайд к этому подходу заключается в том, что все эти службы должны запускаться, когда ваше приложение запущено, поэтому вам придется обрабатывать запуск/остановку этих служб. Это также повлияет на потребление энергии, если службы работают в фоновом режиме.
Решение 3: широковещательная/приемная система
Сторонние установленные приложения, у которых есть широковещательный приемник с фильтром намерения для пользовательского намерения, определенного вами. Кроме того, ваше приложение должно иметь широковещательный приемник с особым намерением, который плагины могут вызывать с результатом. Теперь, скажем, вы хотите вызвать сторонний плагин для некоторого преобразования, вы должны это сделать:
Используйте packagemanager, чтобы найти все сторонние приложения, соответствующие ваше намеренное намерение. Отправить трансляцию с extradata о преобразование. Обрабатывать преобразование в широковещательном приемнике приложение плагина. После того, как трансформация будет выполнена, отправьте трансляцию с результат в исходное приложение.
Эта опция полностью асинхронна, и для выполнения без каких-либо гарантий может потребоваться любое количество времени.