Самым простым способом коммуникации между двумя приложения на кратчайшей дистанции (скажем, вытянутой руки) мне казалась технология Network Service Discovery Manager. Эта технология очень часто используется при поиске принтеров в рамках wifi сети, например. Если очень кратко (ведь речь в статье о другом), то схема такая: устройство регистрирует сервис, который может быть найден на другом устройстве. В рамках соединения между устройствами может быть передана какая-то минимальная информация. В теории (и отчасти на практике) это казалось идеальным: запуск сервиса на одном устройстве и мгновенное (почти) его получение на другом.
На практике не все оказалось так гладко. Так, например, на устройствах раньше Marshmallow передача данных не поддерживалась, так что пришлось городить огород и находить костыльные решения… Которые впрочем оказались не так востребованы. Кажется, на некоторых wifi роутерах возможность поиска устройств отключена… или не работает по какой-либо другой таинственной причине.
Пришлось вернуться обратно к списку возможных ответов на вопрос “Как передать информацию с одного устройства на другое”. Так как в рамках задачи эти два устройства общаются через сервер, то варианты получились следующие:
- Общение по Bluetooth. Вообще, скорость соединения устройств по блутусу не так скоростна, как допустим NFC, но мне необходима поддержка довольно медленных устройств, так что я отложил этот вариант
- Создание PIN кода на сервере и ввод его на другом устройстве. Этот вариант мне понравился тем, что клавиатура будет работать на любом устройстве, и таких подводных камней, как например при NSD можно избежать. Но это решение потребовало бы усилий не только Android, но и бэкенд разработчика, и как бы я ни был “за” это решение, я его отложил
- Шифрование базовой информации в виде QR / Barcode. В связи с некоторыми задачами в будущем, я решил использовать именно этот вариант.
И снова не без проблем. Оказалось, что QR коды, их генерация и чтение в рамках Android разработки не совсем тривиальная задача. Google предоставил инструмент для чтения кодов в рамках Play Services Vision, но для этого надо иметь актуальные версии play services, установленные на устройствах. Как показал мой опыт работы над библиотекой Vision ранее, это может быть проблемой, поэтому я искал вариант без использования Play Services.
К тому же возможно использование дешевых китайских устройств, где не совсем понятно будут ли установлены гугловские сервисы, поэтому лучше максимально от них дистанцироваться.
Если начать гугление на тему QR коды в андроид приложении, то первое (и практически единственное) решение — это библиотека zxing. Там оказалось не все так просто (не в режиме установил, написал и вперед), а пришлось немного повозиться, поэтому я решил осветить рабочую интеграцию.
Итак, первое, что надо сделать, это добавить зависимость в наш build.gradle
implementation "com.google.zxing:core:${versions.zxing}"
Актуальная версия на момент написания статьи 3.3.0
Создание QR кода легко гуглится
fun create(text: String): Bitmap? {
val writer = QRCodeWriter()
return try {
val bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, 512, 512)
val width = bitMatrix.width
val height = bitMatrix.height
val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
for (x in 0 until width) {
for (y in 0 until height) {
bmp.setPixel(x, y, if (bitMatrix.get(x, y)) Color.BLACK else Color.WHITE)
}
}
bmp
} catch (e: WriterException) {
null
}
}
А вот с чтением QR кода возникли некоторые сложности. Не буду пытать, а сразу приложу рабочий код
fun read(bitmap: Bitmap): String? {
val intArray = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(intArray, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val source = RGBLuminanceSource(bitmap.width, bitmap.height, intArray)
val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
val reader = MultiFormatReader()
return try {
val result = reader.decode(binaryBitmap)
result.text
} catch (e: Exception) {
null
}
}
Ну и рабочий код в Gist, как обычно https://gist.github.com/sashatinkoff/003bc354792871ab971f53cc77b78170#file-qrcode-kt