Привет, ребята!
Это моя вторая статья про разработку своего проекта. Тем, кто не читал предыдущую статейку: она про то, как из одного места (гугл таблицы) автоматически экспортировать данные в другое (ноушн).
Сегодня я расскажу, как я писал (и проектировал) библиотеку для того, чтобы сторонние приложения могли получать данные, отправляемые моим приложением. Всех заинтересовавшихся прошу под кат.
Вкратце про проект. Есть устройство, которое подключается к смартфону. Есть мое приложение, внутри которого нейросеть распознает данные от устройства и выдает результат. И есть другие приложения, которые хотят получить этот самый результат.
Результат бывает нескольких видов: голые данные с устройства, обработанные данные с устройства, информация о состоянии устройства, информация о правах доступа приложения к данным (например, что пользователь отозвал права доступа к данным устройства). Нужно как-то передавать этот самый результат в другие приложения.
Если вдруг я что-то неправильно поясню по своему коду — вот тут документация к моей библиотеке.
Есть замечательный механизм — Broadcast'ы. Если вкратце — это сообщение от одного приложения другим приложениям. Можно отправить сразу всем, а можно — какому-то определенному.
Чтобы это дело отправлять и принимать, нужно:
Вообще делать из объекта JSON — это не всегда корректно. Можно отправлять через Broadcast штуку, называемую Parcelable, а можно — Serializable. Serializable — это стандартная вещица из Java, Parcelable — аналогичная штука, но оптимизированная для мобильных устройств.
У меня объекты достаточно маленькие. Кроме того, зачастую надо получить именно JSON: я сам написал стороннее приложение, чтобы оно отправляло на сервер сырые данные. Поэтому я выбрал именно «сделать из передаваемого объекта JSON». Возможно, потом я передумаю.
Тут все просто. Есть библиотека Gson, которая чудесно подходит для наших нужд.
Чтобы сделать все круто, переопределим метод toString(). Ну и сделать fromString(), чтобы получить обратно наш объект.
Вот пример такого кода:
Тут мы создаем intent, задаем его действие, кладем объект и отправляем как broadcast.
BroadcastUtils.BROADCAST_GESTURE — это штучка, по которой мы будем фильтровать поступающие broadcast'ы в другом приложении (нужно ли обрабатывать это или не нужно).
Чтобы отправить сообщение конкретному приложению, нужно еще дополнительно задать следующее:
PermissionsFetcher.REFACE_APP — это APPLICATION_ID моего приложения, а ${PermissionsFetcher.REFACE_APP}.receivers.ActionsReceiver — путь до ресивера.
Вот так мы регистрируем ресивер. Если вы регистрируете его, используя контекст приложения — он будет получать broadcast'ы, пока приложение не закрыто. Если используете контекст активити — пока она не закроется.
А вот GesturesReceiver:
Тут я, как видите, получил интент, переделал его обратно в объект и отправил куда-то-там с помощью RxJava.
Вы прочитали статью по проектированию приложений, которые должны взаимодействовать с другими приложениями. Надеюсь, этот опыт вам чем-то поможет.
Для пущего эффекта можно посмотреть исходники моей библиотеки и пример работы с ней и поставить звездочку на случай, если вам когда-нибудь это пригодится: github.com/reface-tech/CodeSpecialApp
Это моя вторая статья про разработку своего проекта. Тем, кто не читал предыдущую статейку: она про то, как из одного места (гугл таблицы) автоматически экспортировать данные в другое (ноушн).
Сегодня я расскажу, как я писал (и проектировал) библиотеку для того, чтобы сторонние приложения могли получать данные, отправляемые моим приложением. Всех заинтересовавшихся прошу под кат.
Часть 1. Проблема
Вкратце про проект. Есть устройство, которое подключается к смартфону. Есть мое приложение, внутри которого нейросеть распознает данные от устройства и выдает результат. И есть другие приложения, которые хотят получить этот самый результат.
Результат бывает нескольких видов: голые данные с устройства, обработанные данные с устройства, информация о состоянии устройства, информация о правах доступа приложения к данным (например, что пользователь отозвал права доступа к данным устройства). Нужно как-то передавать этот самый результат в другие приложения.
Если вдруг я что-то неправильно поясню по своему коду — вот тут документация к моей библиотеке.
Часть 2. Планируем решение
Есть замечательный механизм — Broadcast'ы. Если вкратце — это сообщение от одного приложения другим приложениям. Можно отправить сразу всем, а можно — какому-то определенному.
Чтобы это дело отправлять и принимать, нужно:
- Как-то сделать из передаваемого объекта JSON
- Отправить Broadcast
- Принять Broadcast в другом приложении
- Восстановить передаваемый объект из JSON
Вообще делать из объекта JSON — это не всегда корректно. Можно отправлять через Broadcast штуку, называемую Parcelable, а можно — Serializable. Serializable — это стандартная вещица из Java, Parcelable — аналогичная штука, но оптимизированная для мобильных устройств.
У меня объекты достаточно маленькие. Кроме того, зачастую надо получить именно JSON: я сам написал стороннее приложение, чтобы оно отправляло на сервер сырые данные. Поэтому я выбрал именно «сделать из передаваемого объекта JSON». Возможно, потом я передумаю.
Часть 3. Пилим решение
Пункт 1 и пункт 4. В JSON, а потом обратно
Тут все просто. Есть библиотека Gson, которая чудесно подходит для наших нужд.
Чтобы сделать все круто, переопределим метод toString(). Ну и сделать fromString(), чтобы получить обратно наш объект.
class SecureData(val eeg1: Double?, val eeg2: Double?, date: Date) {
override fun toString(): String {
val gson = Gson()
return gson.toJson(this)
}
companion object {
fun fromString(model: String): SecureData {
val gson = Gson()
return gson.fromJson(model, SecureData::class.java)
}
}
}
Пункт 2. Посылаем объект
Вот пример такого кода:
val intent = Intent()
intent.action = BroadcastUtils.BROADCAST_GESTURE
intent.putExtra(BroadcastUtils.EXTRA_GESTRE, it.toString())
sendBroadcast(intent)
Тут мы создаем intent, задаем его действие, кладем объект и отправляем как broadcast.
BroadcastUtils.BROADCAST_GESTURE — это штучка, по которой мы будем фильтровать поступающие broadcast'ы в другом приложении (нужно ли обрабатывать это или не нужно).
Чтобы отправить сообщение конкретному приложению, нужно еще дополнительно задать следующее:
intent.component = ComponentName(
PermissionsFetcher.REFACE_APP,
"${PermissionsFetcher.REFACE_APP}.receivers.ActionsReceiver"
)
PermissionsFetcher.REFACE_APP — это APPLICATION_ID моего приложения, а ${PermissionsFetcher.REFACE_APP}.receivers.ActionsReceiver — путь до ресивера.
Пункт 3. Получаем объекты
Вот так мы регистрируем ресивер. Если вы регистрируете его, используя контекст приложения — он будет получать broadcast'ы, пока приложение не закрыто. Если используете контекст активити — пока она не закроется.
registerReceiver(GesturesReceiver(), IntentFilter(BroadcastUtils.BROADCAST_GESTURE))
А вот GesturesReceiver:
class GesturesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Timber.i("Received gesture")
val action = BroadcastUtils.reparseGestureIntent(intent)
MainApp.actionSubject.onNext(action)
}
}
Тут я, как видите, получил интент, переделал его обратно в объект и отправил куда-то-там с помощью RxJava.
Часть 4. Заключение
Вы прочитали статью по проектированию приложений, которые должны взаимодействовать с другими приложениями. Надеюсь, этот опыт вам чем-то поможет.
Для пущего эффекта можно посмотреть исходники моей библиотеки и пример работы с ней и поставить звездочку на случай, если вам когда-нибудь это пригодится: github.com/reface-tech/CodeSpecialApp