Google search engine
Home Blog Page 3

Isolates, Streams & Background Tasks: The Modern Guide to Parallel Processing in Flutter

When building Flutter apps, we often take pride in smooth UI, crisp animations, and responsive interactions. But under the hood — especially when dealing with heavy computation, long network calls, data parsing, or background work — if we’re not careful, our app’s frame rate can suffer, or, worse, the UI can freeze, leaving users to see jank.

If you’re looking for the best Flutter app development company for your mobile application, then feel free to contact us at — support@flutterdevs.com


In this guide, I’ll walk you through:

Let’s get started 🚀


🔹 What Are Isolates — And Why They Matter

🧠 The problem: single-thread UI

By default, Dart (and thus Flutter) runs everything on a single “main” isolate — that means UI rendering, input handling, business logic, everything shares the same thread and memory. (Flutter Documentation)

This is fine for many tasks — but as soon as you throw in heavy work: parsing a massive JSON, processing an image, doing complex calculations — the UI might struggle to keep up, causing frame drops or jank. (Flutter Documentation)

🛠️ Enter: Isolates

An Isolate in Dart is like a separate worker — it has its own memory, its own event loop, and runs independently of the main isolate. (Dart)

Important characteristics:

  • No shared memory between isolates — they don’t share variables, memory structures, or state. That avoids a lot of complexity related to threads and concurrency (mutexes, data races, etc.). (Dart)
  • Communication only via message passing (using SendPort / ReceivePort). (Flutter Documentation)
  • As a result, heavy computation or I/O in an isolate won’t block the main UI, which keeps animations and interactions smooth. (Flutter Documentation)

✅ When to use isolates

Use isolates when your Flutter app faces:

  • CPU-intensive tasks: heavy computation, data processing, large list operations, complex algorithms. (Flutter Documentation)
  • Large data parsing: e.g, decoding a big JSON, processing large files. (Dart)
  • File/media processing: compression, image processing, video/audio processing, etc. (Flutter Documentation)

🔹 How to Use Isolates — Code Patterns & Best Practices

Here’s how you typically work with isolates in Flutter / Dart:

Example: Using Isolate.spawn()

import 'dart:isolate';
// Top-level or static function (necessary for spawning)
void heavyTask(SendPort sendPort) {
int result = 0;
for (int i = 0; i < 100000000; i++) {
result += i;
}
sendPort.send(result);
}
Future<void> runHeavyTask() async {
final receivePort = ReceivePort();
await Isolate.spawn(heavyTask, receivePort.sendPort);
final result = await receivePort.first as int;
print('Result from isolate: $result');
}
  • Here, heavyTask runs in a separate isolate.
  • We pass a SendPort For communication, the isolate does its work and sends the result back via sendPort.
  • The main isolate waits and reads the result via the ReceivePort

Simpler alternative: compute()

For simpler, stateless tasks, Flutter provides the compute() function (from flutter/foundation). Under the hood, it uses isolates but abstracts away the manual SendPort / ReceivePort boilerplate.

Example:

import 'package:flutter/foundation.dart';
int doWork(int input) {
return input * input;
}
void someFunction() async {
final result = await compute(doWork, 42);
print('Result: $result');
}

✅ Use compute() for quick, one-off background jobs (e.g, JSON parsing, quick math, small image processing).

⚠️ Use Isolate.spawn() when you need more control — long-running tasks, multiple messages, complex data — or want a persistent worker isolate.

Important caveats & best practices

  • Since isolates don’t share memory, you can’t just reference existing complex objects across isolates. You often need to pass only simple data (primitives, serializable data) or immutable objects. (Flutter Documentation)
  • Isolate spawning has overhead: spawning too many isolates (e.g, per small task) might become inefficient. Think: Is it big enough to warrant the overhead?
  • Always ensure to close ports (ReceivePort.close() when done) to avoid memory leaks.

🔹 Streams: Asynchronous Data Over Time

While isolates help with concurrency/parallelism, sometimes you just need asynchronous data that flows over time — e.g, data from a network, user input, repeated events, timers, etc. That’s where Streams shine.

  • A Stream<T> In Dart, a sequence of asynchronous events (values) over time is represented. (Dart)
  • You can listen to streams, use awaitfor loops, combine multiple streams, transform data — ideal for reactive programming. (Dart)

Example: Simple periodic stream

Stream<int> counterStream = Stream.periodic(
Duration(seconds: 1),
(count) => count,
);
void listenCounter() async {
await for (var value in counterStream) {
print('Count: $value');
}
}

Here, counterStream emits an integer every second; using awaitfor we consume each value as it arrives. (Dart)

Streams are ideal for:

  • Real-time or periodic data (timers, sensors, location, live updates)
  • Handling asynchronous sequences (network responses, user-generated events)
  • Reactive UI updates (e.g, updating UI when stream emits new data)

🔹 Background Tasks: When the App Is Backgrounded or Needs Scheduling

Isolates and streams solve many concurrency and data-flow challenges — but what about tasks that need to run even when the app is backgrounded (or periodically), like syncing data, uploading logs, fetching remote updates, geofencing, cleanup jobs, etc.?

Flutter supports background processing — often implemented using isolates under the hood. (Flutter Documentation)

🔁 Common approaches/packages

  • Use a plugin like WorkManager (on Android / iOS) to schedule background tasks that survive across app restarts or device reboots. (Flutter Documentation)
  • For simpler periodic tasks: use Dart’s Timer, but keep in mind that callbacks run on the main isolate — so avoid heavy work inside a plain Timer.
  • For more robust background services, there are packages like flutter_background_service. These allow long-running background tasks beyond the typical app lifecycle.

📝 What to keep in mind

  • Always manage resources carefully: background tasks consume CPU, memory, and battery, so schedule judiciously.
  • Handle platform constraints: on iOS / Android, background execution policies differ — sometimes scheduled tasks may be delayed, throttled, or disallowed.
  • Combine with isolates/streams: for example, a background job can spawn an isolate to process data, and then send results to the main isolate or store locally — or even emit a stream of updates when data is ready.

🔹 Putting It All Together: Real-World Use-Cases & Architecture Ideas

Here are some scenarios where combining isolates + streams + background tasks makes your app robust and performant:

Use-case: How to implement Parsing large JSON data from the server (maybe several MBs) after download. Use an isolate — perhaps via compute() or Isolate.spawn() — to decode and process JSON, then pass the result to the main isolate. UI remains smooth. Downloading images/videos and processing/compressing them without freezing UI Spawn an isolate for network + processing. Use streams or callbacks to track progress. Uploading queued data (e.g, offline form submissions) when connectivity returns, even if the app was closed. Use a background task scheduler (workmanager / background_service) to run a task on connectivity change, inside which you spawn an isolate to upload/process data. Periodic data sync (e.g., checking for updates, fetching background updates). Use background scheduling + isolates; optionally emit results via streams to update UI or send local notifications.

📦 Suggested folder/architecture structure

lib/
background/ // all background-task + isolate logic
task_scheduler.dart // setup workmanager or background service
data_processor.dart // functions to run in isolates (parsing, processing)
streams/ // stream controllers & broadcast streams
services/ // networking / DB / API services
ui/ // widgets / screens
main.dart

This separation keeps UI code clean and ensures you’re not mixing heavy logic with presentation.


✅ When to Prefer Async / Future Over Isolates / Streams — Keep It Simple

Remember: just because isolates and streams exist doesn’t mean you should always use them. For simple tasks — small API calls, light data processing, quick file I/O — Dart’s normal async/await + Futures are often sufficient and simpler to reason about.

Overusing isolates (especially spawning many small ones) or over-engineering with streams can add unnecessary complexity. Always measure: Is the task heavy enough to justify the overhead?


🧠 Summary: Why Understanding Parallel / Async Tools Matters

  • Isolates give you real parallelism (on multi-core devices) and prevent UI jank by offloading heavy work.
  • Streams let you handle asynchronous sequences of data elegantly.
  • Background tasks + scheduling enable timely data sync, offline support, and background processing — essential for modern apps.

By mastering these tools, you not only make your apps more responsive and efficient — you also unlock patterns for real-world, production-ready features: background sync, media processing, offline handling, and more.

If used wisely (with correct data flow, resource management, and architecture), this trio becomes a powerful backbone for any serious Flutter application.


From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automationIoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire Flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on FacebookGitHubTwitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.


Flutter Performance Mastery 2025: The Complete Checklist for Sub-60ms Frame Rendering

If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.


Table of Contents:

Introduction: High-Performance Flutter as a Formal Engineering Discipline

Understanding Human Perception and Frame Budgeting

Deep Widget Rebuild Governance

Advanced Memory Management and Garbage Collection Strategy

CPU vs GPU Task Distribution

Flutter Isolates for Computational Offloading

Advanced Layout Optimization and Constraint Engineering

Image Pipeline Optimization: Memory-Safe Asset Processing

Shader Compilation Strategy & Impeller Optimization

Navigation and Route Performance Engineering

Micro-Optimizing Animations for Predictable Rendering

Performance Profiling Methodology Using Flutter DevTools

Comprehensive Performance Benchmarks

Enterprise-Level Flutter Case Studies

Platform Channels and Native Performance Influence

Comprehensive Flutter Performance Checklist

Final Conclusion: Flutter Performance as an Operational Standard

Reference


Introduction: High-Performance Flutter as a Formal Engineering Discipline

By 2025, Flutter performance has evolved into a specialized engineering domain rather than a simple best-practice exercise. High refresh-rate displays, foldable interfaces, real-time synchronization systems, and complex UI-driven business applications demand deterministic rendering behavior. A sub-60ms frame pipeline is no longer considered premium, but a baseline requirement for premium-grade mobile products.

This expanded and refined guide adopts an enterprise-level, developer-focused tone with heavy technical depth. It systematically dissects Flutter’s rendering internals, memory behavior, GPU pipeline management, architectural decisions, and system-level tuning strategies required to achieve stable frame rendering under consistent load.

This version goes beyond surface-level optimization, treating Flutter performance as a measurable system characteristic influenced by code structure, OS-level scheduling, GPU workload distribution, and runtime memory mechanics.

Primary SEO Keyword: Flutter Performance Optimization
 Supporting Keywords: Sub-60ms rendering, Flutter rendering pipeline, Flutter UI performance, Flutter DevTools profiling, High-performance Flutter architecture


Understanding Human Perception and Frame Budgeting

Human visual perception identifies animation jank when frame drops exceed temporal thresholds. While 60 FPS remains the industry benchmark, modern interfaces increasingly operate at 90Hz and 120Hz. This shifts the target frame budget significantly, pressuring developers to engineer every screen for consistency.

Frame Budget Targets

  • 60 FPS → 16.6ms per frame
  • 90 FPS → 11.1ms per frame
  • 120 FPS → 8.3ms per frame

Any processing delay beyond this threshold results in frame drops, causing visual inconsistencies such as flickering, stuttering, or delayed interactions. Achieving sub-60ms rendering while maintaining scalable design complexity is the hallmark of Flutter performance mastery.


Flutter Rendering Stack: Internal Pipeline Analysis

Flutter’s rendering architecture integrates multiple layers that collaboratively process UI instructions. This pipeline exists as a progression of deterministic processes executed within constrained time limits.

Full Rendering Pipeline Flow

Dart Execution Layer

Widget Tree Construction

Element Tree Diffing

RenderObject Computation

Layout Constraints Resolution

Paint Calls Generation

Layer Tree Compositing

GPU Rasterization (Skia / Impeller)

The UI thread is responsible for generating the scene graph, while the Raster thread handles GPU rendering. Bottlenecks at any level cause cascading frame drops, making it essential to optimize every stage.

Flutter 2025 introduces optimized Impeller as the default rendering backend, providing predictable shader behavior, reduced shader compile stutter, and stable GPU frame consistency. This replaces on-the-fly shader compilation delays that previously affected complex animations.


Deep Widget Rebuild Governance

Unregulated rebuild cycles remain the largest contributor to performance inefficiency. Widget rebuilding itself is not problematic, but uncontrolled rebuild scopes propagate unnecessary recalculations across the UI hierarchy.

A rebuild-heavy architecture results in excessive layout recalculations and paint cycles.

Rendering Impact Graph

User Action → Parent setState() → Entire Tree Rebuild → Re-layout → Repaint → Frame Delay

The ideal architecture localizes updates only to changed areas.

Optimized Rebuild Pattern

class PriceDisplay extends StatelessWidget {
final String value;
const PriceDisplay({super.key, required this.value});
  @override
Widget build(BuildContext context) {
return RepaintBoundary(
child: Text(
value,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
);
}
}

The RepaintBoundary ensures isolated repaint zones, preventing expensive redraws upstream.


Advanced Memory Management and Garbage Collection Strategy

Flutter employs automatic garbage collection, but careless object creation leads to performance degradation via GC pauses.

Memory Performance Engineering

  • Reuse controllers where possible
  • Avoid creating objects inside build methods
  • Cache frequently used objects
  • Monitor heap growth using DevTools

Frequent garbage collection cycles introduce unpredictable frame jitter, particularly in animation-heavy interfaces.


CPU vs GPU Task Distribution

Optimal performance requires balancing workload distribution. CPU-heavy logic delays widget build while GPU-intensive operations affect painting cycles.

Best Practices

  • Delegate data processing to isolates
  • Limit shadow usage
  • Minimize layer opacity stacking
  • Avoid alpha blending overloads

Flutter Isolates for Computational Offloading

Isolates allow parallel execution independent from the UI thread.

Future<int> heavyCalculation(int value) async {
return compute(_processData, value);
}
int _processData(int value) {
return value * value;
}

This architecture ensures UI thread remains unhindered.


Advanced Layout Optimization and Constraint Engineering

Constraint thrashing emerges when widgets repeatedly renegotiate size rules. Deep nested flex layouts amplify this issue.

Optimized Layout Hierarchy

High-Cost Structure:
Column
→ Column
→ Row
→ Column
Optimized Structure:
CustomScrollView
→ SliverList
→ SliverGrid

This dramatically reduces layout passes per frame.


Image Pipeline Optimization: Memory-Safe Asset Processing

Techniques

  • Prefer WebP over PNG
  • Use ResizeImage
  • Implement precacheImage
  • Use CachedNetworkImage
precacheImage(const AssetImage('assets/banner.webp'), context);

This ensures zero-latency asset rendering.


Shader Compilation Strategy & Impeller Optimization

Shader compilation was historically a major jank source. Impeller precompiles shaders, improving runtime stability.

Performance Strategy:

  • Avoid dynamic shader generation
  • Test shader-heavy UI early
  • Enable shader warm-up where required

Large navigation stacks degrade performance through memory pressure.

Professional Routing Strategy

  • Lazy load secondary screens
  • Cache frequently accessed routes
  • Dispose unused controllers properly

Micro-Optimizing Animations for Predictable Rendering

Animations should be GPU-driven with minimal recalculation.

AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: isExpanded ? 300 : 100,
height: 100,
);

Implicit animations reduce layout thrash compared to custom frame controllers.


Performance Profiling Methodology Using Flutter DevTools

Monitoring

  • UI Thread Timeline
  • Raster Thread Load
  • Memory Allocation Profiles
  • Hot Reload Hotspots

Profile mode offers closest real-world production metrics.


Comprehensive Performance Benchmarks

Production App Testing Results

Scenario Avg Frame Render Before Optimization After Optimization Home Dashboard 85ms Laggy 18ms Smooth Product List 72ms Janky 14ms Ultra Map Interaction 110ms Severe Lag 21ms Stable


Enterprise-Level Flutter Case Studies

Case Study: Banking Application Interface

Implementation of layered financial dashboards caused frame spikes.

Optimization Steps:

  • RepaintBoundaries segmented UI
  • Isolates for data aggregation
  • Sliver refactoring

Results:

  • FPS stabilized at 58–62
  • CPU load reduced by 41%

Case Study: Real-Time Analytics Dashboard

Performance Bottleneck: Excessive chart re-rendering during stream updates.

Solution:

  • Stream throttling
  • Chart caching layers
  • GPU compositing optimization

Outcome:

  • Rendering delay reduced from 120ms to 16ms

Platform Channels and Native Performance Influence

Excessive platform channel calls degrade performance. Reduce communication frequency and batch operations.

static const MethodChannel _channel = MethodChannel('native_bridge');
final response = await _channel.invokeMethod('fetchOptimizedData');

Prefer asynchronous batched calls for efficiency.


Production Performance Governance Model

A professional Flutter app adopts continuous performance regression tracking and performance gates before deployment.

Governance Framework

  • Performance regression alerts
  • CI-based DevTools profiling
  • Real-device stress testing
  • Performance SLAs

Future-Ready Flutter Performance Trends

Flutter performance evolution includes:

  • Advanced Impeller GPU pipeline
  • Dynamic frame scheduling
  • Improved garbage collector heuristics
  • Intelligent build tree pruning

Comprehensive Flutter Performance Checklist

  • Enforce const usage everywhere
  • Minimize build method logic
  • Implement RepaintBoundary strategically
  • Leverage isolates for processing
  • Pre-cache large assets
  • Avoid widget nesting abuse
  • Profile continuously

Final Conclusion: Flutter Performance as an Operational Standard

Flutter performance in 2025 defines application credibility. Achieving sub-60ms frame rendering demands disciplined architecture, systematic profiling, and continuous iterative improvements. This is not a one-time effort but a perpetual engineering cycle.

When performance becomes foundational rather than corrective, Flutter applications achieve premium fluidity, superior responsiveness, and enterprise-grade reliability, ensuring optimal user satisfaction and competitive longevity.

Flutter Performance Optimization is no longer just about speed; it is about architectural integrity, predictability, and engineering excellence.

References:

Flutter performance profiling
Diagnosing UI performance issues in Flutter.docs.flutter.dev

13 Ultimate Flutter Performance Optimization Techniques for 2025
Discover 13 Flutter performance optimization techniques to boost app speed. Improve your app’s performance easily with…www.f22labs.com

https://www.bacancytechnology.com/blog/flutter-performance


From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automationIoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:
 And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

How to Secure API Keys, Tokens & Secrets in Flutter Without Exposing Them

0

If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.


Table of Contents

Introduction

Why Hardcoding Secrets in Flutter Is a Critical Risk

Secrets That Must Never Be Public

The Golden Rule: Secrets Belong on the Server

Using Environment Variables During Development

Token-Based Authentication Flow

Using — dart-define for Build-Time Variables

Obfuscation and Minification

Secure Example Architecture Flow

Conclusion

Reference

Introduction

In modern mobile application development, security is no longer optional. Flutter developers routinely connect their applications to APIs for authentication, analytics, payments, maps, notifications, and cloud services. These integrations almost always require sensitive credentials such as API keys, access tokens, private secrets, or client credentials. The problem arises when these sensitive values are embedded directly inside the Flutter codebase, assuming they are safe because the app is compiled.

In reality, Flutter apps can be reverse engineered with basic tools. Attackers can inspect source strings, analyze network traffic, and extract secrets that were never meant to be public. Once exposed, these secrets can be used to perform unauthorized actions, drain paid resources, compromise user data, and damage the credibility of your product.

This in-depth guide explains how to secure API keys, tokens, and secrets in Flutter without exposing them. It focuses on real-world architecture, practical coding methods, and proven security patterns, with clear examples where necessary.


Why Hardcoding Secrets in Flutter Is a Critical Risk

When you hardcode secrets such as API keys or access tokens directly in your Flutter application, they become part of the compiled binary. Tools like JADX, APKTool, and Frida make it easy to inspect APK and IPA files. Even simple string scanning can reveal sensitive data buried in constants or configuration files.

This means that anyone with access to your app file can extract your secrets. These stolen keys can then be used to impersonate your application, exceed rate limits, rack up huge bills on paid APIs, or even access private user information. Obfuscation alone does not solve this problem, as it merely slows attackers rather than stopping them.

Understanding that a Flutter application runs on a user-controlled device is essential. Anything inside it should be treated as potentially exposed.


Secrets That Must Never Be Public

Sensitive data that should never be directly embedded in Flutter includes API keys, OAuth client secrets, JWT signing keys, database credentials, encryption private keys, Firebase admin credentials, payment gateway secrets, and third-party service tokens. If a credential grants direct access to a privileged system, it must remain server-side.


The Golden Rule: Secrets Belong on the Server

The safest architecture places all critical secrets on a backend server, not in the Flutter app. The Flutter client should only communicate with your backend API, which then securely communicates with external services.

The communication flow should look like this:

Flutter App → Your Backend Server → Third-Party API

This pattern ensures the Flutter app never directly sees or stores any sensitive key. The backend acts as a protective shield controlling authentication, authorization, logging, and filtering.


Using Environment Variables During Development

Environment variables help prevent secrets from being committed to your repository during development. A common practice is to use a .env file combined with the flutter_dotenv package.

Example .env file:

API_BASE_URL=https://api.yourserver.com
 MAPS_KEY=dev_key_here

Add .env to your .gitignore file to ensure it is not pushed to GitHub or shared accidentally.

Flutter usage example:

import 'package:flutter_dotenv/flutter_dotenv.dart';
Future<void> main() async {
await dotenv.load(fileName: ".env");
runApp(MyApp());
}
String apiBaseUrl = dotenv.env['API_BASE_URL'] ?? '';

While this protects secrets from being exposed in your repository, remember that the compiled app can still be analyzed. Therefore, environment variables are helpful but not a complete solution.


Secure Backend Proxy Approach

Instead of calling third-party APIs directly from Flutter, route all requests through your backend. This ensures all secrets remain secure in the server environment.

Flutter request example:

final response = await http.get(
Uri.parse('https://yourserver.com/api/weather'),
headers: {
'Authorization': 'Bearer \$userToken'
},
);

Backend Node.js example:

app.get('/api/weather', async (req, res) => {
const apiKey = process.env.WEATHER_API_KEY;
const response = await axios.get(`https://externalapi.com/data?key=${apiKey}`);
res.json(response.data);
});

This design ensures the Flutter client never receives or stores the third-party API key.


Secure Storage for Temporary Tokens

Temporary tokens such as session tokens or access tokens can be securely stored using Flutter’s secure storage solutions.

Example using flutter_secure_storage:

final storage = FlutterSecureStorage();
await storage.write(key: 'access_token', value: token);
String? token = await storage.read(key: 'access_token');

This data is encrypted using Android Keystore or iOS Keychain, making it significantly safer than SharedPreferences. However, this method should only be used for short-lived tokens, not permanent secrets.


Token-Based Authentication Flow

A secure Flutter app should rely on tokens provided by a backend. The process typically begins with user authentication, after which the backend generates an access token.

After successful login, the backend provides a JWT or similar token, which the Flutter app stores securely. Every subsequent request includes this token in the headers, allowing the backend to verify the user’s identity.

final response = await http.post(
Uri.parse('https://api.yourserver.com/login'),
body: {'email': email, 'password': password},
);
final token = jsonDecode(response.body)['access_token'];
await storage.write(key: 'access_token', value: token);

The backend manages token expiry and refresh rules, ensuring better control over authentication.


Using — dart-define for Build-Time Variables

Flutter allows injecting values at build time using dart-define. This is ideal for environment-based configuration like staging or production URLs.

Build command example:

flutter build apk --dart-define=API_URL=https://api.production.com

Access inside Flutter:

const apiUrl = String.fromEnvironment('API_URL');

This is suitable for configuration values but still not recommended for highly sensitive secrets.


Obfuscation and Minification

Flutter provides code obfuscation features that make reverse engineering more difficult.

flutter build apk --obfuscate --split-debug-info=./debug-symbols

While this improves complexity for attackers, it must not be relied upon as a primary security method. It works best when combined with backend-based secret protection.


Encrypting Local Data

Encryption adds another layer of protection for locally stored sensitive information. Using libraries like encrypt or pointycastle allows encryption before storage.

Example:

final key = Key.fromUtf8('32charsecretkeyforencryption!');
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
f
final encrypted = encrypter.encrypt('Sensitive Data', iv: iv);
final decrypted = encrypter.decrypt(encrypted, iv: iv);

However, encryption loses effectiveness if the encryption key is embedded in the app. Therefore, it should complement server-based security strategies.


Certificate Pinning and Secure Network Channels

Always use HTTPS and enforce certificate pinning to prevent man-in-the-middle attacks. Libraries like Dio support SSL pinning to ensure communication only with your verified server.

This significantly reduces the risk of intercepted network traffic exposing authentication tokens or session data.


Common Mistakes Developers Must Avoid

Many Flutter developers unintentionally compromise security by placing API keys in constants files, logging secrets to the console, storing credentials in plaintext, or uploading configuration files to public repositories. These mistakes are avoidable by carefully auditing code and adopting strict development standards.


CI/CD and Secret Management

Modern development teams use CI/CD pipelines to manage secrets securely. Platforms such as GitHub Actions, GitLab CI, and Bitrise support encrypted variables that inject secrets during automated builds without exposing them in code.

This ensures that secrets remain protected throughout the deployment lifecycle.


Real-World Secure Architecture

A well-designed Flutter architecture includes a backend gateway that authenticates and authorizes every request. This layered structure ensures that the app itself never handles sensitive credentials directly.

Each request is verified, logged, rate-limited, and encrypted, dramatically reducing the risk of abuse.


How to Rotate Compromised Secrets

When a secret is exposed, immediate action is required. Always revoke the compromised key at the source, generate a new one, update backend configurations, and monitor system usage for abnormal behavior. Regular key rotation is a healthy security practice.


Enterprise-Level Secret Management

Large-scale applications often rely on secret management services such as AWS Secrets Manager, Google Secret Manager, Azure Key Vault, or HashiCorp Vault. These tools dynamically supply secrets to servers while controlling access and auditing usage.

This level of control ensures secrets are never hardcoded and always delivered securely when needed.


Secure Example Architecture Flow

The Flutter app authenticates users and receives a session token. This token is securely stored and used for API access. The backend verifies the token before accessing any third-party services, ensuring secrets never leave the secure environment.

This system supports logging, access control, token expiration, and intrusion detection mechanisms.


Conclusion

Securing API keys, tokens, and secrets in Flutter is not achieved through a single technique but through a strategic combination of backend delegation, secure storage, encrypted communication, token-based access, and disciplined development practices. Your Flutter application should never contain critical secrets that can compromise your system.

When implemented properly, these practices protect your infrastructure, user data, financial resources, and business reputation. Security must be treated as a core feature, not an afterthought.

By following the secure architectural principles and practical coding examples discussed in this guide, you can significantly reduce the risk of exposure and build Flutter applications that are production-ready and resilient against modern security threats.

If you need architectural diagrams, production-ready templates, or implementation guides for specific APIs, feel free to ask.


At What the Flutter, we love working with Flutter apps to make them high-performing that delight users. Contact us today to discuss how we can optimize your Flutter app performance.

Thanks for reading this article

If I got something wrong? Let me know in the comments. I would love to improve.

Clap

If this article helps you.


References:

Correct way of storing API Keys in flutter following best practises
Which is the correct way(best practice) of adding secret API keys in flutter in case I want to push the code on github…stackoverflow.com

How to Secure Your API Keys in Flutter (Step-by-Step)
Want to keep your Flutter apps safe and secure? ▶️ Learn best practices for securing API keys in Flutter with our…www.cogniteq.com

How to Store API Keys in Flutter: –dart-define vs .env files
An overview of different techniques for storing API keys on the client, along with security best practices to prevent…codewithandrea.com


From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automationIoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:
 And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Securely Storing Local Data in Flutter

0

Introduction

In mobile development, crafting fluid UIs and responsive animations is just one part of building a high-quality app. The less visible — but arguably more critical — side of that effort is data security.Whether your Flutter app stores authentication tokens, onboarding flags, payment preferences, or user profile data, how that data is stored locally matters a lot more than many developers initially realize.

In development, it’s tempting to use shared_preferences because it’s simple, persistent, and doesn’t require setup. But convenience comes with trade-offs:

The data saved shared_preferences is stored in plaintext.
 That means if the device is rooted, jailbroken, or an attacker simply has debugging access to the app’s data directory, they can extract sensitive information effortlessly.

This isn’t a theoretical risk — it’s a real-world vulnerability. Consider:

  • A malicious user reverse-engineering your APK or IPA
  • Someone gaining access to your app’s sandbox and reading stored session keys
  • A debugging proxy or compromised emulator dumping local data to logs

If you’re storing even moderately sensitive values like JWTs, OAuth tokens, user IDs, or app logic toggles (e.g., “isAdmin” or “hasPremiumAccess”), you’re opening the door to account takeover, impersonation, and data leakage.

So how do we address this in Flutter?

That’s where the concept of secure local storage using encrypted shared preferences comes into play. Flutter offers secure storage solutions like:

  • flutter_secure_storage: For simple key-value storage using the platform’s native Keystore or Keychain
  • Hive with AES encryption: For structured, performant, and encrypted data models
  • local_auth: For adding biometric authentication gates like Face ID or fingerprint before data access

Why You Need Secure Local Storage

In Flutter (and mobile development in general), it’s common to use packages like shared_preferences or standard file APIs to store user data locally. They’re fast, simple, and convenient — but they lack one critical feature: security.

The Problem with Plaintext Storage

By default, tools like shared_preferences save data as unencrypted plaintext — meaning it’s written directly to the device’s local file system in a human-readable format. Anyone with access to the filesystem can open and read this data. On a stock Android or iOS device, that may sound safe. But consider:

  • Rooted Android devices allow full file system access, bypassing app sandboxes
  • Jailbroken iPhones similarly grant low-level access to app data folders
  • Debug builds (especially during testing) often lack protections and leak data in logs
  • Physical theft of a phone could expose local storage if biometric/PIN protection is weak

If your app stores authentication tokens, user profile data, feature flags, or medical/personal identifiers, saving them insecurely puts you at risk of:

  • Session hijacking: An attacker copies the access token and impersonates the user
  • Account takeover: A reused refresh token could be used to continuously re-authenticate
  • Data privacy violations: Violating GDPR, HIPAA, or other compliance frameworks
  • Security audit failures: If your app handles sensitive data, insecure storage can fail app store reviews or vendor certifications

Real-World Risks

Apps like banking, healthcare, or enterprise tools are especially vulnerable:

  • A health tracking app leaking user vitals or activity data
  • A corporate field agent app exposing business logic through saved feature toggles
  • A messaging app saving session tokens that allow impersonation

Even if you think the data is low-risk, once combined with other app info, it can become a vector for privilege escalation or reverse engineering.

The Modern Minimum: Encrypt, Gate, Isolate

To secure data properly in 2025, a basic checklist includes:

  • Encryption at rest: Ensure sensitive data is stored using AES or similar ciphers
  • Secure key storage: Store encryption keys using OS-provided keystores (Keychain, Keystore)
  • Biometric gating: Require Face ID / fingerprint to access certain data
  • Tamper detection: Detect if the device is rooted or jailbroken, and limit data access

Flutter gives you tools like flutter_secure_storage, Hive with encryption, and local_auth to meet these requirements. Using them isn’t just a best practice — it’s an essential layer in protecting both your app and your users.

In short:

If it’s valuable enough to store, it’s valuable enough to protect.

Don’t treat local storage as a cache — treat it as an extension of your backend security model.


Available Secure Storage Solutions for Flutter

Here’s a breakdown of the major options:


Choosing the Right Secure Storage in Flutter:

When to Use Which Solution

As a Flutter developer, you need to pick your storage tool based on what you’re storing, how sensitive it is, and how often you access it.


What Technical Trade-Offs to Consider

Each secure storage option in Flutter comes with strengths and caveats.

flutter_secure_storage

Pros:

  • Uses Android Keystore and iOS Keychain for storing secrets securely.
  • Supports biometric protection out of the box.
  • Simple key-value interface.

Cons:

  • Not built for large or complex structured data.
  • Slight overhead for keychain/keystore reads/writes.
  • Doesn’t support non-string values.

Best For: Access tokens, session flags, login states.

Hive with AES Encryption

Pros:

  • Super-fast local NoSQL database.
  • Good for structured or repeated access data (e.g. cached user profile, offline forms).
  • Built-in encryption using a 256-bit AES key.

Cons:

  • You are responsible for key management (securely storing the encryption key).
  • Slightly higher learning curve for data modeling.
  • Encryption adds performance cost at scale (e.g., >1MB blobs).

Best For: Offline-first apps, encrypted forms, app-specific user models.

EncryptedSharedPreferences

Pros:

  • Familiar interface (like shared_preferences) but with encryption.
  • Great drop-in replacement for low-effort upgrade.

Cons:

  • Less flexible than Hive for complex models.
  • May lack maintenance or support vs more established packages.

Best For: Simple apps needing quick security hardening.


How These Tools Work Internally

Understanding how these libraries handle security under the hood is key to trusting your implementation.

flutter_secure_storage internals:

On Android:

  • Uses the Android Keystore to generate or store a cryptographic key.
  • That key is used to encrypt/decrypt your values.
  • Encrypted values are saved in SharedPreferences, but they are unreadable without the key.

On iOS:

  • Leverages the Keychain.
  • Secure by design and automatically protected by system-level biometric gating (if enabled).

Hive with AES Encryption:

  • Stores encrypted data in a local file.
  • You provide a 256-bit AES key (Uint8List) when opening a box.
  • Hive encrypts each record on write and decrypts on read.
  • You must store the AES key separately — often via flutter_secure_storage.
// Example: Hive box with encryption
final encryptionKey = await secureStorage.read(key: 'hive_key');
// Assuming encryptionKey is a Base64 string

final key = base64Url.decode(encryptionKey);
final box = await Hive.openBox('secureBox',
encryptionCipher: HiveAesCipher(key),
);

Storing Structured Data Securely

1. Using flutter_secure_storage

Getting Started: Step-by-Step Guide

1. Install Required Packages

Add the following dependencies to your pubspec.yaml:

dependencies:
flutter_secure_storage: ^9.0.0

Run flutter pub get.

2. Create a Secure Storage Helper Class

Create a reusable service to abstract all secure storage logic.

import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureStorageService {
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<void> write(String key, String value) async {
await _storage.write(key: key, value: value);
}
Future<String?> read(String key) async {
return await _storage.read(key: key);
}
Future<void> delete(String key) async {
await _storage.delete(key: key);
}
Future<void> clearAll() async {
await _storage.deleteAll();
}
}

3. Store and Retrieve Data

final storage = SecureStorageService();
// Storing a token securely
await storage.write('auth_token', 'eyJhbGciOi...');
// Reading the token
final token = await storage.read('auth_token');
// Deleting the token
await storage.delete('auth_token');

Real-World Example: Secure Login State

class AuthRepository {
final SecureStorageService _secureStorage = SecureStorageService();
Future<void> login(String token) async {
await _secureStorage.write('auth_token', token);
}
Future<bool> isLoggedIn() async {
final token = await _secureStorage.read('auth_token');
return token != null;
}
Future<void> logout() async {
await _secureStorage.delete('auth_token');
}
}

2. Using Hive

Key-value pairs are fine for simple use cases, but what if you need to persist entire objects (e.g., user profiles, session objects, offline orders)?

Use Hive — a fast, lightweight, and local NoSQL DB — with AES encryption.

  1. Add Dependencies
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
path_provider: ^2.0.11
encrypt: ^5.0.1

2. Generate Encryption Key

You can store the encryption key securely using flutter_secure_storage.

import 'dart:convert';
import 'dart:math';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
Future<String> generateEncryptionKey() async {
final secureStorage = FlutterSecureStorage();
var key = await secureStorage.read(key: 'hive_key');
if (key == null) {
final keyBytes = List<int>.generate(32, (i) => Random.secure().nextInt(256));
key = base64UrlEncode(keyBytes);
await secureStorage.write(key: 'hive_key', value: key);
}
return key;
}

3. Initialize Hive with Encryption

import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:encrypt/encrypt.dart';

Future<void> initHive() async {
final dir = await getApplicationDocumentsDirectory();
Hive.init(dir.path);
final keyStr = await generateEncryptionKey();
final encryptionKey = base64Url.decode(keyStr);
final encryptedBox = await Hive.openBox(
'secureBox',
encryptionCipher: HiveAesCipher(encryptionKey),
);
await encryptedBox.put('user_profile', {'name': 'Alice', 'email': 'alice@example.com'});
final data = encryptedBox.get('user_profile');
print(data); // Output: {name: Alice, email: alice@example.com}
}

Hive + AES lets you store entire objects securely, without exposing data in storage.


Challenges You Should Plan For

Remember: encrypted local storage is still local — it doesn’t sync across devices by default.


Future Outlook (2025–2030)

Flutter secure storage practices are evolving fast:

  • Passkey support: Flutter will gain tighter integration with platform credential managers
  • Hardware-backed keys: Secure Enclave (iOS) and StrongBox (Android) will be easier to use via wrappers
  • End-to-end encrypted sync: Cloud-based backup/restore of encrypted data
  • App attestation APIs: Allow secure detection of rooted/jailbroken devices before unlocking local stores

As regulations like GDPR, HIPAA, and ISO tighten, Flutter apps will be expected to match the security bar of native apps.


Conclusion

As a Flutter developer, don’t just ask: “How do I store data locally?”
 Ask: “What happens if someone dumps my app’s storage tomorrow?”

Choosing the right secure storage library is about risk mitigation, code maintainability, and user trust.

Secure local storage isn’t about checking boxes — it’s about respecting user data and avoiding preventable breaches. Flutter gives you the tools:

  • Use flutter_secure_storage for secrets and tokens
  • Combine it with local_auth for biometric-protected access
  • Store structured, encrypted data using Hive

Building these layers now sets your app up for scale, compliance, and user trust.

As Flutter continues maturing, encryption and security will be first-class concerns, not afterthoughts. Build with security from day one, and your users will thank you with loyalty and peace of mind.


Thanks for reading this article

If I got something wrong? Let me know in the comments. I would love to improve.

Clap

If this article helps you.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Flutter vs React Native in 2025: A Developer’s Perspective

0

Introduction

As a mobile developer in 2025, I often alternate between Flutter and React Native depending on project scope, client needs, and performance expectations. Both frameworks have matured, and choosing one is no longer a matter of hype — it’s a strategic engineering decision.

In this blog, I’ll break down the key differences between Flutter and React Native from a practical, developer-first viewpoint. I’ll also include real code snippets, tooling comparisons, and tips based on current ecosystem status.


1. Market Position in 2025

Both Flutter and React Native continue to dominate cross-platform development.

  • Flutter is now heavily adopted in enterprise-grade apps and multi-platform workflows (web, mobile, desktop).
  • React Native remains strong with startups, MVPs, and teams already embedded in the JavaScript/React ecosystem.

Community & Popularity in 2025

Flutter

  • GitHub Activity: Flutter continues to receive strong attention on GitHub, with active issue discussions, regular commits, and contributions from both Google and the open-source community. Many of the most-used packages are now maintained by the core team or long-term contributors, increasing stability and trust.
  • Stack Overflow Presence: In 2025, Flutter has seen a steady rise in developer questions, answers, and tutorials. The growth reflects increased adoption in both enterprise and solo development. Stack Overflow answers are detailed, up-to-date, and often link to official documentation or code samples.
  • Job Market Demand: Flutter job opportunities have significantly increased, especially in sectors like fintech, healthcare, and logistics. Many companies are seeking Flutter developers for multi-platform roles — covering mobile, web, and desktop in a single codebase. The demand is especially strong in regions like Europe, India, and South America.
  • Community Resources: Popular conferences (e.g., Flutter Forward, Google I/O sessions) and YouTube channels have helped grow a very structured learning path. Flutter meetups and communities are active in local and online spaces.

React Native

  • GitHub Activity: React Native remains a powerhouse in open-source development. Maintained by Meta (formerly Facebook) and supported by thousands of contributors, the project sees constant improvements. Key features like the new architecture (Fabric, TurboModules) are now stable and widely adopted.
  • Stack Overflow Presence: The framework enjoys a large pool of answered questions due to its longevity. While the growth rate of questions has stabilized, the knowledge base is mature. Developers benefit from years of community experience, often solving common challenges quickly.
  • Job Market Demand: React Native remains one of the top job skills in mobile app development. It is still widely preferred in startups and mid-sized companies, especially those already using JavaScript, Node.js, or React for their web stacks. TypeScript proficiency alongside React Native is often expected.
  • Community Resources: The ecosystem benefits from deep JavaScript integration. Many community-led libraries, Expo’s managed workflow, and commercial support (like Microsoft’s macOS contributions) make React Native feel approachable and flexible.

2. Performance Comparison

Flutter

  • Native Compilation: Flutter compiles Dart directly into native ARM code, offering optimized runtime performance for both Android and iOS. This allows apps to bypass traditional JS bridges and interact with native APIs more efficiently.
  • Rendering Engine: Uses the Skia graphics engine to render UI components. This means the UI is drawn directly on the canvas rather than relying on platform-specific components, resulting in consistent visuals across platforms.
  • Smooth UI & Animations: Flutter continues to offer buttery-smooth animations. With tools like CustomPainter, AnimatedBuilder, and the flutter_animate package, even advanced motion UIs perform seamlessly.
  • Predictable Frame Rates: Developers can reliably achieve 60fps or 120fps frame rates, depending on the device, thanks to efficient frame scheduling and Dart’s single-threaded event loop.
  • Best Suited For:
  • Complex, custom UIs
  • Animation-heavy apps
  • Performance-critical enterprise apps
  • Consistent behavior across a wide range of devices

React Native

  • JavaScript Interface (JSI): React Native’s adoption of JSI and Hermes engine has modernized its architecture. With JSI, the bridge between JavaScript and native code is faster and more flexible, enabling better performance than earlier versions.
  • Hermes Engine: Now the default JS engine for React Native apps. It reduces startup time, memory usage, and improves overall responsiveness of apps, especially on Android.
  • Multithreaded Architecture: React Native still executes JavaScript logic on a separate thread while the UI updates occur on the main thread. While this can improve concurrency, it sometimes leads to race conditions or performance hiccups in complex apps.
  • Optimized for Real-time Features: Apps involving real-time interactions (chat, streaming, dashboards) benefit from React Native’s async handling capabilities — especially with React 18’s concurrent features.

Best Suited For:

  • Apps with moderate UI complexity
  • Startups needing quick iteration cycles
  • Teams already invested in the JavaScript/React stack
  • Apps relying on real-time data or integrations

3. UI & Design Capabilities

Flutter

  • Widget-Based Architecture
     Flutter uses a fully custom UI toolkit built in Dart. Every element on screen — from text to animations — is a widget. This allows developers full control over layout, styling, and behavior.
  • Pixel-Perfect Rendering
     With Skia as the rendering engine, Flutter draws every pixel independently of the underlying platform. This ensures that the UI looks the same across iOS, Android, web, and desktop, with no platform-specific inconsistencies.
  • Material & Cupertino Widgets
     Flutter offers first-party support for both Material Design (Android) and Cupertino (iOS) styles. You can use either or blend both in a single app.
  • Declarative UI Coding
     Flutter’s declarative approach allows concise and expressive UI code. Here’s an example:
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(10),
),
child: Text('Hello from Flutter!'),
),
),
),
);
  • Great for Custom Designs
     Building complex, animated, or branded interfaces is easier in Flutter due to its layered and flexible rendering stack.

Best Suited For:

  • Cross-platform UI consistency
  • Custom-designed interfaces
  • High-fidelity prototyping
  • Designers working closely with developers

React Native: 

  • Native Components First
     React Native uses platform-native components under the hood. A <View> in React Native maps to a native UIView on iOS and a ViewGroup on Android. This gives apps a “native” feel out of the box.
  • StyleSheet-Based Design
     Styling is done using a simplified CSS-like system. This makes it intuitive for web developers but can be limiting for highly customized UI.
  • JSX Syntax
     The UI is defined in JSX, allowing a clean separation of logic and layout. Here’s an example:
import { View, Text, StyleSheet } from 'react-native';

export default function App() {
return (
<View style={styles.container}>
<Text>Hello from React Native!</Text>
</View>
);
}

const styles = StyleSheet.create({
container: {
padding: 20,
backgroundColor: 'skyblue',
borderRadius: 10,
},
});
  • Responsive Design Considerations
     Due to reliance on native components, UI behavior can vary slightly between platforms. Developers often need to write platform-specific tweaks to achieve visual parity.

Best Suited For:

  • Apps requiring a native look and feel
  • Teams with React/web development experience
  • MVPs and fast iteration cycles
  • Apps targeting only mobile (iOS & Android)

Verdict:

  • Flutter: Best for UI consistency and custom design.
  • React Native: Better for apps needing platform-native feel.

4. Developer Experience

Flutter:

  • Dart is clean, typed, and modern.
  • Robust tooling with Android Studio, VS Code, and Flutter DevTools.
  • Structured, opinionated architecture.

React Native:

  • Leverages JavaScript/TypeScript — familiar for web developers.
  • Better integration with existing web and Node.js codebases.
  • Hot reload works well, but native linking/debugging can be complex.

Verdict:

  • Choose Flutter for a clean architecture and self-contained stack
  • Choose React Native if your team already uses JS/React.

Flutter

  • Strong Official Plugin Support
     Flutter’s core team maintains essential plugins like:
  • camera: For image and video capture
  • webview_flutter: Embeds web content
  • google_maps_flutter: Google Maps integration
     These are stable, actively updated, and optimized for performance.
  • Mature Community Packages
     The Flutter ecosystem includes high-quality, developer-trusted libraries:

flutter_bloc: Scalable state management

go_router: Declarative and nested routing

hive: Lightweight NoSQL database for local storage

flutter_hooks: Reduces boilerplate in widget logic

  • Package Stability & Documentation
     Increasing adoption by large enterprises has pushed the community to improve code quality, documentation, and long-term support.
  • FlutterFire Suite
     A first-party integration with Firebase, enabling seamless use of services like Auth, Cloud Firestore, Analytics, and Messaging.

Best Suited For:

  • Teams preferring official and maintained libraries
  • Developers who prioritize stability and fewer runtime issues
  • Projects with long-term maintainability goals

React Native

  • Vast Library Ecosystem
     React Native benefits from the broader JavaScript and Node.js community. There are thousands of libraries available for almost any need, from UI kits to device features.
  • Third-Party and Community Plugins
     While there’s variety, some plugins rely on community bridges or aren’t actively maintained. Developers often evaluate libraries for update frequency and iOS/Android parity.

Popular Libraries in Use:

react-navigation: Widely used for routing and navigation

redux-toolkit: Scalable state management

react-native-maps: Map integrations

react-native-reanimated: Smooth animations

  • Expo Framework
     Expo simplifies development and testing, especially for new developers. However, it has limitations around custom native code unless you eject the app from the managed workflow.
  • Open Source Culture
     Many companies (like Shopify and Microsoft) contribute actively to React Native, pushing the ecosystem forward with modern practices and architectural improvements.

Best Suited For:

  • Projects needing a broad set of JS-compatible libraries
  • Developers coming from a web background
  • Teams already using React in other platforms (e.g., web, TV)

6. Web & Desktop Support

Flutter

  • Production-Ready Across Platforms
     Flutter supports web, Windows, macOS, and Linux with stable releases. Developers can use a single codebase to build and deploy across all major platforms.
  • Consistent Developer Experience
     Whether you’re building for mobile or desktop, Flutter’s development flow remains the same — no separate setup or tooling required.

UI and Performance on Desktop
 Desktop support includes native windowing, mouse/keyboard input, and resizable UI — making Flutter great for:

  • Admin dashboards
  • Enterprise tools
  • Internal utilities

Web Performance
 Web support has improved, with better rendering, faster load times, and reduced bundle sizes in production builds.

Use Cases:

  • Building internal business tools quickly
  • Offering companion web apps alongside mobile apps
  • Deploying PWAs or full desktop applications

React Native

Limited but Evolving Support
 React Native is still primarily mobile-focused. Some support for desktop exists via community-driven efforts like:

  • react-native-web for browser-based apps
  • react-native-windows and react-native-macos (led by Microsoft)
  • Platform Support Caveats
     These extensions are not officially core-maintained, and platform parity can be inconsistent. Features that work seamlessly on mobile may require workarounds or native bridging on web/desktop.

Ideal Scenarios:

  • Building mobile apps with some web extension
  • Integrating small UI elements into existing web platforms
  • Teams using React across web and native apps

Not Recommended For:

  • Full-featured desktop apps
  • Projects needing seamless multi-platform output from a single codebase

7. Community & Learning Curve

Flutter

Developer Learning Curve

  • Uses Dart, which may be unfamiliar to new devs (especially web developers).
  • Once learned, Dart offers strong typing, excellent tooling, and a modern syntax similar to Swift/Kotlin.
  • UI development is declarative and tightly integrated with widgets — you build everything in code (including layout).
  • Requires understanding of widget trees, state management (e.g., Riverpod, Bloc), and Flutter’s custom rendering system.

Community Growth

  • The Flutter community has grown rapidly, especially in Asia, Europe, and South America.
  • Google’s official support plus open-source contributions have led to stable, well-documented packages.
  • Strong presence in forums like GitHub, Stack Overflow, Reddit, and Discord.

Learning Resources

  • Excellent documentation on flutter.dev
  • Plenty of free and paid tutorials, courses, and YouTube content.
  • Official sample apps, code labs, and templates available.

React Native

Developer Learning Curve

  • Based on JavaScript, which is already known by millions of developers.
  • Integrates well with React, making it easy for web developers to transition to mobile.
  • Uses familiar concepts like components, hooks, and props/state — especially appealing to full-stack JS developers.
  • Tooling and ecosystem knowledge (e.g., Node.js, npm, Babel, Metro bundler) help ease setup.

Community Maturity

  • Larger community overall, with contributions from Facebook (Meta), Microsoft, Shopify, and open-source developers.
  • However, the community is fragmented due to:
  • Many navigation libraries (react-navigation, react-native-router-flux)
  • Multiple state management options (Redux, MobX, Zustand, etc.)
  • Varying levels of package maintenance

Learning Resources

  • Abundant tutorials, blog posts, GitHub examples, and Stack Overflow discussions.
  • Community-driven projects and Expo offer a beginner-friendly starting point.
  • More content overall, but can sometimes be outdated or inconsistent.

8. Real-World Apps in 2025

A framework’s maturity is best reflected in the kinds of apps built with it. In 2025, both Flutter and React Native have powered major applications — though their adoption patterns differ based on goals like design control, speed to market, and platform reach.

Flutter-Powered Apps (2025)

These apps often demand highly custom UIs, performance consistency across platforms, and multi-device support:

  • BMW (My BMW App)
  • Delivers a fully branded, visually rich experience across iOS and Android.
  • Uses Flutter’s custom rendering to maintain UI parity across car systems and phones.

Google Pay (India, Global versions)

  • Handles real-time payments, security-sensitive interactions, and animations.
  • Flutter helps Google maintain one codebase across mobile and future web dashboards.

Alibaba (Xianyu App)

  • One of the earliest large-scale Flutter adopters.
  • Leverages Flutter’s speed and native-like feel for an e-commerce experience with high traffic.

Nubank (Latin America’s digital bank)

  • Uses Flutter for rapid iteration and visual consistency.
  • Crucial for fintech apps needing strict design control and security compliance.

Other Use Cases

  • Enterprise dashboards, health monitoring apps, POS systems.
  • Particularly favored in fintech, healthcare, and internal enterprise tools where multi-platform delivery matters.

React Native-Powered Apps (2025)

These apps are typically in ecosystems where speed, developer availability, and JavaScript integration are essential:

Instagram

  • Uses React Native in parts of the app to prototype and ship features faster across platforms.
  • Reuses components between mobile and web (React).

Pinterest

  • Implements React Native modules where needed for dynamic UI and feed interaction.

Discord

  • Relies on React Native for parts of the mobile interface.
  • Integrates tightly with its existing web-based React architecture.

Shopify (partial modules)

  • Uses React Native for some internal tools and select app sections.
  • React Native fits well with their full-stack JavaScript preference.

Coinbase

  • Known to use React Native in parts of their customer-facing app for quick deployments and JS-team integration.

Developer Takeaways

Flutter is preferred when:

  • You want control over UI on every screen.
  • You’re building for multiple platforms (desktop, mobile, web).
  • Performance and consistent UX matter more than rapid MVP delivery.

React Native is ideal when:

  • You already have a JavaScript-heavy team.
  • Your priority is faster go-to-market or shared logic between web and mobile.
  • You’re optimizing for mobile platforms only, without immediate plans for web/desktop.

9. When to Choose What — Decision Table (2025 Developer Guide)

Choosing between Flutter and React Native in 2025 depends on your project scope, team background, and platform requirements. Below is a clear decision matrix to guide your choice based on common development criteria.


Final Thoughts: My Developer Take in 2025

In 2025, both Flutter and React Native have matured into reliable, production-ready frameworks. As a developer who actively works with both, I don’t believe in a one-size-fits-all approach — the right choice always depends on the context.

When I Choose Flutter

I reach for Flutter when:

  • The app demands high-performance animations or handles complex UIs.
  • I’m targeting multiple platforms (mobile, desktop, web) from a single codebase.
  • The design requires custom UI/UX that must look exactly the same across devices.
  • I want tighter control over rendering and layout without platform-specific workarounds.

When I Choose React Native

I go with React Native when:

  • I’m building MVPs or prototypes that need to ship fast.
  • The team already works in a JavaScript/React ecosystem, reducing ramp-up time.
  • The app is mobile-only, and I want to reuse React-based business logic.
  • Community-driven tools or third-party integrations are key to the project.

The Core Principle

There is no “best” framework — only the best fit for your project and team.

Some apps need Flutter’s UI power and cross-platform scope. Others benefit from React Native’s speed and developer familiarity.

As developers in 2025, our responsibility is to make informed, strategic choices — not follow trends. With both Flutter and React Native in your toolkit, you’re equipped to handle a wide range of use cases.


Thanks for reading this article

If I got something wrong? Let me know in the comments. I would love to improve.

Clap

If this article helps you.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Flutter Apps with AI and Machine Learning

0

Introduction


In recent years, Artificial Intelligence (AI) and Machine Learning (ML) have emerged as transformative technologies across multiple industries, including mobile development. From predictive recommendations to image recognition and natural language understanding, these technologies are powering a new era of intelligent, user-centric apps.

At the same time, Flutter, Google’s open-source UI toolkit, has rapidly gained popularity for building natively compiled applications for mobile, web, and desktop using a single codebase. But what happens when we merge the power of AI/ML with Flutter’s cross-platform efficiency?

The result is a powerful toolkit that allows developers to build dynamic, intelligent mobile apps that can not only respond to user input but also learn, adapt, and optimize over time.

In this blog, we’ll explore how you can integrate AI and ML into your Flutter apps, the tools available, and walk through a step-by-step implementation of an image classification feature using TensorFlow Lite.

If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.


Table of Contents:

Introduction

Why Use AI/ML in Flutter Apps?

Ways to Integrate AI/ML in Flutter

Practical Walkthrough

Expanding Possibilities

Key Challenges

Final Thoughts

Resources


2. Why Use AI/ML in Flutter Apps?

Integrating AI/ML into Flutter applications can significantly enhance the user experience. Here’s why developers are increasingly combining these technologies:

  • Personalization: AI enables apps to tailor content, UI, and workflows based on individual user behavior. Think personalized product suggestions, dynamic feed curation, or adaptive settings based on usage patterns.
  • Smarter Automation: Repetitive or complex tasks — like detecting faces in photos or transcribing audio — can be automated using pre-trained ML models, drastically reducing manual effort.
  • Enhanced Features: From language translation to predictive analytics, ML unlocks functionalities that were previously hard to implement in mobile environments.
  • Intelligent Insights: Understanding how users interact with your app, predicting churn, or recommending next actions becomes easier with AI-driven analytics baked into your Flutter stack.
  • Improved Engagement: Flutter, with its rich plugin ecosystem and support for native and cloud integrations, is well-positioned to support AI/ML use cases at scale on both Android and iOS.

By integrating AI/ML, developers can create apps that are not just reactive but predictive, adaptive, and context-aware.


3. Ways to Integrate AI/ML in Flutter

There are multiple strategies for bringing AI/ML capabilities to your Flutter apps, depending on your project’s requirements and complexity.

a. Using Pre-trained Models

One of the easiest ways to get started is by using pre-trained models that have been optimized for mobile devices. Tools include:

  • TensorFlow Lite: A lightweight version of TensorFlow designed for on-device inference.
  • Google ML Kit: Provides a suite of easy-to-use APIs for text recognition, face detection, barcode scanning, and more.

This approach is ideal for developers looking to implement proven ML capabilities quickly.

b. Custom Models

When your use case is particular — identifying rare plant species or classifying industrial equipment — you’ll want to train your model.

Using platforms like TensorFlow or PyTorch, you can build and train a model, convert it to .tflite format, and run it within your Flutter app using plugins like tflite_flutter.

This gives you full control over the model’s behavior, but also requires knowledge of data science and model optimization for mobile.

c. Cloud-based APIs

When on-device processing is not feasible due to model size or complexity, cloud solutions come into play:

  • Google Cloud AI Platform
  • Firebase ML
  • Amazon SageMaker / AWS AI Services
  • Microsoft Azure Cognitive Services

These platforms offer scalable solutions for tasks like natural language processing, vision recognition, translation, and much more.


4. Practical Walkthrough: Image Classification Using TensorFlow Lite

Let’s build a simple Flutter app that can classify images using a pre-trained MobileNet model via TensorFlow Lite.

Step 1: Initialize a Flutter Project

flutter create flutter_ml_demo
cd flutter_ml_demo

Step 2: Add Required Packages

In pubspec.yaml, add:

dependencies:
tflite_flutter: ^0.9.0
image_picker: ^1.0.0
flutter:
sdk: flutter

Step 3: Download and Add the Model

Get a pre-trained MobileNet model from TensorFlow Lite Model Zoo. Add the .tflite model file and the associated labels.txt into your project’s assets/ folder.

Update your pubspec.yaml:

flutter:
assets:
- assets/mobilenet_v1.tflite
- assets/labels.txt

Step 4: Load the Model

Create a helper class to load the model:

import 'package:tflite/tflite.dart';

Future<void> loadModel() async {
String? res = await Tflite.loadModel(
model: "assets/mobilenet_v1_1.0_224.tflite",
labels: "assets/labels.txt",
);
print(res);
}

Call loadModel() in your initState().

Step 6: Pick an Image

import 'package:image_picker/image_picker.dart';
File? _image;

Future<void> pickImage() async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(source: ImageSource.gallery);

if (pickedFile != null) {
setState(() {
_image = File(pickedFile.path);
});
classifyImage(_image!);
}
}

Step 6: Run Preprocessing & Inference

You’ll need to resize the image to the model’s input dimensions (e.g., 224×224), normalize pixel values.

Future<void> classifyImage(File image) async {
var output = await Tflite.runModelOnImage(
path: image.path,
imageMean: 127.5,
imageStd: 127.5,
numResults: 5,
threshold: 0.5,
);
print(output);
}

Step 7: Display the Output


Display the output in your widget tree using setState() to update a result variable.


5. Expanding Possibilities: Other AI/ML Use Cases in Flutter

Beyond image classification, Flutter is capable of delivering a wide range of AI/ML-powered features that can significantly enhance user experience and app intelligence. Here are some compelling use cases you can explore:

  • Text recognition: Flutter apps can leverage Google’s ML Kit to extract text from images in real time. Using packages like google_mlkit_text_recognition, developers can implement optical character recognition (OCR) to scan receipts, documents, or handwritten notes directly from the device’s camera — no server required.
  • Face and object detection: ML Kit also supports powerful on-device detection capabilities, including:

Face detection: Identify facial features, expressions, and landmarks.

Object and landmark detection: Recognize everyday items or famous locations.

Barcode scanning: Scan QR codes and barcodes seamlessly.

These features allow developers to build apps for security, entertainment, AR, or productivity with fast, offline performance.

  • Sentiment analysis and Natural Language Processing: By integrating cloud-based NLP services such as Google Cloud Natural Language API or AWS Comprehend, Flutter apps can analyze user-generated content. Use cases include:

Sentiment analysis: Detect the mood or tone of user messages.

Entity recognition: Extract names, places, or key terms from text.

This is ideal for social apps, feedback analysis, or AI-powered customer support.

  • Chatbots and voice assistants: Integrate Dialogflow (Google’s chatbot platform) or similar services to create conversational agents in Flutter. For example, using the Dialogflow API or a package, you can send user messages to an AI model and display responses, building a smart chat UI.
  • Recommendation systems: Build personalized recommendations (e.g., for products or content) by training a model on user data or by leveraging cloud recommendation services. The model can run locally (for small datasets) or via a backend.

These are just a few ideas. The Flutter community has many packages (e.g., for speech-to-text, sentiment analysis, etc.) and samples demonstrating such features. In general, any task that benefits from ML (NLP, vision, predictions) can be integrated into a Flutter app with the right model or API.


6. Key Challenges in Building AI-Enabled Flutter Apps

While integrating artificial intelligence and machine learning into Flutter apps opens up exciting possibilities, it also introduces important technical and strategic challenges. Developers must be mindful of several factors to ensure a seamless user experience and efficient performance.

On-Device vs. Cloud-Based Inference

One of the first decisions when implementing AI in a Flutter app is whether to run the model on the device or offload processing to the cloud.

  • On-device inference (using TensorFlow Lite or ML Kit) offers low latency, offline access, and stronger privacy since data never leaves the device. However, mobile devices come with limited computational resources. Running large or complex models may lead to slower performance and higher battery consumption.
  • Cloud-based inference leverages powerful remote servers to handle more complex tasks. This enables the use of advanced models that would otherwise be impractical on mobile. However, it requires stable internet connectivity and introduces challenges around latency and user data privacy. Developers must implement secure data transmission and comply with relevant regulations.

Model Size and Performance Optimization

Machine learning models can significantly increase an app’s binary size and resource consumption if not optimized correctly.

  • To reduce size and improve performance, developers commonly apply quantization, pruning, or model distillation techniques. These methods help compress models while preserving acceptable accuracy.
  • Flutter supports running optimized models, and packages like tflite_flutter are compatible with quantized models. However, developers must strike a balance between performance, accuracy, and memory footprint. Profiling and benchmarking on target devices is essential to ensure smooth user experiences.

Privacy and Data Security

AI features often require access to sensitive user data such as photos, voice, or location. This raises critical privacy and security concerns, especially when using cloud-based APIs.

  • On-device processing can help avoid unnecessary data transmission and provide better privacy controls.
  • Regardless of where processing occurs, developers must implement transparent permission handling, encrypt sensitive data, and follow best practices in secure storage and transmission.
  • It is also important to evaluate whether certain operations can be performed locally, and whether user data can be anonymized or minimized to reduce privacy risks.

Platform-Specific Configuration

Implementing ML features in Flutter often involves additional platform-specific setup and testing.

  • On Android, developers might need to modify Gradle configurations to avoid compressing ML model files during build time.
  • On iOS, using TensorFlow Lite may require updating the Podfile and linking the appropriate native dependencies.
  • Moreover, hardware differences (e.g., ARM vs. x86 architectures, variations in camera APIs) can lead to compatibility and performance discrepancies between devices. Comprehensive testing on both platforms is critical to ensure functionality and stability across your app’s user base.

By carefully addressing these challenges — selecting between on-device and cloud processing, optimizing models, ensuring data security, and handling platform-specific nuances — developers can deliver high-performing, secure, and reliable AI features in their Flutter apps.


7. Final Thoughts

AI and Machine Learning are not just futuristic ideas — they are the present and future of mobile development. When combined with Flutter’s cross-platform capabilities, developers gain a unique advantage: the ability to build intelligent, real-time, adaptive applications without sacrificing development speed or user experience.

Whether you’re enhancing an existing app or building something new, consider incorporating AI/ML to deliver smarter interactions and better outcomes.

Explore, experiment, and evolve — the AI-powered Flutter ecosystem is full of potential.


8. Resources


Thanks for reading this article

If I got something wrong? Let me know in the comments. I would love to improve.

Clap

If this article helps you.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Best Practices for State Management in Flutter Apps

If you’re looking for the best Flutter app development company for your mobile application then feel free to contact us at — support@flutterdevs.com.

Table of Contents:

Introduction

What is State Management in Flutter?

Types of State in Flutter

Popular State Management Approaches in Flutter

When to Use Which State Management Approach?

Best Practices for State Management in Flutter

Conclusion

Reference


Introduction

State management is one of the most crucial aspects of Flutter development. It determines how data flows and updates across your app, impacting performance, maintainability, and user experience.

Choosing the right state management approach depends on the complexity of your app, the size of your development team, and the features you need to implement.

In this guide, we will cover:
 1. What state management is and why it’s important
 2. Types of state in Flutter
 3. Popular state management solutions
 4. Best practices for writing scalable and efficient apps

What is State Management in Flutter?

In simple terms, state is the data that changes during the lifecycle of an app.

For example:

  • The current theme (dark/light mode)
  • A user’s login status
  • A list of items in a shopping cart

State management ensures that when the state changes, the UI updates accordingly.

Types of State in Flutter

There are two types of state in Flutter:

Ephemeral (UI) State

  • Temporary state that doesn’t need to be shared across widgets.
  • Example: TextField input, animations, page scroll position
  • Best handled using StatefulWidget

App State (Global State)

  • State that needs to be shared across multiple screens.
  • Example: User authentication, theme settings, cart items, API data
  • Requires a state management solution

Popular State Management Approaches in Flutter

Flutter provides multiple ways to manage state. Below are the most commonly used approaches, along with their advantages and best use cases.

1. setState() (Basic Approach)

  • Best For: Small apps, UI-related state
  • Complexity: Low
  • Pros:
     Simple and easy to implement
     No extra dependencies required
  • Cons:
     Not scalable for large apps
     Causes unnecessary widget rebuilds

2. InheritedWidget (Built-in Flutter Solution)

  • Best For: Low-level state sharing between widgets
  • Complexity: Medium
  • Pros:
     Part of Flutter’s core framework (no extra package)
     Good for sharing state across widget trees
  • Cons:
     Complex to manage for large apps
     Requires manual updates and rebuilds

3. Provider (Recommended for Most Apps)

  • Best For: Small to medium apps needing shared state
  • Complexity: Medium
  • Pros:
     Easy to integrate and scalable
     Built on InheritedWidget (efficient state updates)
     Good community support
  • Cons:
     Not ideal for complex business logic
     Requires understanding of ChangeNotifier

4. Riverpod (Better Alternative to Provider)

  • Best For: Scalable apps with dependency injection
  • Complexity: Medium
  • Pros:
     Eliminates the limitations of Provider
     Safer and more flexible with auto-dispose
     Works well with dependency injection
  • Cons:
     Slight learning curve compared to Provider

5. Bloc (Business Logic Component)

  • Best For: Large, enterprise-level apps
  • Complexity: High
  • Pros:
     Predictable state management with events & states
     Well-structured and testable
     Good for apps needing explicit state transitions
  • Cons:
     Boilerplate-heavy (requires defining events, states, and blocs)
     Steep learning curve for beginners

6. GetX (Lightweight and Fast)

  • Best For: Apps needing minimal boilerplate
  • Complexity: Low to Medium
  • Pros:
     Simple and requires less code
     Built-in dependency injection and routing
     Lightweight and high-performance
  • Cons:
     Not officially recommended by Flutter
     Can lead to less structured code if misused

7. Redux (Predictable State Management)

  • Best For: Apps needing a centralized state management solution
  • Complexity: High
  • Pros:
     Good for apps needing time-travel debugging
     Scales well for large applications
  • Cons:
     Boilerplate-heavy and complex
     Overkill for simple apps

When to Use Which State Management Approach?

Using setState() for Local UI State

Use setState for small state updates within a single widget.

class CounterScreen extends StatefulWidget {
@override
_CounterScreenState createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
int _counter = 0;

void _incrementCounter() {
setState(() {
_counter++;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('Counter: $_counter')),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}

 Best For: Small, simple apps
 Not suitable for: Large apps with shared state

Using Provider (Recommended for Most Apps)

Provider is a lightweight and efficient state management solution that builds on InheritedWidget.

Installation

dependencies:
provider: ^6.0.5

Implementation

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// 1. Create a ChangeNotifier class
class CounterModel extends ChangeNotifier {
int _counter = 0;
int get counter => _counter;

void increment() {
_counter++;
notifyListeners(); // Notifies widgets to rebuild
}
}

void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}

class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Counter: ${context.watch<CounterModel>().counter}'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterModel>().increment(),
child: Icon(Icons.add),
),
);
}
}

Best For: Medium-sized apps with moderate state sharing
Not suitable for: Very complex business logic

Using Riverpod (Better Provider Alternative)

Riverpod is a safer and more powerful version of Provider with dependency injection.

Installation

dependencies:
flutter_riverpod: ^2.3.6

Implementation

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';

// Define a state provider
final counterProvider = StateProvider<int>((ref) => 0);

void main() {
runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}

class CounterScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);

return Scaffold(
body: Center(child: Text('Counter: $counter')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Icon(Icons.add),
),
);
}
}

Using Bloc (For Large Apps with Complex Logic)

Bloc (Business Logic Component) is one of the most powerful state management solutions for Flutter. It follows a predictable state transition approach using:

  1. Events → Trigger state changes (e.g., “Increment Counter”).
  2. States → Define what UI should display (e.g., “Counter: 0”).
  3. Bloc → The core logic that takes events and produces states.

Step 1: Install Dependencies

Add the following to pubspec.yaml:

dependencies:
flutter_bloc: ^8.1.3
equatable: ^2.0.5

Step 2: Create a Bloc for Counter Management

Define Events (counter_event.dart)

import 'package:equatable/equatable.dart';

abstract class CounterEvent extends Equatable {
@override
List<Object> get props => [];
}

class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}

Define States (counter_state.dart)

import 'package:equatable/equatable.dart';

abstract class CounterState extends Equatable {
@override
List<Object> get props => [];
}

class CounterInitial extends CounterState {
final int counterValue;
CounterInitial(this.counterValue);

@override
List<Object> get props => [counterValue];
}
  • CounterInitial(0) → Starts with 0
  • Equatable ensures efficient state comparison, preventing unnecessary rebuilds.

Create Bloc (counter_bloc.dart)

import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterInitial(0)) {
on<IncrementEvent>((event, emit) {
final newValue = (state as CounterInitial).counterValue + 1;
emit(CounterInitial(newValue)); // Emit new state
});

on<DecrementEvent>((event, emit) {
final newValue = (state as CounterInitial).counterValue - 1;
emit(CounterInitial(newValue));
});
}
}
  • on<IncrementEvent>() → Increases counter
  • on<DecrementEvent>() → Decreases counter
  • Uses emit() to update the state

Step 3: Integrate Bloc into UI (main.dart)

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterScreen(),
),
);
}
}

class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Flutter Bloc Example')),
body: Center(
child: BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
if (state is CounterInitial) {
return Text('Counter: ${state.counterValue}', style: TextStyle(fontSize: 24));
}
return Container();
},
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
child: Icon(Icons.add),
),
SizedBox(width: 20),
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
child: Icon(Icons.remove),
),
],
),
);
}
}

Best For: Large-scale apps needing maintainability
Not suitable for: Small projects due to complexity

Best Practices for State Management in Flutter

1. Keep Business Logic Separate from UI

  • Use Provider, Riverpod, or Bloc to separate logic from widgets.
  • Avoid using setState() in deeply nested widgets.

2. Choose the Right State Management Solution

  • Use setState() for UI-related state (e.g., toggling a switch).
  • Use Provider/Riverpod for medium-sized apps.
  • Use Bloc for large-scale apps.

3. Use Immutable State

  • Immutable state reduces bugs.
  • Use final and const wherever possible.

4. Optimize Performance

  • Use const constructors for widgets to avoid unnecessary rebuilds.
  • Use select() in Provider/Riverpod to listen to specific state changes.

5. Use Dependency Injection for Scalability

  • Riverpod and GetIt allow easy dependency injection for maintainable code.

Conclusion:

Choosing the right state management approach depends on your app’s size and complexity:

setState() → Best for small apps with simple UI updates.
 InheritedWidget → Useful for low-level state sharing.
 Provider → Recommended for small to medium apps needing shared state.
 Riverpod → Scalable and efficient, great for dependency injection.
 Bloc → Best for large apps with complex state management needs.
 GetX → Lightweight, fast, and minimal boilerplate.
 Redux → Ideal for centralized state management in enterprise apps.

Choose based on your app’s size, complexity, and scalability needs!

By following best practices, you can build efficient, maintainable, and high-performing Flutter apps.


Thanks for reading this article

If I got something wrong? Let me know in the comments. I would love to improve.

Clap

If this article helps you.


References:

List of state management approaches
A list of different approaches to managing state.docs.flutter.dev

Top Flutter State Management Packages
Check out the top Flutter State Management Packages like GetX, Riverpod, BLoC, Provider, and MobX to help you manage…www.dhiwise.com

Flutter State Management – Essential Guide and Best Practices
Discover the essential guide to Flutter state management. Learn best practices and key factors to improve your Flutter…solguruz.com


From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automation, IoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:

And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a Flutter developer for your cross-platform Flutter mobile app project hourly or full-time as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Voice Recorder in FlutterFlow

0

FlutterFlow enables powerful app development with drag-and-drop tools and state management — no custom code required. In this guide, you’ll learn how to build a Voice Recorder feature from scratch, with recording, playback, and saved voice notes.

You’ll create:

  • A mic permission flow
  • A record button
  • A list of audio recordings
  • Playback functionality using FlutterFlow’s built-in widgets

Let’s walk through the full setup!

Step 1: Create the Data Schema

First, define a local Data Type to store each audio note.

Data Type Name: voiceNoteDS

Fields:

  • audioPath (String): the file path of the recording
  • createdAt (DateTime): the date and time when it was recorded

This structure will be used to store and display each recording in a list.

Step 2: Create App State Variable

Next, set up a persistent App State variable to hold all voice notes:

App State Variable

  • Name: voiceNotesAS
  • Type: List<Data (voiceNoteDS)>
  • Persistence: ✅ Enabled

This variable will update every time a recording is saved, keeping the list even when the app is closed and reopened.

Step 3: Add Microphone Permission

Before recording, we must ask the user for microphone access.

How to do it:

  1. Open the Action Flow for your record button.
  2. Add the Request Permission action.
  3. Choose Permission Type: microphone

This ensures the app can access the mic before recording begins.

Step 4: Setup Voice Recording Logic (Visual Flow)

Refer to your flow (see screenshot Step 5). You’ll use a conditional to toggle recording on and off.

Logic Flow:

  • Condition: isRecording == false
  • ✅ TRUE → Start Recording → Set isRecording = true
  • ❌ FALSE → Stop Recording → Set isRecording = false → Save file path → Create new voiceNoteDS item → Add to voiceNotesAS

You’ll use the following actions:

  • Start Audio Recording
  • Stop Audio Recording
  • Update Page/App State
  • Append to List (voiceNotesAS)

Step 5: Design the UI

Here’s how the layout is structured:

🔹 Main Layout

  • Stack for overlapping mic button at bottom
  • Column to hold title and recordings list
  • ListView for displaying each recorded item

🎵 Inside ListView:

Each item includes:

  • The recording timestamp (using createdAt)
  • A Play button using Audio Player widget, with audioPath as the file input

 UI Preview

Here’s a screenshot of the working UI:

You can see:

  • The page title “Voice Recorder”
  • A card-style list of saved recordings with play buttons
  • A floating red microphone button to toggle recording

🎯 The clean layout is perfect for voice notes, chat messages, or interviews.

Final Result

When you’re done:

  • Tap the mic button to start/stop recording.
  • Recordings are saved locally with timestamps.
  • They appear in a scrollable ListView.
  • Each item includes a play button to listen to the audio.

And all of this is built inside FlutterFlow using built-in widgets, actions, and state — no Dart code needed!

Wrap-Up

You’ve successfully created a fully functional Voice Recorder app in FlutterFlow with:

  • Mic permission handling
  • Dynamic UI
  • Persistent storage
  • Instant playback

This feature can now be reused in note-taking apps, audio journals, or messaging apps.

Let me know if you’d like this exported as PDF, Markdown, or submitted to the FlutterFlow Marketplace as a reusable component!

Conclusion

In this tutorial, you’ve learned how to create a complete Voice Recorder in FlutterFlow — without writing any custom code. From setting up the data structure and managing app state, to designing a clean UI and handling microphone permissions, each step was accomplished using FlutterFlow’s built-in tools and visual logic.

This voice recorder feature is not only practical but also reusable across various app use cases like:

  • Personal voice memos
  • Chat voice messages
  • Task reminders
  • Audio logs

By combining widgets like Audio Recorder, Audio Player, and ListView, along with state management, you’ve built a real-world feature that enhances user experience and app functionality.

Now that your voice recording component is ready, you can extend it even further — perhaps by uploading audio to Firebase Storage, syncing with user accounts, or transcribing notes using AI tools.

From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automation, IoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Keep exploring, and keep building smarter with FlutterFlow!

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire Flutterflow developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Document Scanner in FlutterFlow 

0

In the digital age, being able to scan and store documents on-the-go is more than a convenience — it’s a necessity. Whether it’s students scanning their notes, professionals saving receipts, or individuals digitizing important papers, having a document scanner built directly into a mobile app adds incredible value.

In this blog, we’ll explore how to create a fully functional document scanner inside FlutterFlow, using a native plugin (cunning_document_scanner) and custom widgets/actions for scanning, previewing, and downloading images.

What You’ll Build

We’re going to build a FlutterFlow Document Scanner app that:

  • 📸 Scans books or documents via the camera.
  • 🖼️ Shows the scanned image in a bottom sheet.
  • ⬇️ Lets users download the scanned image to their device.

All this will be built using:

  • 2 Widgets: DocumentScanner and ScannerDoc
  • 1 Custom Action: takeScanner
  • Plugin: cunning_document_scanner: ^1.2.3

🛠️ Tools & Packages Required

To enable scanning and saving functionality, we’ll use:

dependencies:
cunning_document_scanner: ^1.2.3

Make sure these packages are added in your FlutterFlow project’s pubspec.yaml file via the “Custom Code > Dependencies” tab.

Widget Structure

DocumentScanner Widget

This is the main screen of the app. It contains a button or icon that initiates the scan process.

What it does:

  • Calls the takeScanner custom action when tapped.
  • Stores the list of scanned image paths.
  • Navigates to the ScannerDoc screen to show results.

🔧 Dart Code:

// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'dart:io';

import 'package:cunning_document_scanner/cunning_document_scanner.dart';

class DocumentScanner extends StatefulWidget {
const DocumentScanner({
super.key,
this.width,
this.height,
});

final double? width;
final double? height;

@override
State<DocumentScanner> createState() => _DocumentScannerState();
}

class _DocumentScannerState extends State<DocumentScanner> {
List<String> _pictures = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: onPressed, child: const Text("Add Pictures")),
for (var picture in _pictures) Image.file(File(picture))
],
)),
),
);
}

void onPressed() async {
List<String> pictures;
try {
pictures = await CunningDocumentScanner.getPictures() ?? [];
if (!mounted) return;
setState(() {
_pictures = pictures;
});
} catch (exception) {
// Handle exception here
}
}
}

ScannerDoc Widget

This widget displays the scanned images in a bottom sheet.

Features:

  • Scrollable image viewer (for multiple scans).
  • Tappable image preview.
  • Download button next to each image for saving.

🔧 Dart Code:

// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'package:cunning_document_scanner/cunning_document_scanner.dart';
import 'dart:io';

class ScannerDoc extends StatefulWidget {
const ScannerDoc({
super.key,
this.width,
this.height,
});

final double? width;
final double? height;

@override
State<ScannerDoc> createState() => _ScannerDocState();
}

class _ScannerDocState extends State<ScannerDoc> {
List<String> _pictures = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: onPressed, child: const Text("Add Pictures")),
for (var picture in _pictures) Image.file(File(picture))
],
)),
),
);
}

void onPressed() async {
List<String> pictures;
try {
pictures = await CunningDocumentScanner.getPictures() ?? [];
if (!mounted) return;
setState(() {
_pictures = pictures;
});
} catch (exception) {
// Handle exception here
}
}
}

Custom Action: takeScanner

This action integrates the cunning_document_scanner plugin and launches the native camera interface.

🔧 Dart Code:

// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'dart:io';
import 'dart:async';
import 'package:cunning_document_scanner/cunning_document_scanner.dart';

Future<List<FFUploadedFile>?> takeScanner() async {
// Add your function code here!
try {
// Panggil scanner untuk mengambil gambar dokumen
List<String>? pictures = await CunningDocumentScanner.getPictures();

// Jika hasilnya kosong, return null
if (pictures == null || pictures.isEmpty) {
return null;
}

// Konversi hasil path gambar menjadi List<FFUploadedFile>
List<FFUploadedFile> uploadedFiles = pictures.map((path) {
File file = File(path);
return FFUploadedFile(
name: path.split('/').last, // Mengambil nama file dari path
bytes: file.readAsBytesSync(), // Membaca file sebagai bytes
);
}).toList();

return uploadedFiles;
} catch (e) {
print('Error scanning document: $e');
return null;
}
}

How It Works:

  • Calls the scanner.
  • Returns a list of scanned image paths.
  • Passes these paths back to the widget for display.

Adding the Download Button

Inside the ScannerDoc bottom sheet, we add a Download button. This button triggers another custom action that saves the image to the user’s gallery.

Putting It All Together (User Flow)

  1. Open App → DocumentScanner widget.
  2. Click “Scan” → launches camera via takeScanner.
  3. User scans pages → list of image paths returned.
  4. Navigate to ScannerDoc → show images in bottom sheet.
  5. User taps “Download” → image saved to gallery.

Customizing the UI

FlutterFlow allows you to:

  • Use custom containers to style your bottom sheet
  • Add animation when showing the scanned image
  • Support light/dark themes
  • Add optional text fields (e.g. label your scans)

You can also:

  • Combine this with OCR tools to extract text
  • Convert images to PDF using another custom action
  • Sync with Firebase to store scanned files in the cloud

Permissions to Handle

Be sure to request permissions for:

  • Camera Access
  • Storage Access (Android only)

Use permission_handler to manage this properly in custom code.

Final Testing Tips

  • Test on a real device (scanning and file saving might not work on emulators).
  • Verify permissions are granted.
  • Check for multiple image support if needed.
  • Add error handling for denied permissions.

Conclusion

By combining FlutterFlow’s visual development power with native Flutter packages like cunning_document_scanner, you can create a production-ready document scanner in just a few hours. With reusable widgets, clean actions, and smooth UI, your app can offer a premium scanning experience without depending on third-party apps.

From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automation, IoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire Flutterflow developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

CupertinoRadio Widget in FlutterFlow 

FlutterFlow is a powerful low-code platform that allows you to build Flutter applications visually — without writing traditional Flutter code. While FlutterFlow is known for its Material design components, it also supports Cupertino (iOS-style) widgets, like the CupertinoRadio, giving you more design flexibility.

In this blog, we’ll explore what the CupertinoRadio widget is, how to use it in FlutterFlow, and when to choose it over the standard Material-style radio buttons.

What is CupertinoRadio?

The CupertinoRadio widget is part of Flutter’s Cupertino design system, which replicates the native iOS look and feel. It functions similarly to a traditional radio button, allowing users to select a single item from a list of options. The key difference is in the styling — it’s built to look and behave like a native iOS component.

In FlutterFlow, the CupertinoRadio widget gives your app a native iOS experience while maintaining the benefits of low-code development.

When Should You Use CupertinoRadio in FlutterFlow?

Use CupertinoRadio when:

  • You’re designing an app specifically for iOS.
  • You want to give your users a native Apple-style UI.
  • You’re using other Cupertino elements like CupertinoNavigationBar or CupertinoSwitch.

How to Use CupertinoRadio in FlutterFlow?

Currently, FlutterFlow doesn’t have a direct drag-and-drop CupertinoRadio widget like in Flutter code. However, you can mimic its functionality by using the Custom Widget feature, or by creating iOS-style radio buttons using standard widgets + logic.

Here are two methods to implement Cupertino-style radio buttons in FlutterFlow:

Method 1: Using FlutterFlow Widgets (Visual No-Code)

Step-by-Step Guide:

  1. Create a List of Options:
  • Use a Column or ListView.
  • Add a Row inside for each option.
  1. Add a Circle Indicator:
  • Use a Container with a border to represent the radio circle.
  • Use conditional visibility to show a filled circle inside if selected.
  1. Add Text Label:
  • Add a Text widget next to the radio icon to show the option.
  1. Add Selection Logic:
  • Define a State Variable (e.g., selectedOption) of type String or Int.
  • Set a GestureDetector or InkWell around the Row.
  • On Tap → Update State to set the selected option.
  1. Dynamic Styling:
  • Change the container color or add an inner circle when it matches the selected option.

💡 This method visually mimics CupertinoRadio and works well in FlutterFlow’s no-code interface.

Method 2: Using a Custom Widget (for Exact iOS Look)

If you want to use the actual Flutter CupertinoRadio widget inside FlutterFlow:

Step-by-Step:

  1. Go to the Custom Widgets Tab.
  2. Create a New Custom Widget
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class CustomCupertinoRadio extends StatefulWidget {
  final String groupValue;
  final String value;
  final Function(String) onChanged;

  const CustomCupertinoRadio({
    required this.groupValue,
    required this.value,
    required this.onChanged,
  });

  @override
  _CustomCupertinoRadioState createState() => _CustomCupertinoRadioState();
}

class _CustomCupertinoRadioState extends State<CustomCupertinoRadio> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => widget.onChanged(widget.value),
      child: Row(
        children: [
          CupertinoRadio<String>(
            value: widget.value,
            groupValue: widget.groupValue,
            onChanged: (String? val) {
              if (val != null) {
                widget.onChanged(val);
              }
            },
          ),
          SizedBox(width: 8),
          Text(widget.value),
        ],
      ),
    );
  }
}

  1. Add the Widget to Your Page:
  • Pass groupValue, value, and onChanged as parameters.
  • Bind them to FlutterFlow State Variables to manage selection.

✅ This gives you a pixel-perfect native iOS radio control inside FlutterFlow.

 Styling Tips

  • Match your radio buttons with Cupertino themes (light backgrounds, clean spacing).
  • Combine them with other Cupertino elements like CupertinoListTile or CupertinoFormRow.
  • Use minimalist fonts like San Francisco to enhance the iOS feel.

 Important Considerations

  • CupertinoRadio is great for iOS-themed apps. If you are targeting Android, it’s better to use RadioButton or conditionally render based on platform.
  • FlutterFlow doesn’t support all native Flutter widgets visually, but Custom Widgets give you full power.

Conclusion

The CupertinoRadio widget is a great way to bring native iOS design elements into your FlutterFlow projects. While it may require a bit of extra work compared to drag-and-drop widgets, the payoff is a more polished and platform-specific UI.

Whether you simulate the look using FlutterFlow’s visual tools or integrate a custom widget, CupertinoRadio lets you build an intuitive and stylish iOS experience — right inside FlutterFlow.

From Our Parent Company Aeologic

Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automation, IoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.

Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire Flutterflow developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.