Dialogflow Mobile Development Integration: Android and Flutter Complete Tutorial

Dialogflow Mobile Development Integration: Android and Flutter Complete Tutorial
Want to add AI conversation features to your App?
Whether it's a customer service assistant, voice assistant, or interactive guide, Dialogflow can help you implement it. This article teaches you how to integrate Dialogflow into Android and Flutter to build mobile applications with natural language understanding capabilities.
If you're not yet familiar with Dialogflow, we recommend first reading the Dialogflow Complete Guide.
Mobile App Integration Method Comparison
There are two main ways to integrate Dialogflow into an App, each with pros and cons.
Direct API Call
App directly calls Dialogflow API:
App → Dialogflow API → Response
Advantages:
- Simple architecture
- Lower latency
- No need to build backend
Disadvantages:
- API key exposed in App (security risk)
- Cannot add additional business logic
- Difficult to record conversation history
Backend Proxy
App calls Dialogflow through your backend:
App → Your Backend → Dialogflow API → Your Backend → App
Advantages:
- API key safely stored in backend
- Can add business logic (validation, logging, filtering)
- Easy to integrate with other systems
Disadvantages:
- Need to build and maintain backend
- Slightly higher latency
- More complex architecture
Analysis and Selection Recommendations
| Method | Suitable Scenarios |
|---|---|
| Direct API | POC validation, learning purposes, internal tools |
| Backend Proxy | Production products, security needs, enterprise applications |
Recommendation: Production Apps should always use the backend proxy method.
Illustration: Two Integration Architecture Comparison
Scene Description: A side-by-side comparison diagram, left side showing "Direct API Call" architecture (App → Dialogflow), right side showing "Backend Proxy" architecture (App → Backend → Dialogflow). Pros and cons listed below each architecture.
Visual Focus:
- Main content clearly presented
Required Elements:
- Based on key elements in description
Chinese Text to Display: None
Color Tone: Professional, clear
Elements to Avoid: Abstract graphics, gears, glowing effects
Slug:
dialogflow-mobile-integration-architecture
Android Studio Integration
Project Setup
Step 1: Add Dependencies
In app/build.gradle add:
dependencies {
implementation 'com.google.cloud:google-cloud-dialogflow:4.0.0'
implementation 'io.grpc:grpc-okhttp:1.56.1'
implementation 'com.google.auth:google-auth-library-oauth2-http:1.19.0'
}
Step 2: Configure Network Permissions
In AndroidManifest.xml add:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Gradle Dependencies
Complete build.gradle configuration:
android {
compileSdk 34
defaultConfig {
minSdk 24
targetSdk 34
}
packagingOptions {
exclude 'META-INF/INDEX.LIST'
exclude 'META-INF/DEPENDENCIES'
}
}
dependencies {
implementation 'com.google.cloud:google-cloud-dialogflow:4.0.0'
implementation 'io.grpc:grpc-okhttp:1.56.1'
implementation 'io.grpc:grpc-stub:1.56.1'
}
Service Account Setup
Step 1: Get Key File
- Go to Google Cloud Console > IAM > Service Accounts
- Create or select service account
- Download JSON key file
Step 2: Place Key (Development Use)
Place key file at app/src/main/res/raw/credentials.json
Note: This is only suitable for development testing. Use backend proxy for production.
DetectIntent API Call
Create Dialogflow client class:
class DialogflowClient(context: Context) {
private val sessionsClient: SessionsClient
private val session: SessionName
private val projectId = "your-project-id"
private val sessionId = UUID.randomUUID().toString()
init {
// Load credentials
val stream = context.resources.openRawResource(R.raw.credentials)
val credentials = GoogleCredentials.fromStream(stream)
.createScoped(listOf("https://www.googleapis.com/auth/cloud-platform"))
val settings = SessionsSettings.newBuilder()
.setCredentialsProvider { credentials }
.build()
sessionsClient = SessionsClient.create(settings)
session = SessionName.of(projectId, sessionId)
}
suspend fun detectIntent(text: String): String {
return withContext(Dispatchers.IO) {
val textInput = TextInput.newBuilder()
.setText(text)
.setLanguageCode("en-US")
.build()
val queryInput = QueryInput.newBuilder()
.setText(textInput)
.build()
val request = DetectIntentRequest.newBuilder()
.setSession(session.toString())
.setQueryInput(queryInput)
.build()
val response = sessionsClient.detectIntent(request)
response.queryResult.fulfillmentText
}
}
fun close() {
sessionsClient.close()
}
}
Example Code
Complete Activity example:
class ChatActivity : AppCompatActivity() {
private lateinit var dialogflowClient: DialogflowClient
private lateinit var messageAdapter: MessageAdapter
private val messages = mutableListOf<Message>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
dialogflowClient = DialogflowClient(this)
messageAdapter = MessageAdapter(messages)
recyclerView.adapter = messageAdapter
sendButton.setOnClickListener {
val text = inputEditText.text.toString()
if (text.isNotEmpty()) {
sendMessage(text)
inputEditText.text.clear()
}
}
}
private fun sendMessage(text: String) {
// Display user message
messages.add(Message(text, isUser = true))
messageAdapter.notifyItemInserted(messages.size - 1)
// Call Dialogflow
lifecycleScope.launch {
try {
val response = dialogflowClient.detectIntent(text)
messages.add(Message(response, isUser = false))
messageAdapter.notifyItemInserted(messages.size - 1)
recyclerView.scrollToPosition(messages.size - 1)
} catch (e: Exception) {
messages.add(Message("Sorry, an error occurred", isUser = false))
messageAdapter.notifyItemInserted(messages.size - 1)
}
}
}
override fun onDestroy() {
super.onDestroy()
dialogflowClient.close()
}
}
Flutter Integration
Package Selection
Flutter has several Dialogflow-related packages:
| Package | Description | Maintenance Status |
|---|---|---|
dialogflow_grpc | Official gRPC protocol | Active |
flutter_dialogflow | Community package | Less Updated |
dialogflow_flutter | Simplified version | Less Updated |
Recommendation: Use dialogflow_grpc or directly use HTTP API.
Cross-Platform Implementation
Step 1: Add Dependencies
In pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^1.1.0
uuid: ^4.0.0
Step 2: Create API Service
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
class DialogflowService {
final String projectId;
final String accessToken; // Get from backend
final String sessionId = Uuid().v4();
DialogflowService({required this.projectId, required this.accessToken});
Future<String> detectIntent(String text) async {
final url = Uri.parse(
'https://dialogflow.googleapis.com/v2/projects/$projectId/agent/sessions/$sessionId:detectIntent'
);
final response = await http.post(
url,
headers: {
'Authorization': 'Bearer $accessToken',
'Content-Type': 'application/json',
},
body: jsonEncode({
'queryInput': {
'text': {
'text': text,
'languageCode': 'en-US',
},
},
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['queryResult']['fulfillmentText'];
} else {
throw Exception('Dialogflow API error: ${response.statusCode}');
}
}
}
Example Widget
class ChatScreen extends StatefulWidget {
@override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final TextEditingController _controller = TextEditingController();
final List<ChatMessage> _messages = [];
late DialogflowService _dialogflow;
bool _isLoading = false;
@override
void initState() {
super.initState();
_dialogflow = DialogflowService(
projectId: 'your-project-id',
accessToken: 'your-access-token', // Should actually get from backend
);
}
void _sendMessage() async {
final text = _controller.text.trim();
if (text.isEmpty) return;
setState(() {
_messages.add(ChatMessage(text: text, isUser: true));
_isLoading = true;
});
_controller.clear();
try {
final response = await _dialogflow.detectIntent(text);
setState(() {
_messages.add(ChatMessage(text: response, isUser: false));
});
} catch (e) {
setState(() {
_messages.add(ChatMessage(text: 'Sorry, an error occurred', isUser: false));
});
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('AI Assistant')),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (context, index) {
final message = _messages[index];
return ChatBubble(
text: message.text,
isUser: message.isUser,
);
},
),
),
if (_isLoading) LinearProgressIndicator(),
_buildInputArea(),
],
),
);
}
Widget _buildInputArea() {
return Container(
padding: EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(hintText: 'Enter message...'),
onSubmitted: (_) => _sendMessage(),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: _sendMessage,
),
],
),
);
}
}
State Management Integration
Use Provider to manage conversation state:
class ChatProvider extends ChangeNotifier {
final List<ChatMessage> _messages = [];
bool _isLoading = false;
List<ChatMessage> get messages => _messages;
bool get isLoading => _isLoading;
Future<void> sendMessage(String text) async {
_messages.add(ChatMessage(text: text, isUser: true));
_isLoading = true;
notifyListeners();
try {
final response = await _dialogflow.detectIntent(text);
_messages.add(ChatMessage(text: response, isUser: false));
} catch (e) {
_messages.add(ChatMessage(text: 'An error occurred', isUser: false));
} finally {
_isLoading = false;
notifyListeners();
}
}
}
Illustration: Flutter Chat Interface Screenshot
Scene Description: A phone simulator screenshot showing Flutter-developed chat interface. Screen has conversation bubbles (user on right, AI on left), bottom input field and send button. Interface design is clean and modern.
Visual Focus:
- Main content clearly presented
Required Elements:
- Based on key elements in description
Chinese Text to Display: None
Color Tone: Professional, clear
Elements to Avoid: Abstract graphics, gears, glowing effects
Slug:
flutter-dialogflow-chat-interface
Voice Assistant Features
Let App support voice input and output.
Speech-to-Text Integration
Android (using SpeechRecognizer):
class VoiceInputManager(private val context: Context) {
private var speechRecognizer: SpeechRecognizer? = null
private var onResult: ((String) -> Unit)? = null
fun startListening(onResult: (String) -> Unit) {
this.onResult = onResult
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
speechRecognizer?.setRecognitionListener(object : RecognitionListener {
override fun onResults(results: Bundle?) {
val matches = results?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
matches?.firstOrNull()?.let { onResult(it) }
}
override fun onError(error: Int) {
// Handle error
}
// Other required override methods...
})
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US")
}
speechRecognizer?.startListening(intent)
}
fun stopListening() {
speechRecognizer?.stopListening()
speechRecognizer?.destroy()
}
}
Flutter (using speech_to_text):
import 'package:speech_to_text/speech_to_text.dart' as stt;
class VoiceInput {
final stt.SpeechToText _speech = stt.SpeechToText();
bool _isListening = false;
Future<void> initialize() async {
await _speech.initialize();
}
void startListening(Function(String) onResult) {
_speech.listen(
onResult: (result) {
if (result.finalResult) {
onResult(result.recognizedWords);
}
},
localeId: 'en_US',
);
_isListening = true;
}
void stopListening() {
_speech.stop();
_isListening = false;
}
}
Text-to-Speech Playback
import 'package:flutter_tts/flutter_tts.dart';
class VoiceOutput {
final FlutterTts _tts = FlutterTts();
Future<void> initialize() async {
await _tts.setLanguage('en-US');
await _tts.setSpeechRate(0.5);
}
Future<void> speak(String text) async {
await _tts.speak(text);
}
Future<void> stop() async {
await _tts.stop();
}
}
Continuous Dialogue Mode
Implement Siri-like continuous dialogue experience:
class ContinuousDialogue {
final VoiceInput _voiceInput;
final VoiceOutput _voiceOutput;
final DialogflowService _dialogflow;
bool _isActive = false;
void startConversation() async {
_isActive = true;
while (_isActive) {
// Voice input
final userText = await _listenForInput();
if (userText == 'end conversation') {
_isActive = false;
break;
}
// Call Dialogflow
final response = await _dialogflow.detectIntent(userText);
// Voice output
await _voiceOutput.speak(response);
// Brief wait before continuing to listen
await Future.delayed(Duration(milliseconds: 500));
}
}
}
Security Considerations
Mobile App security is especially important—once API keys leak, they can't be retrieved.
API Key Protection Strategies
Never do this:
// ❌ Hard-coding key in code
val apiKey = "AIzaSyXXXXXXXXXXXXXXX"
Recommended approaches:
1. Use Backend Proxy (Recommended)
App → Your Backend (authentication + Dialogflow call) → App
Backend stores API key, App only communicates with backend.
2. Use Firebase Remote Config
val remoteConfig = Firebase.remoteConfig
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
if (task.isSuccessful) {
val apiKey = remoteConfig.getString("dialogflow_api_key")
}
}
3. Use Android Keystore
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
// Securely store and retrieve keys
User Authentication Integration
Ensure only logged-in users can use AI features:
class SecureDialogflowClient(private val authService: AuthService) {
suspend fun detectIntent(text: String): String {
// Confirm user is logged in
val user = authService.currentUser
?: throw UnauthorizedException("Please log in first")
// Get access token
val token = authService.getIdToken()
// Call your backend (not directly calling Dialogflow)
return apiService.chat(
token = token,
text = text
)
}
}
Sensitive Data Handling
Don't log sensitive conversations:
// ❌ Logging full conversation
Log.d("Chat", "User said: $userInput")
// ✓ Only log necessary information
Log.d("Chat", "User sent message, length: ${userInput.length}")
Clear local conversation history:
fun clearChatHistory() {
// Clear memory
messages.clear()
// Clear local storage
sharedPreferences.edit().remove("chat_history").apply()
}
Illustration: Security Architecture Diagram
Scene Description: A security architecture diagram showing recommended backend proxy mode. App (with lock icon) → HTTPS → Backend (with firewall icon) → Dialogflow. Indicates keys only exist in backend, App doesn't touch sensitive information.
Visual Focus:
- Main content clearly presented
Required Elements:
- Based on key elements in description
Chinese Text to Display: None
Color Tone: Professional, clear
Elements to Avoid: Abstract graphics, gears, glowing effects
Slug:
dialogflow-mobile-security-architecture
Worried about API key security? Mobile App security issues are easily overlooked—once something happens, it's very troublesome. Book architecture consultation to have us help design secure integration architecture.
Release Considerations
App Store / Play Store Review
Privacy Policy Requirements:
If App collects conversation content, need to explain in privacy policy:
- What data is collected
- How data is used
- How long data is retained
- How users can delete data
Permission Explanations:
If using microphone permission, need to explain why:
- "Used for voice input, allowing you to speak with the AI assistant"
Performance Optimization
Reduce Startup Time:
// Lazy load Dialogflow client
private val dialogflowClient by lazy {
DialogflowClient(applicationContext)
}
Background Processing:
// Process in background thread
viewModelScope.launch(Dispatchers.IO) {
val response = dialogflowClient.detectIntent(text)
withContext(Dispatchers.Main) {
updateUI(response)
}
}
Offline Handling
Handling when there's no network:
suspend fun detectIntent(text: String): String {
if (!isNetworkAvailable()) {
return "Currently no network connection, please try again later."
}
return try {
dialogflowClient.detectIntent(text)
} catch (e: IOException) {
"Network connection unstable, please try again later."
}
}
For more API integration details, refer to Dialogflow Fulfillment and API Integration Tutorial. For Intent design, refer to Dialogflow Intent and Context Tutorial. For cost estimation, refer to Dialogflow Pricing Complete Analysis.
Next Steps
After completing mobile integration, you can:
- Optimize Conversation Design: Dialogflow Intent and Context Complete Tutorial
- Develop Backend Integration: Dialogflow Fulfillment and API Integration Tutorial
- Control Costs: Dialogflow Pricing Complete Analysis
Want to Add AI Conversation Features to Your App?
Integrating AI conversations in Apps involves many technical details: API integration, security, performance optimization, review compliance...
If you need:
- Add AI customer service features to existing App
- Develop new App with voice assistant
- Design secure and reliable integration architecture
- Cross-platform (iOS + Android) solution
Book AI implementation consultation to have an experienced team help you plan and implement.
We've helped multiple Apps successfully integrate AI conversation features, consultation is completely free.
Need Professional Cloud Advice?
Whether you're evaluating cloud platforms, optimizing existing architecture, or looking for cost-saving solutions, we can help
Book Free ConsultationRelated Articles
Dialogflow CX vs ES Complete Comparison: 2026 Version Selection Guide
What's the difference between Dialogflow CX and ES? This article compares features, pricing, and use cases in detail, with a decision flowchart to help you choose the right version without mistakes or wasting money.
DialogflowDialogflow Fulfillment and API Integration Complete Tutorial
Complete Dialogflow Webhook development tutorial: Cloud Functions deployment, DetectIntent API calls, third-party API integration. Includes Node.js and Python example code with GitHub project links.
DialogflowDialogflow Complete Guide 2026: From Beginner to Production AI Chatbot Development
Complete analysis of Google Dialogflow CX vs ES version differences, Generative AI Agents, Vertex AI integration, cost calculation, and LINE Bot integration tutorials. Build enterprise-grade AI customer service bots from scratch with 2026 latest generative AI features and practical examples.