Без GPS и геолокации: узнаём местоположение пользователя, используя сим-карту
Сегодня огромное количество приложений пытается получить информацию о местоположении устройства пользователя.
Но и вам как разработчику эта информация также может понадобиться. Например, вы разрабатываете приложение новой социальной сети. В специальном разделе пользователи будут просматривать популярные публикации. А хитрый алгоритм настолько хитрый, что подсовывает свои рекомендации, основываясь на местоположении устройства пользователя.
Получить данные о местоположении устройства особого труда не составит, и после некоторой обработки они будут использоваться хитрым алгоритмом.
Но параноик внимательный читатель спросит: "Погодите-ка... А что если пользователь будет отдавать приложению фиктивные данные о своём местоположении?"
И будет прав! Если пользователи включат фиктивное местоположение, описанный функционал вашего приложения должным образом работать не будет. Хитрый алгоритм будет думать, что он всех перехитрил, но по факту пользователи из Индии увидят бесполезный для них контент, к примеру, на китайском языке от пользователей "из Китая".
Итог: киллер-фича вашего приложения не работает.
Может, есть выход?
Да, выход есть. Конкретно в нашем случае нет необходимости знать точное местоположение пользователя. Достаточно знать район/город, где он находится.
Чтобы узнать примерное местоположение пользователя, нужно узнать местоположение базовой станции оператора сотовой связи, к которой подключен пользователь. А для этого нужно получить кое-какие данные с SIM-карты на устройстве пользователя.
Кстати, известное приложение TikTok так и делает: оно получает данные с SIM-карты и определяет местоположение пользователя, предотвращая подделку местоположения.
Как мы к этому пришли?
Мы разрабатывали продукт, который сильно зависел от местоположения пользователя, и подумали: "Что делать, если определение местоположения будет недоступно из-за сбоя на устройстве, плохой погоды или если пользователь предоставит фиктивное местоположение?"
Мы тщательно изучили эти сценарии со всеми аспектами и решили использовать данные SIM-карты для получения информации о базовой станции и её координатах. Это позволило нам определить местоположение пользователя с помощью триангуляции. Качество данных, которое мы получили нас устроило.
В этой статье я опишу способ получения информации о местоположении базовой станции, к которой подключен пользователь. Для этого нам понадобится смартфон с SIM-картой.
Примечание: не имеет значения, включен GPS или выключен. В описанном процессе он не используется.
Начнём, пожалуй
Прежде всего, нам нужно API для доступа к информации о геолокации. Мне известно два:
Google Geolocation API — удобный API, но требуется подключенная платёжная учётная запись для вашего проекта;
OpenCellID от Unwiredlabs — простой в использовании API, крупнейшая в мире открытая база данных вышек сотовой связи.
Перейдите по ссылке выше, зарегистрируйтесь и получите API-ключ. И почитайте документацию, там всё подробно описано.
Как же оно всё работает?
Ваше приложение должно сделать запрос к API, отправив такие данные:
{
"token": "Your_API_Token",
"radio": "gsm",
"mcc": 310,
"mnc": 404,
"cells": [{
"lac": 7033,
"cid": 17811
}],
"address": 1
}
Описание полей для ясности:
token
— ваш API-ключ;radio
— тип сети, например GSM, LTE и пр.;mcc
— Mobile Country Code, уникальный идентификатор сотового оператора;mnc
— Mobile Network Code, код мобильной сети. В комбинации с MCC является уникальным идентификатором сотового оператора;lac
— Location Area Code;cid
— Cell ID.
Ответ вы получите в таком формате:
{
"status": "ok",
"balance": 100,
"lat": 39.573726,
"lon": -105.005387,
"accuracy": 730,
"address": "1289-1425 West Mineral Avenue, Littleton, CO 80120, USA"
}
То, что нужно. Приступим к реализации.
Реализация
Запустите Android Studio. Создайте новый проект или клонируйте/импортируйте этот.
Создаём модель запроса
Она будет использоваться для запроса к API:
Создаём модель ответа
Она будет использоваться при получении ответа от API:
Создаём сервис
Он используется для взаимодействия с API:
В приложении мы использовали Retrofit. Полную реализацию здесь я приводить не буду, но исходный код доступен. Мы реализовали ViewModel и Activity, которые будут взаимодействовать с API.
Важно! Для доступа к сетевой информации на устройстве всё же необходимо запросить соответствующее разрешение:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Получаем сведения о сети
Мы создали метод getCurrentCellInfo()
, который будет извлекать данные:
Для получения сведений о сети нам нужно проверить, является ли тип сети GSM, CDMA или LTE. Для этого создаём метод getCellInfo()
для каждого типа сети.
Ниже код для сети типа GSM:
Этот же метод необходимо реализовать для каждого типа сети.
На этом реализация киллер-фичи приложения закончена. Как видите, мы не использовали ни GPS, ни службу определения местоположения. Полученные данные мы отправляем к API, а в ответ сразу получаем информацию о местоположении устройства.
GIF, 650 КБ
Приложение работает, как ожидалось. На этом всё.