Привет, ребята!

Это моя вторая статья про разработку своего проекта. Тем, кто не читал предыдущую статейку: она про то, как из одного места (гугл таблицы) автоматически экспортировать данные в другое (ноушн).

Сегодня я расскажу, как я писал (и проектировал) библиотеку для того, чтобы сторонние приложения могли получать данные, отправляемые моим приложением. Всех заинтересовавшихся прошу под кат.

Часть 1. Проблема


Вкратце про проект. Есть устройство, которое подключается к смартфону. Есть мое приложение, внутри которого нейросеть распознает данные от устройства и выдает результат. И есть другие приложения, которые хотят получить этот самый результат.

Результат бывает нескольких видов: голые данные с устройства, обработанные данные с устройства, информация о состоянии устройства, информация о правах доступа приложения к данным (например, что пользователь отозвал права доступа к данным устройства). Нужно как-то передавать этот самый результат в другие приложения.

Если вдруг я что-то неправильно поясню по своему коду — вот тут документация к моей библиотеке.

Часть 2. Планируем решение


Есть замечательный механизм — Broadcast'ы. Если вкратце — это сообщение от одного приложения другим приложениям. Можно отправить сразу всем, а можно — какому-то определенному.

Чтобы это дело отправлять и принимать, нужно:

  1. Как-то сделать из передаваемого объекта JSON
  2. Отправить Broadcast
  3. Принять Broadcast в другом приложении
  4. Восстановить передаваемый объект из 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

Комментарии (0)