diff --git a/README.md b/README.md index 82f538c..137f6c7 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,148 @@ # APRS RadioRubka -Android-приложение на Kotlin: анимированная заставка «APRS» и карта APRS в WebView. +Android-приложение: анимированная заставка «APRS» → веб-карта APRS и +пуш-уведомления (RuStore Push). Кнопка «назад» закрывает приложение, экран не +гаснет при активном приложении. -## Функции +- Пакет: `ru.ua1zbe.aprsmap` +- Карта: https://aprs.radiorubka.org/?center=67.5096,32.8271&zoom=8 + (задаётся строкой `map_url` в `app/src/main/res/values/strings.xml`) +- Репозиторий: https://git2.ua1zbe.ru/ua1zbe/aprsmap -- Анимированная заставка при старте (градиент, волна букв APRS, прогресс-бар). -- Карта `https://aprs.radiorubka.org` открывается внутри приложения (WebView, JS, zoom). -- Кнопка «Назад» закрывает приложение. +## Стек сборки + +- Gradle wrapper 9.2.0, AGP 8.13.2, Kotlin 2.2.21, JDK 25 +- compileSdk 34, targetSdk 34, minSdk 26 + +> Не использовать системный gradle 4.4.1 — только `./gradlew`. ## Сборка ```bash -./gradlew assembleDebug +./gradlew :app:assembleDebug # отладочный APK +./gradlew :app:assembleRelease # релизный APK (подписан) ``` -APK: `app/build/outputs/apk/debug/app-debug.apk` +Релизный APK: `app/build/outputs/apk/release/app-release.apk`. -## Требования +Перед релизной сборкой нужны (в git НЕ хранятся): -- Android 8.0 (API 26) и выше -- Разрешения: только INTERNET +- `keystore.properties` — подпись релиза (файл в корне проекта): + ``` + storeFile=/полный/путь/aprsmap-release.jks + storePassword=... + keyAlias=aprsmap + keyPassword=... + ``` +- `aprsmap-release.jks` — файл ключа (`.gitignore`). -## Ссылки +Отпечаток подписи (SHA-256) релиза. Получение: -- Gitea: http://git2.ua1zbe.ru/ua1zbe/aprsmap -- Карта: https://aprs.radiorubka.org \ No newline at end of file +```bash +keytool -list -v -keystore aprsmap-release.jks -alias aprsmap -storepass <пароль> | grep SHA256 +# или +$ANDROID_HOME/build-tools/35.0.0/apksigner verify --print-certs app-release.apk +``` + +## Версионирование + +`app/build.gradle.kts`: + +```kotlin +versionCode = 4 // инкремент для каждого релиза +versionName = "1.0.3" +``` + +## Установка на телефон (adb) + +```bash +$ANDROID_HOME/platform-tools/adb install -r app/build/outputs/apk/release/app-release.apk +$ANDROID_HOME/platform-tools/adb shell am start -n ru.ua1zbe.aprsmap/.SplashActivity +``` + +Запуск только через `.SplashActivity` (MainActivity не exported). +Google Play Protect может блокировать sideload — выключите усиленную защиту. + +## Выпуск релиза на Gitea + +1. Собрать `assembleRelease`. +2. Токен API Gitea — в `/tmp/gitea_token.txt` (`Authorization: token`). +3. Создать релиз и загрузить APK (см. пример ниже). Имена тегов: `v1.0.0`, `v1.0.1`, ... + +```bash +TOKEN=$(cat /tmp/gitea_token.txt) +curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \ + -d '{"tag_name":"v1.0.3","target_commitish":"main","name":"v1.0.3","body":"...","draft":false,"prerelease":false}' \ + "https://git2.ua1zbe.ru/api/v1/repos/ua1zbe/aprsmap/releases" +# затем прикрепить APK, взяв id релиза: +curl -s -H "Authorization: token $TOKEN" \ + -F "attachment=@app/build/outputs/apk/release/app-release.apk" \ + "https://git2.ua1zbe.ru/api/v1/repos/ua1zbe/aprsmap/releases//assets?name=APRS_RadioRubka_v1.0.3.apk" +``` + +Сверка обновлений идёт по интерфейсу +`https://git2.ua1zbe.ru/api/v1/repos/ua1zbe/aprsmap/releases/latest` +— поэтому репозиторий публичный. + +## Автообновление + +- При старте `MainActivity.checkForUpdates()` сравнивает `versionName` с последним + релизом Gitea; если есть новее — диалог «Обновить». +- APK скачивается в `cacheDir/updates/`, установка через + `ContentProvider` `UpdateFileProvider` (authority `ru.ua1zbe.aprsmap.fileprovider`) + + `ACTION_VIEW`, при необходимости запрос «Разрешить установку из этого источника». +- `tools/push.sh` — служебное, рассылка пушей (см. ниже). + +## Пуш-уведомления (RuStore Push) + +Актуально с v1.0.3. SDK `ru.rustore.sdk:pushclient:7.4.0`, топик рассылки — +**`aprsmap`**. + +- Параметры в `app/src/main/java/ru/ua1zbe/aprsmap/App.kt`: + `RUSTORE_PROJECT_ID` (project id из консоли RuStore), + `PUSH_TOPIC`. При старте: `RuStorePushClient.init` → `getToken` → + `subscribeToTopic("aprsmap")`. +- `PushMessagingService` получает `onNewToken`/`onMessageReceived`; уведомления с + секцией `notification` показывает сам SDK, `data` с ключами `title`/`body` — + приложение. Канал `aprs_push`. +- Токен устройства пишется в `shared_prefs/aprsmap.xml` (`push_token`) и виден в + logcat `RuStorePush:`. + +### Секреты (в git НЕ хранить) + +`tools/.push.secrets` (в `.gitignore`): + +``` +SERVICE_TOKEN="..." +PROJECT_ID="..." +``` + +SDK на устройстве требует установленный и авторизованный RuStore. + +### Рассылка всем подписчикам топика + +```bash +./tools/push.sh "Заголовок" "Текст" +``` + +Реализация: `POST https://vkpns-topics.rustore.ru/v1/projects/{PROJECT_ID}/topics/aprsmap/publish` +с `Authorization: Bearer {SERVICE_TOKEN}`. Ответ +`{"message":"payload has been successfully published to topic aprsmap"}` — успех. + +### Точечная отправка на устройство + +```bash +curl -s -X POST \ + "https://vkpns.rustore.ru/v1/projects/${PROJECT_ID}/messages:send" \ + -H "Authorization: Bearer ${SERVICE_TOKEN}" -H "Content-Type: application/json" \ + -d '{"message":{"token":"","notification":{"title":"...","body":"..."}}}' +``` + +### Проверка на устройстве + +```bash +adb logcat -d | grep -E "RuStorePush:" +adb shell dumpsys notification | grep -E "aprs_push|aprsmap" +``` + +Ожидаемое: `push token: ...`, `subscribed to aprsmap`, `push displayed by SDK`. \ No newline at end of file