Интеграция AI API в мобильное приложение требует особого подхода к безопасности: API-ключ никогда не должен попадать в клиентское приложение. В этом руководстве мы покажем правильную архитектуру и примеры кода для iOS (Swift), Android (Kotlin) и React Native.
Архитектура: прокси-сервер обязателен
Никогда не вызывайте AI API напрямую из мобильного приложения. APK и IPA файлы можно декомпилировать, и злоумышленник извлечёт ваш API-ключ за минуты. Правильная архитектура:
Мобильное приложение
→ Ваш бэкенд (с авторизацией пользователя)
→ ModelSwitch API (API-ключ хранится только здесь)
→ OpenRouter → AI-провайдер
Бэкенд выполняет роль прокси: принимает запрос от авторизованного пользователя, добавляет API-ключ и передаёт в ModelSwitch. Вот минимальный бэкенд на Express.js:
// server.ts — прокси-бэкенд для мобильного приложения
import express from "express";
import OpenAI from "openai";
const app = express();
app.use(express.json());
const client = new OpenAI({
baseURL: "https://api.modelswitch.ru/v1",
apiKey: process.env.MODELSWITCH_API_KEY!,
});
// Middleware: проверяем токен авторизации пользователя
function authMiddleware(req: any, res: any, next: any) {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token || !verifyUserToken(token)) {
return res.status(401).json({ error: "Unauthorized" });
}
next();
}
app.post("/api/chat", authMiddleware, async (req, res) => {
try {
const { message, model = "gpt-4o-mini" } = req.body;
const response = await client.chat.completions.create({
model,
messages: [{ role: "user", content: message }],
max_tokens: 1000,
});
res.json({ reply: response.choices[0].message.content });
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
app.listen(3000);
React Native
В React Native вызовите ваш прокси-бэкенд через fetch:
// services/ai.ts
const API_BASE = "https://your-backend.com";
export async function sendMessage(
message: string,
userToken: string,
model: string = "gpt-4o-mini"
): Promise<string> {
const response = await fetch(`${API_BASE}/api/chat`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${userToken}`,
},
body: JSON.stringify({ message, model }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
return data.reply;
}
// Использование в компоненте:
// const reply = await sendMessage("Привет!", authToken);
Swift (iOS)
Для iOS используйте URLSession для вызова вашего прокси-сервера:
// AIService.swift
import Foundation
class AIService {
static let shared = AIService()
private let baseURL = "https://your-backend.com"
func sendMessage(_ message: String, token: String) async throws -> String {
let url = URL(string: "(baseURL)/api/chat")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer (token)", forHTTPHeaderField: "Authorization")
let body: [String: Any] = ["message": message, "model": "gpt-4o-mini"]
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, _) = try await URLSession.shared.data(for: request)
let result = try JSONDecoder().decode(ChatResponse.self, from: data)
return result.reply
}
}
struct ChatResponse: Decodable {
let reply: String
}
Kotlin (Android)
Для Android используйте OkHttp или Ktor для вызова бэкенда:
// AIService.kt
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
class AIService(private val baseUrl: String = "https://your-backend.com") {
private val httpClient = OkHttpClient()
suspend fun sendMessage(message: String, token: String): String =
withContext(Dispatchers.IO) {
val json = JSONObject().apply {
put("message", message)
put("model", "gpt-4o-mini")
}
val request = Request.Builder()
.url("$baseUrl/api/chat")
.addHeader("Authorization", "Bearer $token")
.post(json.toString().toRequestBody("application/json".toMediaType()))
.build()
val response = httpClient.newCall(request).execute()
val body = JSONObject(response.body?.string() ?: "{}")
body.getString("reply")
}
}
Заключение
При интеграции AI в мобильные приложения всегда используйте серверный прокси для защиты API-ключа. ModelSwitch упрощает серверную часть: один ключ для 300+ моделей, а переключение между GPT-4o, Claude и другими моделями не требует изменений в мобильном приложении.