Files
chat/docs/MOBILE_QUICK_START.md
Andrey K. Choi 3050e084fa
All checks were successful
continuous-integration/drone/push Build is passing
main functions commit
2025-10-19 19:50:00 +09:00

6.5 KiB
Raw Blame History

🚀 БЫСТРЫЙ СТАРТ: Интеграция Emergency Service в мобильное приложение

📋 КРАТКИЙ ЧЕКЛИСТ (30 минут)

1 УДАЛИТЕ ВРЕМЕННЫЕ ТОКЕНЫ (5 мин)

// ❌ УДАЛИТЬ:
val tempToken = "temp_token_for_${email}"

// ✅ ЗАМЕНИТЬ:
val jwtToken = authManager.getValidJwtToken()

2 ДОБАВЬТЕ JWT АУТЕНТИФИКАЦИЮ (10 мин)

// Добавить в build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1'

// Простая авторизация
suspend fun login(email: String, password: String): String? {
    val response = apiService.login(LoginRequest(email, password))
    return if (response.isSuccessful) {
        response.body()?.access_token
    } else null
}

3 НАСТРОЙТЕ WEBSOCKET (10 мин)

val token = getJwtToken()
val wsUrl = "ws://YOUR_SERVER:8002/api/v1/emergency/ws/current_user_id?token=$token"

val client = OkHttpClient()
val request = Request.Builder().url(wsUrl).build()
val webSocket = client.newWebSocket(request, object : WebSocketListener() {
    override fun onMessage(webSocket: WebSocket, text: String) {
        // Обработка сообщений от сервера
        handleEmergencyMessage(text)
    }
})

4 ДОБАВЬТЕ API CALLS (5 мин)

// Создание экстренного вызова
suspend fun createAlert(latitude: Double, longitude: Double, description: String) {
    val alert = CreateAlertRequest("medical", latitude, longitude, null, description)
    val response = emergencyApi.createAlert(alert, "Bearer $jwtToken")
    // Обработка ответа
}

// Получение списка вызовов
suspend fun getMyAlerts() {
    val response = emergencyApi.getMyAlerts("Bearer $jwtToken")
    // Обработка списка
}

🛠️ ОСНОВНЫЕ ENDPOINTS

Аутентификация:

POST http://YOUR_SERVER:8000/api/v1/auth/login
Body: {"email": "user@example.com", "password": "password"}
Response: {"access_token": "JWT_TOKEN", "user": {...}}

Emergency API (все с Bearer JWT токеном):

POST http://YOUR_SERVER:8002/api/v1/alert - Создать вызов
GET  http://YOUR_SERVER:8002/api/v1/alerts/my - Мои вызовы
GET  http://YOUR_SERVER:8002/api/v1/alerts/active - Активные вызовы
GET  http://YOUR_SERVER:8002/api/v1/alerts/nearby?lat=55.7&lon=37.6&radius=5 - Ближайшие
POST http://YOUR_SERVER:8002/api/v1/alert/{id}/respond - Ответить на вызов
POST http://YOUR_SERVER:8002/api/v1/safety-check - Проверка безопасности

WebSocket:

ws://YOUR_SERVER:8002/api/v1/emergency/ws/current_user_id?token=JWT_TOKEN

📱 МИНИМАЛЬНЫЙ КОД

AuthManager.kt

class AuthManager {
    private var jwtToken: String? = null
    
    suspend fun login(email: String, password: String): Boolean {
        val response = retrofit.create(AuthApi::class.java)
            .login(LoginRequest(email, password))
            
        return if (response.isSuccessful) {
            jwtToken = response.body()?.access_token
            true
        } else false
    }
    
    fun getJwtToken(): String? = jwtToken
}

EmergencyManager.kt

class EmergencyManager(private val authManager: AuthManager) {
    private var webSocket: WebSocket? = null
    
    fun connectWebSocket() {
        val token = authManager.getJwtToken() ?: return
        val wsUrl = "ws://YOUR_SERVER:8002/api/v1/emergency/ws/current_user_id?token=$token"
        
        val request = Request.Builder().url(wsUrl).build()
        webSocket = OkHttpClient().newWebSocket(request, object : WebSocketListener() {
            override fun onMessage(webSocket: WebSocket, text: String) {
                handleMessage(text)
            }
        })
    }
    
    suspend fun createAlert(lat: Double, lon: Double, description: String) {
        val token = authManager.getJwtToken() ?: return
        val alert = CreateAlertRequest("medical", lat, lon, null, description)
        
        val response = emergencyApi.createAlert(alert, "Bearer $token")
        // Handle response
    }
    
    private fun handleMessage(message: String) {
        val data = Json.decodeFromString<WebSocketMessage>(message)
        when (data.type) {
            "emergency_alert" -> showEmergencyNotification(data)
            "connection_established" -> onConnected()
        }
    }
}

🧪 ТЕСТИРОВАНИЕ

Проверьте подключение:

# На сервере запустите тесты
./venv/bin/python test_final_security.py

Тестовые данные:

  • Server: http://192.168.219.108:8000 (замените на ваш IP)
  • Email: shadow85@list.ru
  • Password: R0sebud1985

Быстрый тест в коде:

// В onCreate или init
lifecycleScope.launch {
    val success = authManager.login("shadow85@list.ru", "R0sebud1985")
    if (success) {
        emergencyManager.connectWebSocket()
        Toast.makeText(this@MainActivity, "Connected!", Toast.LENGTH_SHORT).show()
    }
}

⚠️ ВАЖНЫЕ МОМЕНТЫ

  1. Замените IP адрес YOUR_SERVER на реальный IP сервера
  2. Удалите ВСЕ temp_token_ из кода
  3. Добавьте разрешения в AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. Обработайте ошибки сети и токенов
  2. Сохраняйте токен в зашифрованном виде

📞 ПРОБЛЕМЫ?

  1. WebSocket не подключается → Проверьте JWT токен и URL
  2. API возвращает 403 → Проверьте заголовок Authorization
  3. API возвращает 500 → Проверьте формат данных в запросе
  4. Нет уведомлений → Проверьте WebSocket подключение

Полная документация: MOBILE_APP_INTEGRATION_GUIDE.md

Готовые тесты сервера: test_final_security.py - показывает, что все работает!