DEV Community

vmodal_ai
vmodal_ai

Posted on

Building AI-Powered Flutter Apps with Gemini

Building AI-Powered Flutter Apps with Gemini

Generative AI can be integrated into Flutter applications for chat, summarization, classification, content generation, document processing, and intelligent assistants.

A production application should avoid putting sensitive API credentials directly in the mobile application.

A safer architecture is:

Flutter App
    |
    | HTTPS
    v
Backend API
    |
    v
Gemini API
    |
    v
AI Response
Enter fullscreen mode Exit fullscreen mode

Why use a backend?

Embedding a production AI API key directly in an APK makes it possible for attackers to extract the key.

Instead:

Flutter -> FastAPI/Node/Laravel -> Gemini
Enter fullscreen mode Exit fullscreen mode

The backend can implement:

  • authentication
  • rate limiting
  • prompt templates
  • logging
  • usage limits
  • response validation

Step 1: Create the Flutter UI

A simple chat screen can contain:

final controller = TextEditingController();

TextField(
  controller: controller,
  decoration: const InputDecoration(
    hintText: 'Ask something...',
  ),
)
Enter fullscreen mode Exit fullscreen mode

Send the message through a repository:

class AiRepository {
  Future<String> generate(String prompt) async {
    // Call your backend here.
    throw UnimplementedError();
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Define a clean architecture

A scalable Flutter AI application can use:

Presentation
    |
BLoC / Cubit
    |
AI Repository
    |
API Client
    |
Backend
    |
Gemini
Enter fullscreen mode Exit fullscreen mode

This makes it possible to replace Gemini later without rewriting the UI.

Step 3: Backend example with FastAPI

Install dependencies:

pip install fastapi uvicorn google-genai
Enter fullscreen mode Exit fullscreen mode

Example:

import os

from fastapi import FastAPI
from pydantic import BaseModel
from google import genai

app = FastAPI()

client = genai.Client(
    api_key=os.environ["GEMINI_API_KEY"]
)

class ChatRequest(BaseModel):
    message: str

@app.post("/chat")
async def chat(request: ChatRequest):
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=request.message,
    )

    return {"response": response.text}
Enter fullscreen mode Exit fullscreen mode

Keep the API key in an environment variable:

export GEMINI_API_KEY="your-key"
Enter fullscreen mode Exit fullscreen mode

Never commit it to Git.

Step 4: Call the backend from Flutter

Using the http package:

import 'dart:convert';
import 'package:http/http.dart' as http;

class AiApi {
  final String baseUrl;

  AiApi(this.baseUrl);

  Future<String> chat(String message) async {
    final response = await http.post(
      Uri.parse('$baseUrl/chat'),
      headers: {
        'Content-Type': 'application/json',
      },
      body: jsonEncode({
        'message': message,
      }),
    );

    if (response.statusCode != 200) {
      throw Exception('AI request failed');
    }

    final data = jsonDecode(response.body);

    return data['response'] as String;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Add loading and error states

AI requests are asynchronous, so explicitly represent:

Idle
  ↓
Loading
  ↓
Success

or

Loading
  ↓
Failure
Enter fullscreen mode Exit fullscreen mode

With BLoC:

sealed class AiState {}

class AiInitial extends AiState {}

class AiLoading extends AiState {}

class AiSuccess extends AiState {
  final String response;

  AiSuccess(this.response);
}

class AiFailure extends AiState {
  final String message;

  AiFailure(this.message);
}
Enter fullscreen mode Exit fullscreen mode

Prompt engineering

Instead of:

Explain this.
Enter fullscreen mode Exit fullscreen mode

Use structured instructions:

You are an assistant for a Flutter developer.

Task:
Explain the following Dart error.

Requirements:
1. Identify the root cause.
2. Provide corrected code.
3. Keep the explanation concise.

Error:
{{error}}
Enter fullscreen mode Exit fullscreen mode

Structured prompts make application behavior more predictable.

Streaming responses

For chat applications, streaming can improve perceived responsiveness:

User message
     |
     v
Backend
     |
     +---- token
     +---- token
     +---- token
     +---- token
     |
Flutter renders progressively
Enter fullscreen mode Exit fullscreen mode

Consider Server-Sent Events or WebSockets depending on your backend architecture.

Security checklist

Never expose:

  • Gemini API keys
  • database credentials
  • private backend secrets

Add:

  • authentication
  • request validation
  • rate limiting
  • logging
  • abuse protection

Conclusion

Flutter is an excellent client platform for AI applications, but a maintainable architecture separates the UI from the AI provider. A backend gives you control over security, prompts, model selection, cost, and business logic.

Useful Links

SDK Flutter: https://github.com/v-modal/vmodal_sdk_flutter

SDK Android: https://github.com/v-modal/vmodal_sdk_android

Discord: https://discord.gg/K72z28KUx

Top comments (0)