# Автобус №127 — Расписание (Android) Приложение с расписанием автобуса **№127** по маршруту **Кандалакша — Полярные Зори — Зашеек** (Мурманская область). ## Возможности - **Выбор остановки** — Кандалакша / Полярные Зори / Зашеек. При выборе показываются доступные направления (куда можно уехать). - **Ближайшие рейсы** — по 3 на каждое направление, с подсчётом «через N ч M мин» (время по **МСК**, обновляется каждые 30 сек). - **Автоопределение дня недели** — будни/выходные. - **Полное расписание** — по кнопке раскрывается вся таблица (4 остановки: Кандалакша · ПЗ→Зашеек · Зашеек · ПЗ→Кандалакша). - **Пуш-уведомления** — через RuStore Push, см. раздел ниже. - **Меню** — кнопка `⋮` в шапке открывает выпадающее окошко с пунктом «О приложении» (описание и версия сборки). - Тёмная тема, живые часы МСК, подсветка ближайших рейсов (< 15 мин). ## Технические данные | Параметр | Значение | |-----------------|------------------------------| | Тип | WebView-обёртка (HTML/JS) | | Минимальный SDK | 26 (Android 8.0) | | Целевой SDK | 34 (Android 14) | | Сборка | Gradle 8.6 + AGP 8.2.2 | | Подпись | keystore `~/bus127.keystore` (alias `bus127`) | ## Пуш-уведомления (RuStore) Приложение интегрировано с [RuStore Push SDK](https://www.rustore.ru/help/sdk/push-notifications) (аналог Firebase Cloud Messaging). Проект в консоли RuStore привязан к пакету `ru.ua1zbe.bus127` и подписи release-keystore; пока подпись не меняется, перерегистрация не нужна. Для доставки на устройстве должен быть установлен и авторизован **RuStore**. Рассылка выполняется с сервера через API RuStore: ``` POST https://vkpns.rustore.ru/v1/projects/{project_id}/messages:send Authorization: Bearer {service-token} Content-Type: application/json { "message": { "token": "{push-token устройства}", "notification": { "title": "Автобус 127", "body": "Ближайший рейс через 5 мин" } } } ``` - `project_id` и `service-token` берутся в консоли RuStore: **Push-уведомления > Проекты**. В приложение попадает только `project_id`; сервисный токен в APK не хранится. - `push-token` устройства приходит в `onNewToken` (лог `RuStorePush`) и сохраняется в `SharedPreferences` `bus127_push`. - Приложение подписывается на топик `bus127` при старте. Отдельного создания топика в консоли не требуется — публикация в него проходит и для несуществующего. - Если в запросе есть секция `notification` — уведомление показывает сам SDK; если переданы только `data` (`title`/`body`, необязательный `url`) — приложение показывает его само и открывает ссылку по клику. ### Рассылка **Всем подписчикам топика** (все устройства, открывшие приложение): ``` POST https://vkpns-topics.rustore.ru/v1/projects/{project_id}/topics/{topic}/publish Authorization: Bearer {service-token} {"message":{"notification":{"title":"...","body":"..."}}} ``` **Одному устройству** — по его push-токену: ``` POST https://vkpns.rustore.ru/v1/projects/{project_id}/messages:send Authorization: Bearer {service-token} {"message":{"token":"...","notification":{"title":"...","body":"..."}}} ``` Если устройства не подписались сами, их токены можно подписать разом: `POST .../topics/{topic}/batch_subscribe` с `{"push_tokens":[...]}`. Ответ `400` с текстом про `registration token` означает, что адресат не указан или токен устройства неверен; `401`/`403` — неверный сервисный токен или его пара с `project_id`. ## Структура ``` apk-webview/ # исходники APK (WebView) ├── app/ │ ├── build.gradle │ └── src/main/ │ ├── AndroidManifest.xml │ ├── java/ru/ua1zbe/bus127/ │ │ ├── MainActivity.java # главный экран: WebView + запрос разрешения │ │ ├── AboutActivity.java # окно «О приложении» │ │ ├── Webs.java # общий WebView для всех экранов │ │ ├── BusBridge.java # мост страницы и приложения (меню, назад, версия) │ │ ├── Bus127App.java # инициализация RuStore Push SDK │ │ ├── PushMessagingService.java # приём уведомлений │ │ ├── PushIntents.java # переход по клику │ │ └── push/PushStore.java # хранение push-токена │ ├── assets/index.html # интерфейс (HTML/JS) │ └── res/values/strings.xml └── settings.gradle, build.gradle, gradle.properties web/index.html # веб-версия (та же страница, для браузера) ``` ## Сборка ```bash export JAVA_HOME=$HOME/jdk-17.0.20.1+1 export ANDROID_HOME=$HOME/Android/Sdk cd apk-webview ~/gradle-8.6/bin/gradle assembleRelease --no-daemon ``` Готовый APK — в [релизах](../../releases) и в репозитории `android_apk`. ## Лицензия MIT.