<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Codexlancers</title>
    <description>The latest articles on DEV Community by Codexlancers (@codexlancers).</description>
    <link>https://dev.to/codexlancers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3857287%2Fa8e4508f-a0b0-447b-a06a-9bc5efa2ebf5.jpeg</url>
      <title>DEV Community: Codexlancers</title>
      <link>https://dev.to/codexlancers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codexlancers"/>
    <language>en</language>
    <item>
      <title>Effortless Dart Coding with dart_extensions_pro</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Mon, 18 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/effortless-dart-coding-with-dartextensionspro-2bhg</link>
      <guid>https://dev.to/codexlancers/effortless-dart-coding-with-dartextensionspro-2bhg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq72b4rutz2cw9t8x3vz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq72b4rutz2cw9t8x3vz.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Introducing dart_extensions_pro a Dart package that offers a collection of handy extensions and helper functions designed to enhance the development process. By simplifying common tasks and providing streamlined solutions, it allows developers to write code more efficiently and focus on building features rather than repetitive tasks. Ideal for improving productivity, this package is a valuable tool for both novice and experienced programmers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;br&gt;
📊 &lt;strong&gt;Comparison:&lt;/strong&gt; Simplify comparison operations with intuitive extension methods.&lt;/p&gt;

&lt;p&gt;📅** Date Handling:** Effortlessly manage date and time with a variety of helpful functions.&lt;/p&gt;

&lt;p&gt;✍️ &lt;strong&gt;String Utilities:&lt;/strong&gt; Enhance string manipulation with powerful utility functions.&lt;/p&gt;

&lt;p&gt;📋 &lt;strong&gt;List Enhancements:&lt;/strong&gt; Improve list handling with convenient extensions for common operations.&lt;/p&gt;

&lt;p&gt;🧭 &lt;strong&gt;Navigation:&lt;/strong&gt; Streamline navigation tasks with specialized navigation functions.&lt;/p&gt;

&lt;p&gt;👆 &lt;strong&gt;Tap Gestures:&lt;/strong&gt; Easily handle tap gestures to improve user interaction.&lt;/p&gt;

&lt;p&gt;🔁 &lt;strong&gt;Iterable Enhancements:&lt;/strong&gt; Optimize iterable processing with enhanced methods.&lt;/p&gt;

&lt;p&gt;🎨 &lt;strong&gt;Color Conversion:&lt;/strong&gt; Simplify color manipulations and conversions with dedicated functions.&lt;/p&gt;

&lt;p&gt;🔢 &lt;strong&gt;Number Utilities:&lt;/strong&gt; Access a range of number-related utilities for calculations and formatting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgv4n2y7voo919ahz44o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgv4n2y7voo919ahz44o.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
🛠️ &lt;strong&gt;Utility Functions:&lt;/strong&gt; Utilize various handy utility functions to simplify your coding experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
Add dependency to your pubspec.yaml file &amp;amp; run Pub get&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dart_extensions_pro&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And import package into your class file&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:dart_extensions_pro/dart_extensions_pro.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;Analytics&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Visit EXTENSIONS.md for a complete list of all the available extensions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Extensions:                    271
Helper Classes:                7
Helper Functions &amp;amp; Getters:    21
Typedefs:                      7
Mixins:                        2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Here’s a quick preview of dart_extensions_pro,&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;String extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="s"&gt;'hello'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iscapitalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Capitalizes first letter // Hello&lt;/span&gt;
&lt;span class="s"&gt;'Copy this text'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyTo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Copies string to clipboard&lt;/span&gt;
&lt;span class="s"&gt;'test@example.com'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Checks if valid email // true&lt;/span&gt;
&lt;span class="s"&gt;'flutter'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Reverses string // rettulf&lt;/span&gt;
&lt;span class="s"&gt;'madam'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Checks for palindrome // true&lt;/span&gt;
&lt;span class="s"&gt;'flutter example'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toCamelCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Converts to camel case // FlutterExample&lt;/span&gt;
&lt;span class="s"&gt;'{"name": "Flutter"}'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decodeJson&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Parses JSON string to map // {name: Flutter}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Comparison extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if 5 is greater than 3&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if 3 is less than 5&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if 5 is equal to 5&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true, checks if 3 is less than or equal to 3&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true, checks if 5 is greater than or equal to 3&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if 5 is not equal to 3&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Date extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSameDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if today matches the provided date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isToday&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if today is today&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTomorrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if today is tomorrow (unlikely)&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wasYesterday&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// true, checks if today is yesterday (false)&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// adds 5 days to the current date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// adds 3 months to the current date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addYears&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// adds 2 years to the current date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// subtracts 7 days from the current date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// subtracts 1 month from the current date&lt;/span&gt;
&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtractYears&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// subtracts 1 year from the current date&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;List extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// [1, 2, 3, 4], appends 4 to the list using the `&amp;lt;&amp;lt;` operator&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceFirstWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, replaces the first occurrence of 2 with 10&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceLastWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// true, replaces the last item greater than 1 with 20&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Navigation extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyPage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Navigates to `MyPage` using `to()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/home'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Navigates to the named route '/home' using `toNamed()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Pops the current route using `back()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;backUntil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFirst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Pops routes until the first one using `backUntil()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toWithReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnotherPage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Replaces current route with `AnotherPage` using `toWithReplace()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceWithNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/dashboard'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Replaces the current route with named route '/dashboard' using `replaceWithNamed()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toAndRemoveAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Navigates to `HomePage` and removes all previous routes using `toAndRemoveAll()`&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toNamedAndRemoveAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Navigates to named route '/login' and removes all previous routes using `toNamedAndRemoveAll()`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Gesture extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onInkTap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Tapped!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds an ink splash effect with `onInkTap()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onTap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Tapped!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a basic tap gesture with `onTap()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onDoubleTap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Double Tapped!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a double-tap gesture with `onDoubleTap()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onTapCancel&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Tap Cancelled!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a tap cancel gesture with `onTapCancel()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onLongPress&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Long Pressed!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a long press gesture with `onLongPress()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onTapDown&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Tap Down!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a tap down gesture with `onTapDown()`&lt;/span&gt;
&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onScale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;onScaleStart:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Scale Started!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;onScaleUpdate:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Scaling!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;onScaleEnd:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;'Scale Ended!'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;logMsg&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Adds a scale gesture with `onScale()`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Iterable extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastElementIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns the index of the last element or -1 if empty.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasSingleElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Checks if the iterable has exactly one element.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAllMatchingTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEven&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Adds elements matching the predicate to the target list.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereFilter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEven&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Filters elements matching the predicate.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;whereFilterIndexed&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Filters elements with their index.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mapTransform&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// Transforms each element and maps to a new iterable.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skipElements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Skips the first 2 elements.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;takeLastElements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Takes the last 2 elements.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skipWhileElements&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Skips elements while the predicate is true.&lt;/span&gt;
&lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skipLastElements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Skips the last 2 elements.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Color conversion&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toColor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Converts a hex color string to a Color object, assuming full opacity.&lt;/span&gt;
&lt;span class="n"&gt;HexColor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getColorFromHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hexColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Converts a hex color string to an integer color value, adding alpha if missing.&lt;/span&gt;
&lt;span class="n"&gt;HexColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hexColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Creates a HexColor instance from a hex color string.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Number conversion&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;negative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Converts positive numbers to their negative counterparts.&lt;/span&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isBetween&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;inclusive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// Checks if [this] is between [value1] and [value2], inclusive if [inclusive] is true.&lt;/span&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roundToDecimals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decimalPlaces&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Rounds the number to [decimalPlaces] decimal places.&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asRadians&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Converts degrees to radians.&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asDegrees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Converts radians to degrees.&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upperBound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exclusive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// Limits the value to [upperBound], exclusive if [exclusive] is true.&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lowerBound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exclusive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// Ensures the value is not less than [lowerBound], exclusive if [exclusive] is true.&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clampAtMin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lowerBound&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Ensures the value is not below [lowerBound].&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clampAtMax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upperBound&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Ensures the value does not exceed [upperBound].&lt;/span&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orZero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns this value or 0 if null.&lt;/span&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orOne&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns this value or 1 if null.&lt;/span&gt;
&lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Returns this value or [value] if null.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Utility conversion&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isWhole&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Checks if the value is a whole number.&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roundToPrecision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nthPosition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Rounds the value to [precision] decimal places.&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCloseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;precision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0e-8&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// Checks if the value is close to [other] within [precision].&lt;/span&gt;
&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomDouble&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;  &lt;span class="c1"&gt;// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive).&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inYears&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns the number of whole years spanned by this [Duration].&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isInYears&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns `true` if the [Duration] is equal to or longer than one year.&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;absoluteSeconds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Returns the number of seconds remaining after accounting for whole minutes.&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;operator&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;(&lt;/span&gt;&lt;span class="n"&gt;MapEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Inserts a [MapEntry] into the map using the `&amp;lt;&amp;lt;` operator.&lt;/span&gt;
&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Converts the map into a JSON string.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For more information, check out the below link&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://pub.dev/packages/dart_extensions_pro?source=post_page-----f5961086cf63---------------------------------------" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub.dev%2Fstatic%2Fhash-fsujdolb%2Fimg%2Fpub-dev-icon-cover-image.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://pub.dev/packages/dart_extensions_pro?source=post_page-----f5961086cf63---------------------------------------" rel="noopener noreferrer" class="c-link"&gt;
            dart_extensions_pro | Flutter package
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A Dart package that provides handy extensions and helper functions, designed to simplify and speed up development, making coding more efficient and streamlined.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub.dev%2Fstatic%2Fhash-fsujdolb%2Fimg%2Fflutter-logo-32x32.png"&gt;
          pub.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7gwyo2qj7gfbl03y5yx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7gwyo2qj7gfbl03y5yx.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
Thanks for reading! If this post was helpful, feel free to share it and follow for more Flutter tips and tutorials. Keep coding and stay awesome!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Flutter Zoom Meeting Wrapper</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Fri, 15 May 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/flutter-zoom-meeting-wrapper-4hb</link>
      <guid>https://dev.to/codexlancers/flutter-zoom-meeting-wrapper-4hb</guid>
      <description>&lt;p&gt;In today’s connected world, video conferencing has become an essential part of our daily lives. As mobile app developers, integrating reliable video conferencing capabilities can significantly enhance the user experience of your applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhoimbih8xdy0nqumbtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhoimbih8xdy0nqumbtg.png" alt=" " width="720" height="386"&gt;&lt;/a&gt;&lt;br&gt;
The &lt;strong&gt;Flutter Zoom Meeting Wrapper&lt;/strong&gt; is a powerful Flutter plugin that allows you to seamlessly integrate the Zoom Meeting SDK into your Flutter applications. This means your users can join and participate in Zoom meetings directly within your app without ever needing to switch to the Zoom application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;br&gt;
This plugin offers a range of capabilities to enhance your Flutter application:&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Seamless Integration:&lt;/strong&gt; Easy integration with the Zoom Meeting SDK&lt;br&gt;
🔄 &lt;strong&gt;Simple Initialization:&lt;/strong&gt; Initialize the SDK using a JWT token&lt;br&gt;
🎯 &lt;strong&gt;In-App Experience:&lt;/strong&gt; Join meetings directly within your app (no Zoom app required)&lt;br&gt;
📱 &lt;strong&gt;Platform Support:&lt;/strong&gt; Complete Android platform compatibility&lt;br&gt;
🔊 &lt;strong&gt;Rich Meeting Experience:&lt;/strong&gt; Full audio and video meeting functionality&lt;br&gt;
🔐 &lt;strong&gt;Secure Authentication:&lt;/strong&gt; Robust security through JWT authentication flow&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
To begin using the Flutter Zoom Meeting Wrapper in your project, add the following to your pubspec.yaml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter_zoom_meeting_wrapper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run flutter pub get to install the package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mandatory Zoom SDK Setup&lt;/strong&gt;&lt;br&gt;
For the plugin to function correctly, you need to set up the Zoom SDK:&lt;/p&gt;

&lt;p&gt;Download the Zoom SDK ZIP from &lt;a href="https://drive.google.com/file/d/1aKhrS5JCVSxvQkfdXH0N1h45Lk2gt6P9/view" rel="noopener noreferrer"&gt;this link&lt;/a&gt;&lt;br&gt;
Extract the ZIP file after downloading&lt;br&gt;
Copy the libs folder and paste it inside your Flutter pub-cache directory at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.pub-cache/hosted/pub.dev/flutter_zoom_meeting_wrapper-0.0.1/android/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Replace 0.0.1 with the version you're using, if different.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Alternatively, run the following command to open the folder directly:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open ~/.pub-cache/hosted/pub.dev/flutter_zoom_meeting_wrapper-0.0.1/android

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Important: The libs folder must be placed in the correct location for the plugin to function properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up Zoom API Credentials&lt;/strong&gt;&lt;br&gt;
To use the Zoom Meeting SDK in your application, you’ll need to:&lt;/p&gt;

&lt;p&gt;Create a Zoom Developer Account at &lt;a href="https://marketplace.zoom.us/" rel="noopener noreferrer"&gt;Zoom Marketplace&lt;/a&gt;&lt;br&gt;
Create a new app in the Zoom Marketplace&lt;br&gt;
Obtain your API Key and API Secret from the app credentials page&lt;br&gt;
Use these credentials to generate your JWT token&lt;br&gt;
&lt;strong&gt;Generating a JWT Token&lt;/strong&gt;&lt;br&gt;
You can generate a Zoom JWT token using jwt.io with the following payload and signature:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc23oxec6gemc6df5bjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc23oxec6gemc6df5bjl.png" alt=" " width="800" height="192"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Payload:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ZOOM-CLIENT-KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ANY-TIME-STAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ANY-TIME-STAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;greater&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;than&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;iat&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokenExp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ANY-TIME-STAMP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;greater&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;than&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;iat&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify Signature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  "ZOOM-CLIENT-SECRET"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Implementation Guide&lt;br&gt;
Initializing the SDK&lt;/strong&gt;&lt;br&gt;
First, initialize the Zoom SDK with your JWT token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_zoom_meeting_wrapper/flutter_zoom_meeting_wrapper.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize Zoom SDK&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isInitialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ZoomMeetingWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initZoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwtToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Joining a Meeting&lt;/strong&gt;&lt;br&gt;
Once initialized, you can join a Zoom meeting with this simple code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;joinSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ZoomMeetingWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;joinMeeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;meetingId:&lt;/span&gt; &lt;span class="s"&gt;"your_meeting_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;meetingPassword:&lt;/span&gt; &lt;span class="s"&gt;"meeting_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;displayName:&lt;/span&gt; &lt;span class="s"&gt;"Your Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Troubleshooting Common Issues&lt;/strong&gt;&lt;br&gt;
When implementing the Flutter Zoom Meeting Wrapper, you might encounter these common issues:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT Token Invalid:&lt;/strong&gt; Ensure your API Key and Secret are correct, and verify that your system time is accurate.&lt;br&gt;
&lt;strong&gt;Failed to initialize SDK:&lt;/strong&gt; Check that you have a stable internet connection and are using a valid JWT token.&lt;br&gt;
&lt;strong&gt;Cannot join meeting:&lt;/strong&gt; Double-check that the meeting ID and password are correct.&lt;br&gt;
&lt;strong&gt;Current Limitations&lt;/strong&gt;&lt;br&gt;
While the Flutter Zoom Meeting Wrapper provides powerful functionality, be aware of these current limitations:&lt;/p&gt;

&lt;p&gt;🖼️ Custom UI overlays are not supported in the current version&lt;br&gt;
📹 Meeting recording functionality is not available in this plugin&lt;br&gt;
🖥️ Screen sharing capabilities are limited to platform capabilities&lt;br&gt;
&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
The Flutter Zoom Meeting Wrapper offers a straightforward way to integrate Zoom’s powerful meeting capabilities into your Flutter applications. With minimal setup and easy-to-use API, you can enhance your app with professional video conferencing features.&lt;/p&gt;

&lt;p&gt;By providing users with the ability to join meetings without leaving your app, you create a more seamless and integrated experience that keeps users engaged with your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8unuv2bsp8jmmtzmiae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8unuv2bsp8jmmtzmiae.png" alt=" " width="400" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>flutter</category>
      <category>mobile</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Google &amp; Apple Sign-In in Flutter</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Thu, 14 May 2026 12:45:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/google-apple-sign-in-in-flutter-3k5d</link>
      <guid>https://dev.to/codexlancers/google-apple-sign-in-in-flutter-3k5d</guid>
      <description>&lt;p&gt;A production-grade walkthrough: clean auth service, real code from a real app, and integration patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Introduction&lt;br&gt;
Prerequisites&lt;br&gt;
Dependencies &amp;amp; Setup&lt;br&gt;
Getting the Server Client ID&lt;br&gt;
The Clean AuthService&lt;br&gt;
Platform Configuration&lt;br&gt;
Common Errors &amp;amp; Fixes&lt;br&gt;
UI Example&lt;br&gt;
Conclusion&lt;/p&gt;

&lt;p&gt;01 / Introduction&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Social Sign-In Still Matters in 2026&lt;/strong&gt;&lt;br&gt;
Every additional step between a user opening your app and them being inside it is a drop-off point. Password flows are friction. &lt;strong&gt;Google and Apple&lt;/strong&gt; Sign-In are the fastest path from “curious” to “engaged” — two taps and you’re in, no new password to forget.&lt;/p&gt;

&lt;p&gt;💡 Who this is for&lt;/p&gt;

&lt;p&gt;Flutter developers at any level who want latest Google and Apple Sign-In that actually works in production.&lt;/p&gt;

&lt;p&gt;02 / Prerequisites&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You Need Before Starting&lt;/strong&gt;&lt;br&gt;
A Firebase project with Authentication enabled — Google and Apple providers turned on&lt;br&gt;
FlutterFire CLI installed and &lt;strong&gt;flutterfire configure&lt;/strong&gt; already run&lt;br&gt;
For Apple Sign-In: an Apple Developer account with Sign In with Apple capability enabled&lt;br&gt;
For Android Google Sign-In: SHA-1 fingerprint registered in Firebase Console&lt;br&gt;
03 / Dependencies &amp;amp; Setup&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packages, pubspec, and Initialization&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Add to pubspec.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter_dotenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.2.1&lt;/span&gt;
  &lt;span class="na"&gt;firebase_core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.10.1&lt;/span&gt;
  &lt;span class="na"&gt;firebase_auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.5.1&lt;/span&gt;
  &lt;span class="na"&gt;google_sign_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^7.2.0&lt;/span&gt;
  &lt;span class="na"&gt;sign_in_with_apple&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^7.0.1&lt;/span&gt;

&lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create your .env file&lt;/strong&gt;&lt;br&gt;
Store sensitive config outside of source code. Create a** .env &lt;strong&gt;file in your project root and add it to **.gitignore:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get this from Google Cloud Console → OAuth 2.0 → Web Client (see Section 4)
&lt;/span&gt;&lt;span class="n"&gt;SERVER_CLIENT_ID&lt;/span&gt;=&lt;span class="m"&gt;123456789&lt;/span&gt;-&lt;span class="n"&gt;abcdefg&lt;/span&gt;.&lt;span class="n"&gt;apps&lt;/span&gt;.&lt;span class="n"&gt;googleusercontent&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Firebase and Google Sign-In in main.dart&lt;/strong&gt;&lt;br&gt;
This is the most important step people miss, you must call &lt;strong&gt;GoogleSignIn.instance.initialize() **before&lt;/strong&gt; runApp()**, after Firebase is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_core/firebase_core.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:your_app/service/auth_service.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Load environment variables&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;fileName:&lt;/span&gt; &lt;span class="s"&gt;'.env'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Initialize Firebase&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;options:&lt;/span&gt; &lt;span class="n"&gt;DefaultFirebaseOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentPlatform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Initialize AuthService (which calls GoogleSignIn.instance.initialize)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚨 Skip initialize() and you’ll get a StateError&lt;/p&gt;

&lt;p&gt;If you call** authenticate()** or &lt;strong&gt;authorizationClient&lt;/strong&gt; before &lt;strong&gt;initialize(),&lt;/strong&gt; Flutter throws a &lt;strong&gt;StateError: instance not initialized.&lt;/strong&gt; This crashes silently in release builds. Always initialize first.&lt;/p&gt;

&lt;p&gt;04 / Google Cloud Configuration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting the Server Client ID (Web OAuth Client)&lt;/strong&gt;&lt;br&gt;
The &lt;strong&gt;serverClientId&lt;/strong&gt; is the &lt;strong&gt;Web Client ID&lt;/strong&gt; from Google Cloud Console — not the Android or iOS client. It is required for Google Sign-In on Android and enables server-side token verification. Here's exactly how to find it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Cloud Console — Step-by-step walkthrough&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="http://console.cloud.google.com/welcome?pli=1&amp;amp;project=surefany-dcbba" rel="noopener noreferrer"&gt;console.cloud.google.com&lt;/a&gt; and select your Firebase project (same project name as in Firebase Console)&lt;br&gt;
2 . In the left sidebar, navigate to &lt;a href="https://console.cloud.google.com/apis/credentials?project=surefany-dcbba" rel="noopener noreferrer"&gt;APIs &amp;amp; Services → Credentials&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Under OAuth 2.0 Client IDs, look for the entry with type “Web application”. It is usually auto-created by Firebase and named something like “Web client (auto created by Google Service)”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the Web application entry to open its details&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the Client ID field — it ends in &lt;strong&gt;.apps.googleusercontent.com.&lt;/strong&gt; This is your &lt;strong&gt;SERVER_CLIENT_ID.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste it into your &lt;strong&gt;.env **file as **SERVER_CLIENT_ID=&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 Can’t find the Web Client?&lt;/p&gt;

&lt;p&gt;If you don’t see a Web Client ID, go to Firebase Console → Authentication → Sign-in method → Google → click the expand arrow. Firebase will show you the Web SDK configuration which contains the same client ID.&lt;/p&gt;

&lt;p&gt;⚠️ Android vs iOS vs Web — use the Web client&lt;/p&gt;

&lt;p&gt;There will be separate entries for Android, iOS, and Web in the credentials list. The serverClientId parameterspecifically requires the Web client ID. Using the Android or iOS client ID here is a common mistake that silently fails.&lt;/p&gt;

&lt;p&gt;05 / The Clean AuthService&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication Service Implementation&lt;/strong&gt;&lt;br&gt;
Here’s the authentication logic, cleaned up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lib/service/auth_service.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:developer'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:math'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_auth/firebase_auth.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_sign_in/google_sign_in.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:sign_in_with_apple/sign_in_with_apple.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// Clean authentication service — auth logic only, no database concerns.&lt;/span&gt;
&lt;span class="c1"&gt;/// Use it as a foundation and add your own data layer on top.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ─── Singleton ───────────────────────────────────────────&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Firebase + Google ────────────────────────────────────&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;FirebaseAuth&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignIn&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoogleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;/// Web Client ID from Google Cloud Console → OAuth 2.0 → Web application&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;_serverClientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'SERVER_CLIENT_ID'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Public Getters ───────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;isSignedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Initialization ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Call once at app startup, after Firebase.initializeApp().&lt;/span&gt;
  &lt;span class="c1"&gt;/// Required by google_sign_in v7+ before any sign-in call.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;serverClientId:&lt;/span&gt; &lt;span class="n"&gt;_serverClientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[AuthService] Google Sign-In initialized'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[AuthService] Google init error: &lt;/span&gt;&lt;span class="si"&gt;$e&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// fail fast — misconfiguration should be caught at startup&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Google Sign-In ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs in with Google and returns a Firebase [UserCredential].&lt;/span&gt;
  &lt;span class="c1"&gt;/// Throws on cancellation or error — catch in your controller/notifier.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserCredential&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Sign out first — ensures the account picker is always shown&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. Trigger Google authentication — shows the account picker&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignInAccount&lt;/span&gt; &lt;span class="n"&gt;googleUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;scopeHint:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Get the ID token directly from the authenticated account&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignInAuthentication&lt;/span&gt; &lt;span class="n"&gt;googleAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;googleUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Also get the access token from the authorization client (for scopes)&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;authClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;authClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationForScopes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'profile'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Build the Firebase credential from both tokens&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoogleAuthProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;idToken:&lt;/span&gt; &lt;span class="n"&gt;googleAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;idToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;accessToken:&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 5. Sign into Firebase — creates the user on first login automatically&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Apple Sign-In ────────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs in with Apple ID and returns a Firebase [UserCredential].&lt;/span&gt;
  &lt;span class="c1"&gt;/// Throws on cancellation or error — catch in your controller/notifier.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserCredential&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInWithApple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Generate a cryptographically random nonce (replay-attack protection)&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;rawNonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_generateNonce&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Request Apple credential — opens the system Sign-In sheet&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SignInWithApple&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAppleIDCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;scopes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;AppleIDAuthorizationScopes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;AppleIDAuthorizationScopes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Build the Firebase OAuthCredential using Apple's identity token&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;oAuthCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OAuthProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'apple.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;idToken:&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;identityToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;rawNonce:&lt;/span&gt; &lt;span class="n"&gt;rawNonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;accessToken:&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Sign into Firebase&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oAuthCredential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Sign Out ─────────────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs out from both Firebase and Google simultaneously.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Error Messages ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Converts a FirebaseAuthException into a user-readable message.&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;getFirebaseErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirebaseAuthException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'user-not-found'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'No account found with this email.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'wrong-password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Incorrect password.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'email-already-in-use'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'This email is already registered.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'invalid-email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Please enter a valid email.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'weak-password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Password is too weak.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'too-many-requests'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Too many attempts. Try again later.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'network-request-failed'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'No internet connection.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'operation-not-allowed'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'This sign-in method is not enabled.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'account-exists-with-different-credential'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'An account with this email exists with a different sign-in method.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Authentication failed. Please try again.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Nonce Generator (Apple Sign-In) ─────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Generates a cryptographically secure random string.&lt;/span&gt;
  &lt;span class="c1"&gt;/// Apple uses this to prevent replay attacks on the identity token.&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_generateNonce&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;06 / Platform Configuration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android &amp;amp; iOS Setup&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Android — Google Sign-In&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Get your SHA-1 fingerprint&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Debug keystore (development)&lt;/span&gt;
keytool &lt;span class="nt"&gt;-list&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-keystore&lt;/span&gt; ~/.android/debug.keystore &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-alias&lt;/span&gt; androiddebugkey &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-storepass&lt;/span&gt; android &lt;span class="nt"&gt;-keypass&lt;/span&gt; android
&lt;span class="c"&gt;# Copy the SHA1 line from the output, e.g.:&lt;/span&gt;
&lt;span class="c"&gt;# SHA1: A1:B2:C3:D4:E5:F6:...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this SHA-1 in Firebase Console → Project Settings → Your Android app → Add fingerprint. Then re-download google-services.json and place it at android/app/google-services.json.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzve5ddebzx9626rn9n6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzve5ddebzx9626rn9n6.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
⚠️ Add both debug and release SHA-1&lt;/p&gt;

&lt;p&gt;The debug SHA-1 works only during development. For production (Play Store), add the SHA-1 from yourupload keystore. Missing the release SHA-1 causes silent failures after publishing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Verify build.gradle files&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;android/build.gradle&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;buildscript&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s1"&gt;'com.google.gms:google-services:4.4.2'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;android/app/build.gradle&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Must be at the very bottom of the file&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'com.google.gms.google-services'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;iOS — Google Sign-In&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Add the reversed client ID URL scheme&lt;/strong&gt;&lt;br&gt;
Open GoogleService-Info.plist, find the REVERSED_CLIENT_ID value, then add it to ios/Runner/Info.plist:&lt;/p&gt;

&lt;p&gt;ios/Runner/Info.plist&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLTypes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleTypeRole&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Editor&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLSchemes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- REVERSED_CLIENT_ID from GoogleService-Info.plist --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.googleusercontent.apps.YOUR_REVERSED_CLIENT_ID&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;iOS — Apple Sign-In&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Enable the capability in Xcode&lt;/strong&gt;&lt;br&gt;
Open ios/Runner.xcworkspace in Xcode → select Runner target → Signing &amp;amp; Capabilities → + Capability → Sign In with Apple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Enable in Apple Developer Portal&lt;/strong&gt;&lt;br&gt;
Log into developer.apple.com → Identifiers → select your App ID → check Sign In with Apple → Save. Regenerate your provisioning profile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.Enable in Firebase Console&lt;/strong&gt;&lt;br&gt;
Firebase Console → Authentication → Sign-in method → Apple → Enable. Paste your App ID (e.g. com.company.app) as the Service ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.Add the entitlement (if needed)&lt;/strong&gt;&lt;br&gt;
Xcode usually handles this automatically when you add the capability. Verify Runner.entitlements contains com.apple.developer.applesignin with value Default.&lt;/p&gt;

&lt;p&gt;💡 Apple Sign-In on Android&lt;/p&gt;

&lt;p&gt;sign_in_with_apple supports Android via a web-based OAuth flow. You need to configure a web redirect URL in Apple Developer Console and add it to the plugin configuration. See the &lt;a href="https://pub.dev/packages/sign_in_with_apple" rel="noopener noreferrer"&gt;package README&lt;/a&gt; for the full Android setup guide.&lt;/p&gt;

&lt;p&gt;07 / Debugging&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Errors &amp;amp; Exact Fixes&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. StateError: instance not initialized&lt;/strong&gt;&lt;br&gt;
Root Cause: GoogleSignIn.instance is used before calling initialize()&lt;br&gt;
Fix: Make sure to call and await AuthService().initialize() inside main() before runApp()&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. sign_in_failed (Android)&lt;/strong&gt;&lt;br&gt;
Root Cause: SHA-1 fingerprint is missing or incorrect&lt;br&gt;
Fix: Add both debug and release SHA-1 in Firebase Console, then re-download google-services.json&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. PlatformException: sign_in_canceled&lt;/strong&gt;&lt;br&gt;
Root Cause: User closed the Google account picker&lt;br&gt;
Fix: This is expected behavior — handle it silently without showing an error toast&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. operation-not-allowed&lt;/strong&gt;&lt;br&gt;
Root Cause: Google Sign-In is not enabled in Firebase&lt;br&gt;
Fix: Go to Firebase Console → Authentication → Sign-in method → Enable Google&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. idToken is null&lt;/strong&gt;&lt;br&gt;
Root Cause: Authentication failed or was canceled silently&lt;br&gt;
Fix: Always check googleAuth.idToken != null before creating credentials&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Missing REVERSED_CLIENT_ID (iOS)&lt;/strong&gt;&lt;br&gt;
Root Cause: URL scheme is not configured in Info.plist&lt;br&gt;
Fix: Add CFBundleURLSchemes using the REVERSED_CLIENT_ID from GoogleService-Info.plist&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. AuthorizationError: canceled (Apple)&lt;/strong&gt;&lt;br&gt;
Root Cause: User canceled Apple Sign-In&lt;br&gt;
Fix: Catch SignInWithAppleAuthorizationException and ignore when e.code == AuthorizationErrorCode.canceled&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Apple name is null (returning user)&lt;/strong&gt;&lt;br&gt;
Root Cause: Apple only provides the user’s name during the first sign-in&lt;br&gt;
Fix: Save the name in your database when isNewUser == true and reuse it later&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. account-exists-with-different-credential&lt;/strong&gt;&lt;br&gt;
Root Cause: Same email is used with another authentication provider&lt;br&gt;
Fix: Use fetchSignInMethodsForEmail() and guide the user to link accounts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Apple Sign-In not working on Simulator&lt;/strong&gt;&lt;br&gt;
Root Cause: iOS Simulator does not support Apple Sign-In&lt;br&gt;
Fix: Always test Apple Sign-In on a real device&lt;/p&gt;

&lt;p&gt;08 / UI Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// GOOGLE LOGIN&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Google Login Success ✅"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// APPLE LOGIN&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginWithApple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithApple&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Apple Login Success 🍎"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;09 / Conclusion&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary &amp;amp; Best Practices&lt;/strong&gt;&lt;br&gt;
Here’s the complete checklist for production-ready social sign-in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Initialize once — call &lt;strong&gt;AuthService().initialize()&lt;/strong&gt; in &lt;strong&gt;main()&lt;/strong&gt; after Firebase and before &lt;strong&gt;runApp()&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server Client ID = Web Client — get the Web application client from Google Cloud Console, not Android or iOS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sign out Google on each sign-in — call &lt;strong&gt;_googleSignIn.signOut()&lt;/strong&gt; before authenticating so the picker always appears&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Both tokens for Firebase — always pass both &lt;strong&gt;idToken&lt;/strong&gt; and &lt;strong&gt;accessToken&lt;/strong&gt; to &lt;strong&gt;GoogleAuthProvider.credential()&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a secure nonce for Apple — generate it with &lt;strong&gt;Random.secure()&lt;/strong&gt;, always pass &lt;strong&gt;rawNonce&lt;/strong&gt; to the Firebase credential&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save Apple name immediately — it’s only available on the first sign-in; save it to your database right after &lt;strong&gt;isNewUser == true&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detect new vs returning users — use &lt;strong&gt;userCredential.additionalUserInfo?.isNewUser&lt;/strong&gt; to branch your post-auth flow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sign out from both — always call both &lt;strong&gt;_auth.signOut()&lt;/strong&gt; and &lt;strong&gt;_googleSignIn.signOut()&lt;/strong&gt; on logout&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SHA-1: debug + release — add both fingerprints to Firebase or Google Sign-In breaks in production builds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test Apple on a real device — iOS Simulator does not support Apple Sign-In.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>flutter</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flutter + Firebase Cloud Functions: Complete Guide with Real Examples 🚀</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Wed, 13 May 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/flutter-firebase-cloud-functions-complete-guide-with-real-examples-7h2</link>
      <guid>https://dev.to/codexlancers/flutter-firebase-cloud-functions-complete-guide-with-real-examples-7h2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Building modern mobile apps requires more than just a beautiful UI — you also need a reliable backend. This is where F**lutter and Firebase Cloud **Functions become a powerful combination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flutter&lt;/strong&gt; is a UI toolkit by Google that allows you to build natively compiled apps for mobile, web, and desktop using a single codebase.&lt;br&gt;
&lt;strong&gt;Firebase Cloud Functions&lt;/strong&gt; is a serverless backend solution that lets you run code in response to events without managing servers.&lt;br&gt;
👉 When you combine them, you get:&lt;/p&gt;

&lt;p&gt;A fast, scalable frontend (Flutter)&lt;br&gt;
A powerful, secure backend (Cloud Functions)&lt;br&gt;
This guide will walk you through everything — from setup to real-world examples — in a simple and practical way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use Flutter + Firebase Cloud Functions?&lt;/strong&gt;&lt;br&gt;
🔥 &lt;strong&gt;Key Benefits&lt;/strong&gt;&lt;br&gt;
Feature Benefit Serverless backend No need to manage serversReal-time integrationWorks seamlessly with Firestore Scalability Automatically scales with usersSecurityBackend logic stays hiddenCost-effectivePay only for usage&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;br&gt;
Here are some real-world scenarios where this combination shines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Secure Backend Logic&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Payment verification&lt;/li&gt;
&lt;li&gt;User authentication checks&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Notifications System&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send push notifications when data changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger alerts on user actions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Processing&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically process uploaded data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean and transform Firestore entries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Third-Party API Integration&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call external APIs securely (without exposing keys)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scheduled Jobs&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Daily reports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleanup tasks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Setup&lt;/strong&gt;&lt;br&gt;
Let’s set up everything from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Setup Flutter Project&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter create my_app
&lt;span class="nb"&gt;cd &lt;/span&gt;my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Setup Firebase&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Firebase Console&lt;/li&gt;
&lt;li&gt;Create a project&lt;/li&gt;
&lt;li&gt;Add Android/iOS app&lt;/li&gt;
&lt;li&gt;Download config files:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;google-services.json (Android)&lt;/li&gt;
&lt;li&gt;GoogleService-Info.plist (iOS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Add Firebase to Flutter&lt;/strong&gt;&lt;br&gt;
Add dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;firebase_core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^latest&lt;/span&gt;
  &lt;span class="na"&gt;cloud_firestore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize Firebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Setup Firebase CLI&lt;/strong&gt;&lt;br&gt;
Install CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; firebase-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase init functions

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript or TypeScript&lt;/li&gt;
&lt;li&gt;ESLint (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Write Your First Cloud Function&lt;/strong&gt;&lt;br&gt;
Example: Trigger when a user is created in Firestore&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onUserCreate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users/{userId}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New user created:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase deploy &lt;span class="nt"&gt;--only&lt;/span&gt; functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real-World Examples 🔥&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Example 1: Send Push Notification on New Message&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Cloud Function&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendNotification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages/{id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sendToTopic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allUsers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flutter Side&lt;/strong&gt;&lt;br&gt;
Subscribe to topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FirebaseMessaging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subscribeToTopic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"allUsers"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13ckgaxu7lulwggq827n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13ckgaxu7lulwggq827n.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: Secure Payment Verification&lt;/strong&gt;&lt;br&gt;
👉 Never verify payments on the client side!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud Function&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verifyPayment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paymentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Call payment gateway API&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// simulate&lt;/span&gt;

   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpsError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed-precondition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid payment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flutter Call&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseFunctions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;httpsCallable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'verifyPayment'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s"&gt;"paymentId"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 3: Auto-Update Data (Business Logic)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Use Case:&lt;/strong&gt;&lt;br&gt;
When an order is created → update user stats&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateUserStats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orders/{orderId}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;totalOrders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FieldValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 4: Call External API Securely&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchWeather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.weatherapi.com/v1/current.json?key=API_KEY&amp;amp;q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 API key stays safe in backend!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Practices&lt;/strong&gt; ✅&lt;br&gt;
&lt;strong&gt;1. Keep Business Logic in Cloud Functions&lt;/strong&gt;&lt;br&gt;
❌ Don’t trust frontend&lt;br&gt;
✅ Always validate on backend&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Use Environment Config&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firebase functions:config:set api.key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Handle Errors Properly&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpsError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invalid-argument&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Optimize Performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid heavy loops&lt;/li&gt;
&lt;li&gt;Use async/await properly&lt;/li&gt;
&lt;li&gt;Minimize Firestore reads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Secure Your Functions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use authentication checks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpsError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unauthenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common Pitfalls&lt;/strong&gt; ⚠️&lt;br&gt;
❌ &lt;strong&gt;1. Doing Everything in Flutter&lt;/strong&gt;&lt;br&gt;
➡️ Leads to security issues&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;2. Infinite Function Loops&lt;/strong&gt;&lt;br&gt;
Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function writes to Firestore&lt;/li&gt;
&lt;li&gt;Trigger fires again
👉 Fix:
Use flags or conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ &lt;strong&gt;3. Large Cold Start Delays&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Happens in unused functions&lt;br&gt;
👉 Fix:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use smaller functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use regional deployment&lt;br&gt;
❌ &lt;strong&gt;4. Exposing API Keys&lt;/strong&gt;&lt;br&gt;
👉 Always call APIs via Cloud Functions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ &lt;strong&gt;5. Not Handling Errors&lt;/strong&gt;&lt;br&gt;
👉 Always use try/catch&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Pro Tips *&lt;/em&gt;💡&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use TypeScript for better maintainability&lt;/li&gt;
&lt;li&gt;Structure functions into modules&lt;/li&gt;
&lt;li&gt;Log everything using console.log&lt;/li&gt;
&lt;li&gt;Monitor using Firebase Console
&lt;strong&gt;Conclusion&lt;/strong&gt; 🎯
Flutter + Firebase Cloud Functions is a powerful full-stack solution that allows you to build scalable, secure, and modern applications without managing servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 Flutter handles UI beautifully&lt;/li&gt;
&lt;li&gt;🔐 Cloud Functions handle secure backend logic&lt;/li&gt;
&lt;li&gt;⚡ Real-time + serverless = fast &amp;amp; scalable apps&lt;/li&gt;
&lt;li&gt;🧠 Keep sensitive logic off the client&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔧 Use triggers and callable functions wisely&lt;br&gt;
If you’re building apps with features like:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Payments 💳&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notifications 🔔&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AI integrations 🤖&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-time data 📡&lt;br&gt;
👉 Then this stack is one of the best choices available today.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Thought&lt;/strong&gt;&lt;br&gt;
Start simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build one function&lt;/li&gt;
&lt;li&gt;Connect it to Flutter&lt;/li&gt;
&lt;li&gt;Expand step by step
And soon, you’ll be building production-ready apps with confidence 🚀&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 How to Create and Use RPC Functions in Supabase with Flutter (Step-by-Step Guide)</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Tue, 12 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/how-to-create-and-use-rpc-functions-in-supabase-with-flutter-step-by-step-guide-10o0</link>
      <guid>https://dev.to/codexlancers/how-to-create-and-use-rpc-functions-in-supabase-with-flutter-step-by-step-guide-10o0</guid>
      <description>&lt;p&gt;🧠 &lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
When building modern apps, you often need to perform complex database operations — like filtering data, calculating values, or combining multiple queries. Writing all this logic directly in your Flutter app can quickly become messy and inefficient.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;RPC (Remote Procedure Call) functions&lt;/strong&gt; in Supabase come in.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;RPC functions&lt;/strong&gt; allow you to write SQL functions inside your database and call them directly from your app as if they were APIs.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Why use RPC functions in Supabase?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep business logic inside the database (cleaner architecture)&lt;/li&gt;
&lt;li&gt;Reduce network calls (better performance)&lt;/li&gt;
&lt;li&gt;Improve security (controlled access to data)&lt;/li&gt;
&lt;li&gt;Reuse logic across multiple clients (Flutter, Web, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧰 &lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;br&gt;
Before we start, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ A Flutter project set up&lt;/li&gt;
&lt;li&gt;✅ A Supabase project created&lt;/li&gt;
&lt;li&gt;✅ Supabase Flutter SDK installed&lt;/li&gt;
&lt;li&gt;✅ Basic knowledge of SQL (SELECT, WHERE, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ &lt;strong&gt;Step 1: Create an RPC Function in Supabase&lt;/strong&gt;&lt;br&gt;
Let’s say we have a tasks table and we want to fetch all completed tasks for a specific user.&lt;/p&gt;

&lt;p&gt;🗄️ &lt;strong&gt;Example Table:&lt;/strong&gt; tasks&lt;br&gt;
idtitleuser_idis_completed1Task A101true2Task B101false&lt;/p&gt;

&lt;p&gt;🧾 &lt;strong&gt;SQL Function&lt;/strong&gt;&lt;br&gt;
Go to &lt;strong&gt;Supabase Dashboard → SQL Editor&lt;/strong&gt;, and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get_completed_tasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p_user_id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;is_completed&lt;/span&gt; &lt;span class="nb"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;language&lt;/span&gt; &lt;span class="k"&gt;sql&lt;/span&gt;
&lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_completed&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p_user_id&lt;/span&gt;
    &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;is_completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔍 &lt;strong&gt;Explanation (Simple)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create or replace function → creates the RPC function&lt;/li&gt;
&lt;li&gt;p_user_id → input parameter&lt;/li&gt;
&lt;li&gt;returns table → defines output structure&lt;/li&gt;
&lt;li&gt;select ... → actual query logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 &lt;strong&gt;Step 2: Test the Function in Supabase&lt;/strong&gt;&lt;br&gt;
Before using it in Flutter, test it.&lt;/p&gt;

&lt;p&gt;Run this in SQL Editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;get_completed_tasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'your-user-id-here'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Expected Output&lt;/strong&gt;&lt;br&gt;
You should see only completed tasks for that user.&lt;/p&gt;

&lt;p&gt;📱 &lt;strong&gt;Step 3: Call RPC Function in Flutter&lt;/strong&gt;&lt;br&gt;
Now let’s call this function from your Flutter app.&lt;/p&gt;

&lt;p&gt;📦 &lt;strong&gt;Add Supabase Dependency&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;supabase_flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest_version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡ &lt;strong&gt;Initialize Supabase&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;url:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_SUPABASE_URL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;anonKey:&lt;/span&gt; &lt;span class="s"&gt;'YOUR_SUPABASE_ANON_KEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔥 &lt;strong&gt;Call RPC Function&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getCompletedTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;supabase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'get_completed_tasks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;params:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'p_user_id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧠 &lt;strong&gt;Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rpc() → calls Supabase function&lt;/li&gt;
&lt;li&gt;'get_completed_tasks' → function name&lt;/li&gt;
&lt;li&gt;params → must match SQL parameter names
🖥️ &lt;strong&gt;Use in UI&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FutureBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;future:&lt;/span&gt; &lt;span class="n"&gt;getCompletedTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CircularProgressIndicator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ListTile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="nl"&gt;subtitle:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Completed"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🌍 &lt;strong&gt;Real-World Use Case&lt;/strong&gt;&lt;br&gt;
Let’s say you’re building a Task Management App (like your current Flutter project 👀).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqttulxw523qtqd3cpcxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqttulxw523qtqd3cpcxp.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;❌ Fetching all tasks&lt;br&gt;
❌ Filtering in Flutter&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;p&gt;✅ Use RPC to fetch only required data&lt;br&gt;
✅ Improve performance and reduce app logic&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Other Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculating total revenue&lt;/li&gt;
&lt;li&gt;Fetching user-specific dashboards&lt;/li&gt;
&lt;li&gt;Complex joins across tables&lt;/li&gt;
&lt;li&gt;Role-based data filtering
⚠️ &lt;strong&gt;Common Mistakes&lt;/strong&gt;
❌ &lt;strong&gt;1. Parameter Name Mismatch&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nl"&gt;params:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'userId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// WRONG&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✔ Must match SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p_user_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ &lt;strong&gt;2. Forgetting Permissions (RLS)&lt;/strong&gt;&lt;br&gt;
If Row Level Security (RLS) is enabled:&lt;/p&gt;

&lt;p&gt;👉 Make sure policies allow access&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;3. Returning Wrong Data Type&lt;/strong&gt;&lt;br&gt;
If your function returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then handle it properly in Flutter.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;4. Not Testing in SQL First&lt;/strong&gt;&lt;br&gt;
Always test in Supabase before calling from Flutter.&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;Best Practices&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Keep functions simple and focused&lt;/strong&gt;&lt;br&gt;
One function = one responsibility&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Use meaningful names&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get_user_tasks ✔
fetch_data ❌
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Secure with RLS policies&lt;/strong&gt;&lt;br&gt;
Don’t expose sensitive data&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Use indexes for performance&lt;/strong&gt;&lt;br&gt;
Especially for large datasets&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Prefer SQL functions over multiple API calls&lt;/strong&gt;&lt;br&gt;
Cleaner + faster&lt;/p&gt;

&lt;p&gt;🏁 &lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
RPC functions in Supabase are a &lt;strong&gt;powerful way to move logic closer to your database&lt;/strong&gt;, making your Flutter apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Faster&lt;/li&gt;
&lt;li&gt;🧹 Cleaner&lt;/li&gt;
&lt;li&gt;🔐 More secure
By following this step-by-step guide, you can now:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✔ Create SQL functions&lt;br&gt;
✔ Test them in Supabase&lt;br&gt;
✔ Call them seamlessly from Flutter&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Next Steps&lt;/strong&gt;&lt;br&gt;
Add &lt;strong&gt;pagination&lt;/strong&gt; to your RPC functions&lt;br&gt;
Use &lt;strong&gt;PostgreSQL joins&lt;/strong&gt; inside functions&lt;br&gt;
Explore &lt;strong&gt;Edge Functions vs RPC&lt;/strong&gt;&lt;br&gt;
Build reusable &lt;strong&gt;backend logic library&lt;/strong&gt;&lt;br&gt;
If you’re building scalable Flutter apps with Supabase, mastering RPC is a &lt;strong&gt;game changer&lt;/strong&gt; 💥&lt;/p&gt;

</description>
      <category>database</category>
      <category>flutter</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 Integrating Tamara Payment Gateway in a FlutterFlow Application</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Mon, 11 May 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/integrating-tamara-payment-gateway-in-a-flutterflow-application-4080</link>
      <guid>https://dev.to/codexlancers/integrating-tamara-payment-gateway-in-a-flutterflow-application-4080</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9dhwbmva1zlcoumipqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9dhwbmva1zlcoumipqf.png" alt=" " width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
In today’s digital ecosystem, integrating a reliable payment gateway is essential for delivering a smooth and secure user experience. However, building a payment system isn’t just about processing transactions — it’s about ensuring &lt;strong&gt;security, reliability, and compliance,&lt;/strong&gt; all while maintaining a seamless user journey.&lt;/p&gt;

&lt;p&gt;Recently, I worked on integrating the &lt;strong&gt;Tamara Payment Gateway&lt;/strong&gt; into a FlutterFlow application, creating a complete end-to-end payment workflow — from initiating transactions to handling real-time updates.&lt;br&gt;
💡 &lt;strong&gt;The Goal&lt;/strong&gt;&lt;br&gt;
The objective was to implement a &lt;strong&gt;secure and scalable payment flow&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enables users to complete payments smoothly&lt;/li&gt;
&lt;li&gt;Handles transaction states reliably&lt;/li&gt;
&lt;li&gt;Ensures compliance with Tamara’s payment standards&lt;/li&gt;
&lt;li&gt;Works seamlessly across development and production environments
🛠️ &lt;strong&gt;The Implementation&lt;/strong&gt;
The integration involved connecting Tamara’s APIs with the FlutterFlow application and managing the full payment lifecycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ &lt;strong&gt;Key Features Implemented&lt;/strong&gt;&lt;br&gt;
🔹 &lt;strong&gt;Tamara Checkout API Integration&lt;/strong&gt;&lt;br&gt;
We used Tamara’s Checkout API to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initiate payment sessions&lt;/li&gt;
&lt;li&gt;Redirect users to the hosted checkout page&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Process transactions securely&lt;br&gt;
🔐 &lt;strong&gt;Secure Payment Handling&lt;/strong&gt;&lt;br&gt;
Security was a top priority. The implementation ensured:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proper API request validation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Safe handling of transaction data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compliance with Tamara’s payment flow&lt;br&gt;
🔔 &lt;strong&gt;Webhook Integration for Real-Time Updates&lt;/strong&gt;&lt;br&gt;
To keep track of payment status:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented webhooks to receive real-time updates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handled events such as:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Payment success&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Payment failure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transaction updates&lt;br&gt;
This ensures the app always reflects the correct payment status.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💳 &lt;strong&gt;Payment Method Support&lt;/strong&gt;&lt;br&gt;
Enabled support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visa cards&lt;/li&gt;
&lt;li&gt;Mada cards
This ensures compatibility with regional payment preferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 &lt;strong&gt;Environment Configuration&lt;/strong&gt;&lt;br&gt;
Set up both environments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sandbox (Development)&lt;/strong&gt; for testing&lt;br&gt;
&lt;strong&gt;Production&lt;/strong&gt; for live transactions&lt;br&gt;
This separation ensures safe development and smooth deployment.&lt;/p&gt;

&lt;p&gt;🔄 &lt;strong&gt;Reliable Request &amp;amp; Response Handling&lt;/strong&gt;&lt;br&gt;
Carefully managed API communication to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle success and failure cases&lt;/li&gt;
&lt;li&gt;Prevent duplicate transactions&lt;/li&gt;
&lt;li&gt;Ensure consistency across the payment flow
⚠️ &lt;strong&gt;Key Challenge: Hosted Checkout Limitations&lt;/strong&gt;
One of the most interesting aspects of this integration was understanding the limitations of Tamara’s &lt;strong&gt;hosted checkout flow&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvbrxz6uiqsf19gugshh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvbrxz6uiqsf19gugshh.png" alt=" " width="800" height="192"&gt;&lt;/a&gt;&lt;br&gt;
Unlike custom UI payment solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The payment interface is controlled by Tamara&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UI customization options are limited&lt;br&gt;
💡 &lt;strong&gt;Why This Matters&lt;/strong&gt;&lt;br&gt;
At first, this might seem like a limitation, but it actually ensures:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Higher security standards&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Compliance with payment regulations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Reduced risk of implementation errors&lt;br&gt;
Understanding these constraints helped align the integration with best practices recommended by Tamara.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📱 &lt;strong&gt;Final Result&lt;/strong&gt;&lt;br&gt;
The final implementation delivered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A stable and secure payment experience&lt;/li&gt;
&lt;li&gt;Smooth transaction processing&lt;/li&gt;
&lt;li&gt;Accurate real-time payment updates&lt;/li&gt;
&lt;li&gt;Full compliance with Tamara’s standards
Users can now complete payments confidently, knowing the system is both &lt;strong&gt;secure and reliable&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧠 &lt;strong&gt;Key Learnings&lt;/strong&gt;&lt;br&gt;
⚖️ &lt;strong&gt;Balancing UX and Security&lt;/strong&gt;&lt;br&gt;
Not all payment flows allow full UI control. Sometimes, prioritizing security and compliance is more important than customization.&lt;/p&gt;

&lt;p&gt;🔄 &lt;strong&gt;Importance of Webhooks&lt;/strong&gt;&lt;br&gt;
Webhooks are critical for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time updates&lt;/li&gt;
&lt;li&gt;Backend synchronization&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reliable transaction tracking&lt;br&gt;
💻 &lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FlutterFlow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dart&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tamara Payment Gateway APIs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Webhooks for real-time updates&lt;br&gt;
🧠 &lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
This integration reinforced an important lesson:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;A great payment system is not just about UX — it’s about trust, security, and reliability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By combining FlutterFlow with Tamara’s infrastructure, we were able to build a solution that meets both &lt;strong&gt;user expectations and industry standards.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re working on payment integrations, always remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand platform limitations&lt;/li&gt;
&lt;li&gt;Follow recommended flows&lt;/li&gt;
&lt;li&gt;Prioritize security over customization&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  FlutterFlow #PaymentGateway #Tamara #Fintech #MobileDevelopment #APIIntegration #Webhooks
&lt;/h1&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>nocode</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Google &amp; Apple Sign-In in Flutter</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Mon, 11 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/google-apple-sign-in-in-flutter-4102</link>
      <guid>https://dev.to/codexlancers/google-apple-sign-in-in-flutter-4102</guid>
      <description>&lt;p&gt;A production-grade walkthrough: clean auth service, real code from a real app, and integration patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Dependencies &amp;amp; Setup&lt;/li&gt;
&lt;li&gt;Getting the Server Client ID&lt;/li&gt;
&lt;li&gt;The Clean AuthService&lt;/li&gt;
&lt;li&gt;Platform Configuration&lt;/li&gt;
&lt;li&gt;Common Errors &amp;amp; Fixes&lt;/li&gt;
&lt;li&gt;UI Example&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  01 / Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Social Sign-In Still Matters in 2026
&lt;/h3&gt;

&lt;p&gt;Every additional step between a user opening your app and them being inside it is a drop-off point. Password flows are friction. Google and Apple Sign-In are the fastest path from “curious” to “engaged” — two taps and you’re in, no new password to forget.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Who this is for&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Flutter developers at any level who want latest Google and Apple Sign-In that actually works in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  02 / Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What You Need Before Starting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A Firebase project with Authentication enabled — Google and Apple providers turned on&lt;/li&gt;
&lt;li&gt;FlutterFire CLI installed and flutterfire configure already run&lt;/li&gt;
&lt;li&gt;For Apple Sign-In: an Apple Developer account with Sign In with Apple capability enabled&lt;/li&gt;
&lt;li&gt;For Android Google Sign-In: SHA-1 fingerprint registered in Firebase Console&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  03 / Dependencies &amp;amp; Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Packages, pubspec, and Initialization
&lt;/h3&gt;

&lt;p&gt;Add to pubspec.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter_dotenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.2.1&lt;/span&gt;
  &lt;span class="na"&gt;firebase_core&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.10.1&lt;/span&gt;
  &lt;span class="na"&gt;firebase_auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.5.1&lt;/span&gt;
  &lt;span class="na"&gt;google_sign_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^7.2.0&lt;/span&gt;
  &lt;span class="na"&gt;sign_in_with_apple&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^7.0.1&lt;/span&gt;

&lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Create your .env file
&lt;/h3&gt;

&lt;p&gt;Store sensitive config outside of source code. Create a .env file in your project root and add it to .gitignore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Get this from Google Cloud Console → OAuth 2.0 → Web Client (see Section 4)
SERVER_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Initialize Firebase and Google Sign-In in main.dart
&lt;/h3&gt;

&lt;p&gt;This is the most important step people miss, you must call GoogleSignIn.instance.initialize() before runApp(), after Firebase is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_core/firebase_core.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:your_app/service/auth_service.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Load environment variables&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;fileName:&lt;/span&gt; &lt;span class="s"&gt;'.env'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Initialize Firebase&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Firebase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;options:&lt;/span&gt; &lt;span class="n"&gt;DefaultFirebaseOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentPlatform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Initialize AuthService (which calls GoogleSignIn.instance.initialize)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚨 Skip initialize() and you’ll get a StateError&lt;/p&gt;

&lt;p&gt;If you call authenticate() or authorizationClient before initialize(), Flutter throws a StateError: instance not initialized. This crashes silently in release builds. Always initialize first.&lt;/p&gt;




&lt;h2&gt;
  
  
  04 / Google Cloud Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Getting the Server Client ID (Web OAuth Client)
&lt;/h3&gt;

&lt;p&gt;The serverClientId is the Web Client ID from Google Cloud Console — not the Android or iOS client. It is required for Google Sign-In on Android and enables server-side token verification. Here's exactly how to find it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Cloud Console — Step-by-step walkthrough
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;console.cloud.google.com&lt;/a&gt; and select your Firebase project (same project name as in Firebase Console)&lt;/p&gt;

&lt;p&gt;2 . In the left sidebar, navigate to &lt;a href="https://console.cloud.google.com/apis/credentials" rel="noopener noreferrer"&gt;APIs &amp;amp; Services → Credentials&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Under OAuth 2.0 Client IDs, look for the entry with type “Web application”. It is usually auto-created by Firebase and named something like “Web client (auto created by Google Service)”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the Web application entry to open its details&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the Client ID field — it ends in .apps.googleusercontent.com. This is your SERVER_CLIENT_ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste it into your .env file as SERVER_CLIENT_ID=your_id&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 Can’t find the Web Client?&lt;/p&gt;

&lt;p&gt;If you don’t see a Web Client ID, go to Firebase Console → Authentication → Sign-in method → Google → click the expand arrow. Firebase will show you the Web SDK configuration which contains the same client ID.&lt;/p&gt;

&lt;p&gt;⚠️ Android vs iOS vs Web — use the Web client&lt;/p&gt;

&lt;p&gt;There will be separate entries for Android, iOS, and Web in the credentials list. The serverClientId parameterspecifically requires the Web client ID. Using the Android or iOS client ID here is a common mistake that silently fails.&lt;/p&gt;




&lt;h2&gt;
  
  
  05 / The Clean AuthService
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication Service Implementation
&lt;/h3&gt;

&lt;p&gt;Here’s the authentication logic, cleaned up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lib/service/auth_service.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:developer'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:math'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:firebase_auth/firebase_auth.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_dotenv/flutter_dotenv.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_sign_in/google_sign_in.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:sign_in_with_apple/sign_in_with_apple.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// Clean authentication service — auth logic only, no database concerns.&lt;/span&gt;
&lt;span class="c1"&gt;/// Use it as a foundation and add your own data layer on top.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ─── Singleton ───────────────────────────────────────────&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Firebase + Google ────────────────────────────────────&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;FirebaseAuth&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FirebaseAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignIn&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoogleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;/// Web Client ID from Google Cloud Console → OAuth 2.0 → Web application&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;_serverClientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'SERVER_CLIENT_ID'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Public Getters ───────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;isSignedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Initialization ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Call once at app startup, after Firebase.initializeApp().&lt;/span&gt;
  &lt;span class="c1"&gt;/// Required by google_sign_in v7+ before any sign-in call.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;serverClientId:&lt;/span&gt; &lt;span class="n"&gt;_serverClientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[AuthService] Google Sign-In initialized'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[AuthService] Google init error: &lt;/span&gt;&lt;span class="si"&gt;$e&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// fail fast — misconfiguration should be caught at startup&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Google Sign-In ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs in with Google and returns a Firebase [UserCredential].&lt;/span&gt;
  &lt;span class="c1"&gt;/// Throws on cancellation or error — catch in your controller/notifier.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserCredential&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Sign out first — ensures the account picker is always shown&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. Trigger Google authentication — shows the account picker&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignInAccount&lt;/span&gt; &lt;span class="n"&gt;googleUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;scopeHint:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Get the ID token directly from the authenticated account&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GoogleSignInAuthentication&lt;/span&gt; &lt;span class="n"&gt;googleAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;googleUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Also get the access token from the authorization client (for scopes)&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;authClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;authClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationForScopes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'profile'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Build the Firebase credential from both tokens&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GoogleAuthProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;idToken:&lt;/span&gt; &lt;span class="n"&gt;googleAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;idToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;accessToken:&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 5. Sign into Firebase — creates the user on first login automatically&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Apple Sign-In ────────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs in with Apple ID and returns a Firebase [UserCredential].&lt;/span&gt;
  &lt;span class="c1"&gt;/// Throws on cancellation or error — catch in your controller/notifier.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UserCredential&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signInWithApple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Generate a cryptographically random nonce (replay-attack protection)&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;rawNonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_generateNonce&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Request Apple credential — opens the system Sign-In sheet&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SignInWithApple&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAppleIDCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;scopes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;AppleIDAuthorizationScopes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;AppleIDAuthorizationScopes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Build the Firebase OAuthCredential using Apple's identity token&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;oAuthCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OAuthProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'apple.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;idToken:&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;identityToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;rawNonce:&lt;/span&gt; &lt;span class="n"&gt;rawNonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;accessToken:&lt;/span&gt; &lt;span class="n"&gt;appleCredential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Sign into Firebase&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oAuthCredential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Sign Out ─────────────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Signs out from both Firebase and Google simultaneously.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="n"&gt;_auth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="n"&gt;_googleSignIn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Error Messages ───────────────────────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Converts a FirebaseAuthException into a user-readable message.&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;getFirebaseErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FirebaseAuthException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'user-not-found'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'No account found with this email.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'wrong-password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Incorrect password.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'email-already-in-use'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'This email is already registered.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'invalid-email'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Please enter a valid email.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'weak-password'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Password is too weak.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'too-many-requests'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Too many attempts. Try again later.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'network-request-failed'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'No internet connection.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'operation-not-allowed'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'This sign-in method is not enabled.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'account-exists-with-different-credential'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'An account with this email exists with a different sign-in method.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'Authentication failed. Please try again.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ─── Nonce Generator (Apple Sign-In) ─────────────────────&lt;/span&gt;

  &lt;span class="c1"&gt;/// Generates a cryptographically secure random string.&lt;/span&gt;
  &lt;span class="c1"&gt;/// Apple uses this to prevent replay attacks on the identity token.&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_generateNonce&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  06 / Platform Configuration
&lt;/h2&gt;

&lt;p&gt;Android &amp;amp; iOS Setup&lt;/p&gt;

&lt;h3&gt;
  
  
  Android — Google Sign-In
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Get your SHA-1 fingerprint
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Debug keystore (development)&lt;/span&gt;
keytool &lt;span class="nt"&gt;-list&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-keystore&lt;/span&gt; ~/.android/debug.keystore &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-alias&lt;/span&gt; androiddebugkey &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-storepass&lt;/span&gt; android &lt;span class="nt"&gt;-keypass&lt;/span&gt; android
&lt;span class="c"&gt;# Copy the SHA1 line from the output, e.g.:&lt;/span&gt;
&lt;span class="c"&gt;# SHA1: A1:B2:C3:D4:E5:F6:...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this SHA-1 in Firebase Console → Project Settings → Your Android app → Add fingerprint. Then re-download google-services.json and place it at android/app/google-services.json.&lt;/p&gt;

&lt;p&gt;Become a Medium member&lt;/p&gt;

&lt;p&gt;⚠️ Add both debug and release SHA-1&lt;/p&gt;

&lt;p&gt;The debug SHA-1 works only during development. For production (Play Store), add the SHA-1 from yourupload keystore. Missing the release SHA-1 causes silent failures after publishing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify build.gradle files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;android/build.gradle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;buildscript&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s1"&gt;'com.google.gms:google-services:4.4.2'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;android/app/build.gradle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Must be at the very bottom of the file&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'com.google.gms.google-services'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  iOS — Google Sign-In
&lt;/h3&gt;

&lt;p&gt;Add the reversed client ID URL scheme&lt;/p&gt;

&lt;p&gt;Open GoogleService-Info.plist, find the REVERSED_CLIENT_ID value, then add it to ios/Runner/Info.plist:&lt;/p&gt;

&lt;p&gt;ios/Runner/Info.plist&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLTypes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleTypeRole&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Editor&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLSchemes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- REVERSED_CLIENT_ID from GoogleService-Info.plist --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.googleusercontent.apps.YOUR_REVERSED_CLIENT_ID&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  iOS — Apple Sign-In
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enable the capability in Xcode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open ios/Runner.xcworkspace in Xcode → select Runner target → Signing &amp;amp; Capabilities → + Capability → Sign In with Apple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable in Apple Developer Portal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Log into developer.apple.com → Identifiers → select your App ID → check Sign In with Apple → Save. Regenerate your provisioning profile.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable in Firebase Console&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firebase Console → Authentication → Sign-in method → Apple → Enable. Paste your App ID (e.g. com.company.app) as the Service ID.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the entitlement (if needed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Xcode usually handles this automatically when you add the capability. Verify Runner.entitlements contains com.apple.developer.applesignin with value Default.&lt;/p&gt;

&lt;p&gt;💡 Apple Sign-In on Android&lt;/p&gt;

&lt;p&gt;sign_in_with_apple supports Android via a web-based OAuth flow. You need to configure a web redirect URL in Apple Developer Console and add it to the plugin configuration. See the package README for the full Android setup guide.&lt;/p&gt;




&lt;h2&gt;
  
  
  07 / Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Common Errors &amp;amp; Exact Fixes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;StateError: instance not initialized&lt;br&gt;
Root Cause: GoogleSignIn.instance is used before calling initialize()&lt;br&gt;
Fix: Make sure to call and await AuthService().initialize() inside main() before runApp()&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sign_in_failed (Android)&lt;br&gt;
Root Cause: SHA-1 fingerprint is missing or incorrect&lt;br&gt;
Fix: Add both debug and release SHA-1 in Firebase Console, then re-download google-services.json&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PlatformException: sign_in_canceled&lt;br&gt;
Root Cause: User closed the Google account picker&lt;br&gt;
Fix: This is expected behavior — handle it silently without showing an error toast&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;operation-not-allowed&lt;br&gt;
Root Cause: Google Sign-In is not enabled in Firebase&lt;br&gt;
Fix: Go to Firebase Console → Authentication → Sign-in method → Enable Google&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;idToken is null&lt;br&gt;
Root Cause: Authentication failed or was canceled silently&lt;br&gt;
Fix: Always check googleAuth.idToken != null before creating credentials&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Missing REVERSED_CLIENT_ID (iOS)&lt;br&gt;
Root Cause: URL scheme is not configured in Info.plist&lt;br&gt;
Fix: Add CFBundleURLSchemes using the REVERSED_CLIENT_ID from GoogleService-Info.plist&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AuthorizationError: canceled (Apple)&lt;br&gt;
Root Cause: User canceled Apple Sign-In&lt;br&gt;
Fix: Catch SignInWithAppleAuthorizationException and ignore when e.code == AuthorizationErrorCode.canceled&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apple name is null (returning user)&lt;br&gt;
Root Cause: Apple only provides the user’s name during the first sign-in&lt;br&gt;
Fix: Save the name in your database when isNewUser == true and reuse it later&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;account-exists-with-different-credential&lt;br&gt;
Root Cause: Same email is used with another authentication provider&lt;br&gt;
Fix: Use fetchSignInMethodsForEmail() and guide the user to link accounts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apple Sign-In not working on Simulator&lt;br&gt;
Root Cause: iOS Simulator does not support Apple Sign-In&lt;br&gt;
Fix: Always test Apple Sign-In on a real device&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  08 / UI Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// GOOGLE LOGIN&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Google Login Success ✅"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// APPLE LOGIN&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loginWithApple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signInWithApple&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Apple Login Success 🍎"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  09 / Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Summary &amp;amp; Best Practices
&lt;/h3&gt;

&lt;p&gt;Here’s the complete checklist for production-ready social sign-in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialize once — call AuthService().initialize() in main() after Firebase and before runApp()&lt;/li&gt;
&lt;li&gt;Server Client ID = Web Client — get the Web application client from Google Cloud Console, not Android or iOS&lt;/li&gt;
&lt;li&gt;Sign out Google on each sign-in — call _googleSignIn.signOut() before authenticating so the picker always appears&lt;/li&gt;
&lt;li&gt;Both tokens for Firebase — always pass both idToken and accessToken to GoogleAuthProvider.credential()&lt;/li&gt;
&lt;li&gt;Use a secure nonce for Apple — generate it with Random.secure(), always pass rawNonce to the Firebase credential&lt;/li&gt;
&lt;li&gt;Save Apple name immediately — it’s only available on the first sign-in; save it to your database right after isNewUser == true&lt;/li&gt;
&lt;li&gt;Detect new vs returning users — use userCredential.additionalUserInfo?.isNewUser to branch your post-auth flow&lt;/li&gt;
&lt;li&gt;Sign out from both — always call both _auth.signOut() and _googleSignIn.signOut() on logout&lt;/li&gt;
&lt;li&gt;SHA-1: debug + release — add both fingerprints to Firebase or Google Sign-In breaks in production builds&lt;/li&gt;
&lt;li&gt;Test Apple on a real device — iOS Simulator does not support Apple Sign-In.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>flutter</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 FlutterFlow’s New Feature: App Events (A Game Changer for Scalable Apps)</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Sat, 09 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/flutterflows-new-feature-app-events-a-game-changer-for-scalable-apps-1hp9</link>
      <guid>https://dev.to/codexlancers/flutterflows-new-feature-app-events-a-game-changer-for-scalable-apps-1hp9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F124qkagvo1woq4xk9r3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F124qkagvo1woq4xk9r3s.png" alt=" " width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
Building scalable applications in low-code platforms has always been a balance between &lt;strong&gt;speed and maintainability&lt;/strong&gt;. While FlutterFlow makes UI development incredibly fast, managing communication between different parts of an app could sometimes become complex.&lt;/p&gt;

&lt;p&gt;But with the introduction of &lt;strong&gt;App Events&lt;/strong&gt;, FlutterFlow has taken a major step forward — bringing cleaner architecture, better performance, and a much more scalable approach to app development.&lt;/p&gt;

&lt;p&gt;🤯 &lt;strong&gt;The Problem Before App Events&lt;/strong&gt;&lt;br&gt;
Before this update, handling communication between screens or components often involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Passing multiple navigation parameters&lt;/li&gt;
&lt;li&gt;❌ Managing complex global or local state&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ Writing tightly coupled logic between screens&lt;br&gt;
As apps grew larger, this approach became:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hard to maintain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Difficult to debug&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Less scalable&lt;br&gt;
💡 &lt;strong&gt;What Are App Events?&lt;/strong&gt;&lt;br&gt;
App Events introduce a &lt;strong&gt;decoupled communication system&lt;/strong&gt; inside FlutterFlow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Core Idea:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger an event from anywhere in the app&lt;/li&gt;
&lt;li&gt;Listen and respond to that event from anywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No direct connection between components is required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh420jn9ihkyrzfv1h3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh420jn9ihkyrzfv1h3c.png" alt=" " width="800" height="192"&gt;&lt;/a&gt;&lt;br&gt;
This means your app becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More modular&lt;/li&gt;
&lt;li&gt;Easier to maintain&lt;/li&gt;
&lt;li&gt;Much cleaner in terms of logic
🔄 &lt;strong&gt;How It Works (Simple Example)&lt;/strong&gt;
Let’s say a user adds an item to the cart 🛒&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Without App Events:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually update cart badge&lt;/li&gt;
&lt;li&gt;Refresh product list&lt;/li&gt;
&lt;li&gt;Update summary screen&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pass state across multiple screens&lt;br&gt;
&lt;strong&gt;With App Events:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger event → “Cart Updated”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All relevant UI components automatically react&lt;br&gt;
✨ That’s it. No messy logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔑 &lt;strong&gt;Key Highlights&lt;/strong&gt;&lt;br&gt;
🌍 &lt;strong&gt;Global Events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App-level events&lt;/li&gt;
&lt;li&gt;Handled across the entire application&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Processed sequentially&lt;br&gt;
&lt;strong&gt;Perfect for&lt;/strong&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Authentication state changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analytics tracking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Logging&lt;br&gt;
📍 &lt;strong&gt;Local Events&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scoped to specific pages or components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support multiple listeners&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger instant UI updates&lt;br&gt;
&lt;strong&gt;Perfect for:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UI refresh&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Component communication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dynamic interactions&lt;br&gt;
🚀 &lt;strong&gt;Why This Feature Matters&lt;/strong&gt;&lt;br&gt;
App Events bring FlutterFlow closer to &lt;strong&gt;modern software architecture&lt;/strong&gt; patterns, such as:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Event-driven systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loose coupling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reactive UI updates&lt;br&gt;
💥 &lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Less complex code structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easier debugging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved scalability&lt;br&gt;
⚡ &lt;strong&gt;My Take&lt;/strong&gt;&lt;br&gt;
This is easily one of the &lt;strong&gt;most impactful updates in FlutterFlow&lt;/strong&gt; in recent times.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It solves a real problem developers face when scaling apps and introduces a pattern that aligns with how modern applications are built.&lt;/p&gt;

&lt;p&gt;🧩 &lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
FlutterFlow continues to evolve beyond just a UI builder — it’s becoming a &lt;strong&gt;serious development platform&lt;/strong&gt; capable of handling complex applications.&lt;/p&gt;

&lt;p&gt;App Events are a big step in that direction.&lt;/p&gt;

&lt;p&gt;👉 If you haven’t explored it yet, now is the time.&lt;/p&gt;

&lt;h1&gt;
  
  
  FlutterFlow #NoCode #LowCode #AppDevelopment #MobileDevelopment #Firebase #UIUX #TechUpdate #Developers
&lt;/h1&gt;

</description>
      <category>architecture</category>
      <category>flutter</category>
      <category>news</category>
      <category>nocode</category>
    </item>
    <item>
      <title>🚀 1. How I Built a Production-Ready AI Chat App in FlutterFlow (With OpenAI + Firebase)</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Fri, 08 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/1-how-i-built-a-production-ready-ai-chat-app-in-flutterflow-with-openai-firebase-lem</link>
      <guid>https://dev.to/codexlancers/1-how-i-built-a-production-ready-ai-chat-app-in-flutterflow-with-openai-firebase-lem</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7bwa41yb56cm4bpks86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7bwa41yb56cm4bpks86.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
AI is everywhere in 2026 — but building a production-ready AI chat app is still challenging, especially when using low-code tools like FlutterFlow.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through how I built a scalable AI chat system using &lt;strong&gt;FlutterFlow + Firebase + OpenAI API.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;Architecture Overview&lt;/strong&gt;&lt;br&gt;
My setup looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt; → FlutterFlow UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt; → Firebase (Firestore + Cloud Functions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Engine&lt;/strong&gt; → OpenAI API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt; → Chat history in Firestore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💬** Chat Data Structure**&lt;br&gt;
Each message is stored like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello AI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi, how can I help?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server_time"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy chat history retrieval&lt;/li&gt;
&lt;li&gt;Real-time UI updates&lt;/li&gt;
&lt;li&gt;Scalable structure
🔐 &lt;strong&gt;Securing OpenAI API&lt;/strong&gt;
Never expose your API key in the frontend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh2uoi2iuq6qcqc1j2wl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh2uoi2iuq6qcqc1j2wl.png" alt=" "&gt;&lt;/a&gt;&lt;br&gt;
Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Firebase Cloud Functions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Send request → backend → OpenAI → return response
This keeps your app secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚡ &lt;strong&gt;Handling Token Usage (Cost Control)&lt;/strong&gt;&lt;br&gt;
AI APIs can get expensive.&lt;/p&gt;

&lt;p&gt;What I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limit message length&lt;/li&gt;
&lt;li&gt;Store token usage&lt;/li&gt;
&lt;li&gt;Restrict free users (daily limit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 &lt;strong&gt;UI Challenges &amp;amp; Solutions&lt;/strong&gt;&lt;br&gt;
Problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Chat UI lag with many messages&lt;br&gt;
Solution:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pagination&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lazy loading&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Efficient Firestore queries&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 &lt;strong&gt;Final Result&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time AI chat&lt;/li&gt;
&lt;li&gt;Scalable backend&lt;/li&gt;
&lt;li&gt;Controlled cost&lt;/li&gt;
&lt;li&gt;Smooth UI
💡 &lt;strong&gt;Final Thoughts&lt;/strong&gt;
FlutterFlow is powerful — but combining it with backend logic is the real game-changer.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>flutter</category>
      <category>nocode</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>FlutterFlow + RevenueCat: Complete Guide to Subscription Apps</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Thu, 07 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/flutterflow-revenuecat-complete-guide-to-subscription-apps-23d0</link>
      <guid>https://dev.to/codexlancers/flutterflow-revenuecat-complete-guide-to-subscription-apps-23d0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1w6zatleo8l3c2ondwfp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1w6zatleo8l3c2ondwfp.png" alt=" " width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
If you’re building a SaaS or premium mobile app, &lt;strong&gt;subscriptions are one of the most reliable monetization models.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But implementing subscriptions correctly is not just about adding a payment button — it involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure validation&lt;/li&gt;
&lt;li&gt;Real-time status updates&lt;/li&gt;
&lt;li&gt;Handling edge cases (expiry, restore, refunds)
In this guide, I’ll walk you through how I implemented a &lt;strong&gt;production-ready subscription system using FlutterFlow + RevenueCat + Firebase.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💰 &lt;strong&gt;Why RevenueCat?&lt;/strong&gt;&lt;br&gt;
Instead of directly handling &lt;strong&gt;App Store / Play Store billing&lt;/strong&gt;, I used RevenueCat because it simplifies everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Single integration for both iOS &amp;amp; Android&lt;/li&gt;
&lt;li&gt;✅ Handles receipts, validation, and renewals&lt;/li&gt;
&lt;li&gt;✅ Real-time subscription status via webhooks&lt;/li&gt;
&lt;li&gt;✅ Reduces development complexity
👉 Without RevenueCat, managing subscriptions manually becomes very complex.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🏗️ &lt;strong&gt;System Architecture (Simple View)&lt;/strong&gt;&lt;br&gt;
Here’s how the system works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FlutterFlow App (Frontend)&lt;/strong&gt;&lt;br&gt;
→ User interacts with UI (Upgrade, Restore)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RevenueCat SDK&lt;/strong&gt;&lt;br&gt;
→ Handles purchase flow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RevenueCat Server&lt;/strong&gt;&lt;br&gt;
→ Validates transactions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Firebase (Firestore + Cloud Functions)&lt;/strong&gt;&lt;br&gt;
→ Stores subscription status &amp;amp; triggers updates&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔄 &lt;strong&gt;Complete Subscription Flow&lt;/strong&gt;&lt;br&gt;
Here’s the exact flow I implemented:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. User Action&lt;/strong&gt;&lt;br&gt;
User clicks “Upgrade to Premium”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Purchase Trigger&lt;/strong&gt;&lt;br&gt;
RevenueCat SDK opens native purchase screen (App Store / Play Store)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Payment Processing&lt;/strong&gt;&lt;br&gt;
Payment handled securely by Apple/Google&lt;br&gt;
RevenueCat validates purchase&lt;br&gt;
&lt;strong&gt;4. Webhook Trigger&lt;/strong&gt;&lt;br&gt;
RevenueCat sends event → Firebase Cloud Function&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Firestore Update&lt;/strong&gt;&lt;br&gt;
User document is updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"isPremium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"plan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"expiryDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timestamp"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. UI Update&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FlutterFlow listens to Firestore&lt;/li&gt;
&lt;li&gt;Premium features unlock instantly
🧾 &lt;strong&gt;Firestore Database Structure&lt;/strong&gt;
To keep things scalable and clean, I used this structure:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔹 &lt;strong&gt;users collection&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"isPremium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"plan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yearly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"expiryDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timestamp"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔹 &lt;strong&gt;subscriptions collection&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"planId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly_001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1 month"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔹 &lt;strong&gt;events collection (VERY IMPORTANT)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PURCHASE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server_time"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This helps in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tracking revenue&lt;/li&gt;
&lt;li&gt;Debugging issues&lt;/li&gt;
&lt;li&gt;Analytics
⚠️ &lt;strong&gt;Handling Edge Cases (Most Developers Miss This)&lt;/strong&gt;
This is where most apps fail ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1. Expired Subscription&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check expiryDate regularly&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disable premium access automatically&lt;br&gt;
&lt;strong&gt;2. Restore Purchases&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Restore button&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sync with RevenueCat&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update Firestore again&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Cancelled Subscription&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User cancels from App Store&lt;/li&gt;
&lt;li&gt;RevenueCat webhook updates backend&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access removed after expiry&lt;br&gt;
&lt;strong&gt;4. Refunds&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RevenueCat sends refund event&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Immediately update user access&lt;br&gt;
🔐 &lt;strong&gt;Backend Validation (CRITICAL)&lt;/strong&gt;&lt;br&gt;
Never trust frontend logic ❌&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77yjlf28f16tfuxsiif4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77yjlf28f16tfuxsiif4.png" alt=" " width="800" height="192"&gt;&lt;/a&gt;&lt;br&gt;
Always validate subscription from backend using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RevenueCat webhooks&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firebase Cloud Functions&lt;br&gt;
👉 Why?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prevents fake unlock hacks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensures real subscription status&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeps your app secure&lt;br&gt;
⚡ &lt;strong&gt;Performance &amp;amp; Cost Optimization&lt;/strong&gt;&lt;br&gt;
Here’s what I optimized:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔹 &lt;strong&gt;Avoid Excessive Reads&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store only required subscription fields&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t fetch full history every time&lt;br&gt;
🔹 &lt;strong&gt;Use Real-Time Listeners Smartly&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Listen only to user document&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid unnecessary listeners&lt;br&gt;
🔹 &lt;strong&gt;Cache Subscription Status&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduce repeated API calls&lt;br&gt;
🎯 &lt;strong&gt;UI Best Practices (Conversion Focused)&lt;/strong&gt;&lt;br&gt;
Subscription UI is not just design — it impacts revenue 💰&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What worked for me:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highlight best plan (yearly)&lt;/li&gt;
&lt;li&gt;Show discount badge (Save 30%)&lt;/li&gt;
&lt;li&gt;Clear CTA: “Upgrade Now”&lt;/li&gt;
&lt;li&gt;Add trust elements (secure payment, cancel anytime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 &lt;strong&gt;Final Result&lt;/strong&gt;&lt;br&gt;
After implementing this system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Smooth and secure purchase flow&lt;/li&gt;
&lt;li&gt;✅ Real-time subscription updates&lt;/li&gt;
&lt;li&gt;✅ Scalable backend architecture&lt;/li&gt;
&lt;li&gt;✅ Reduced bugs and edge case failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 &lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
FlutterFlow + RevenueCat is a &lt;strong&gt;powerful combination&lt;/strong&gt; for building subscription-based apps quickly.&lt;/p&gt;

&lt;p&gt;But the real difference comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proper backend validation&lt;/li&gt;
&lt;li&gt;Clean database design&lt;/li&gt;
&lt;li&gt;Handling real-world edge cases
👉 That’s what turns a basic app into a production-ready SaaS product.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>saas</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 Flutter Performance Optimization: 10 Proven Tips to Make Your App Faster</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Wed, 06 May 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/flutter-performance-optimization-10-proven-tips-to-make-your-app-faster-39m8</link>
      <guid>https://dev.to/codexlancers/flutter-performance-optimization-10-proven-tips-to-make-your-app-faster-39m8</guid>
      <description>&lt;p&gt;Flutter makes it incredibly easy to build beautiful cross-platform apps. But as your app grows, performance can quickly become a bottleneck — laggy UI, dropped frames, slow builds… and frustrated users.&lt;/p&gt;

&lt;p&gt;In today’s competitive app ecosystem, performance is not optional. Users expect smooth animations, fast load times, and responsive interactions. Even a delay of a few milliseconds can impact user retention.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslcm9xexm5nrxyrjgds7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslcm9xexm5nrxyrjgds7.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we’ll explore &lt;strong&gt;10 practical and proven tips&lt;/strong&gt; to optimize your Flutter app performance — with clear explanations and code examples where needed.&lt;br&gt;
🔧 &lt;strong&gt;1. Minimize Unnecessary Widget Rebuilds&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Frequent widget rebuilds can slow down your app and cause UI lag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use const widgets wherever possible&lt;/li&gt;
&lt;li&gt;Use efficient builders like:&lt;/li&gt;
&lt;li&gt;ValueListenableBuilder&lt;/li&gt;
&lt;li&gt;Selector (Provider)&lt;/li&gt;
&lt;li&gt;Obx (GetX)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;ValueListenableBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;valueListenable:&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;$value&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nf"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Flutter"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces unnecessary rebuilds&lt;/li&gt;
&lt;li&gt;Improves rendering performance
🧠 &lt;strong&gt;2. Choose the Right State Management&lt;/strong&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;
Poor state management = unnecessary UI updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommended:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GetX&lt;/strong&gt; → lightweight, fast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Riverpod&lt;/strong&gt; → scalable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider&lt;/strong&gt; → simple apps
&lt;strong&gt;Tip:&lt;/strong&gt;
Avoid calling setState() for large widgets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 &lt;strong&gt;3. Offload Heavy Tasks Using compute() (Multithreading)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters&lt;/strong&gt;&lt;br&gt;
Running heavy tasks on the main thread causes UI freezes and dropped frames.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;br&gt;
Use compute() to run expensive operations in a separate isolate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/foundation.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;heavyTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heavyTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smooth UI performance&lt;/li&gt;
&lt;li&gt;Prevents frame drops&lt;/li&gt;
&lt;li&gt;Better user experience
🖼️ &lt;strong&gt;4. Optimize Images&lt;/strong&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;
Large images = memory + performance issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best Practices:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use compressed images&lt;/li&gt;
&lt;li&gt;Use cacheWidth / cacheHeight
&lt;strong&gt;Example:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;cacheWidth:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt;&lt;br&gt;
Use cached_network_image for caching.&lt;/p&gt;

&lt;p&gt;⚡ &lt;strong&gt;5. Use&lt;/strong&gt; ListView.builder &lt;strong&gt;for Large Lists&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Rendering all items at once is expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;ListView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;itemCount:&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;itemBuilder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lazy loading&lt;/li&gt;
&lt;li&gt;Better memory usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 &lt;strong&gt;6. Avoid Heavy Work in build() Method&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
build() runs frequently — keep it lightweight.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Bad:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// expensive&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Good:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎞️ &lt;strong&gt;7. Use RepaintBoundary to Reduce Repaints&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Prevents unnecessary repainting of UI parts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;RepaintBoundary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;YourWidget&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Case:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex UI&lt;/li&gt;
&lt;li&gt;Animations&lt;/li&gt;
&lt;li&gt;Charts
⏳ &lt;strong&gt;8. Optimize Animations&lt;/strong&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;
Poor animations = dropped frames.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tips:&lt;/strong&gt;&lt;br&gt;
Use AnimatedContainer instead of manual animation&lt;br&gt;
Avoid rebuilding parent widgets during animation&lt;br&gt;
&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;AnimatedContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;duration:&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;milliseconds:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="n"&gt;isExpanded&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 &lt;strong&gt;9. Reduce Widget Tree Depth&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Deep widget trees increase layout calculation time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt;&lt;br&gt;
Avoid unnecessary nesting&lt;br&gt;
Use helper widgets&lt;br&gt;
❌ &lt;strong&gt;Bad:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Good:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧪 &lt;strong&gt;10. Use Flutter DevTools for Profiling&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
You can’t fix what you can’t measure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance tab&lt;/li&gt;
&lt;li&gt;Memory tab&lt;/li&gt;
&lt;li&gt;Widget rebuild stats
&lt;strong&gt;Command:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter run &lt;span class="nt"&gt;--profile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to check:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frame rendering time (16ms target)&lt;/li&gt;
&lt;li&gt;Jank (frame drops)&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🏁 &lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Optimizing Flutter performance isn’t about one magic trick — it’s about small, consistent improvements across your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use const and avoid unnecessary rebuilds&lt;/li&gt;
&lt;li&gt;Optimize images and lists&lt;/li&gt;
&lt;li&gt;Keep build() clean&lt;/li&gt;
&lt;li&gt;Use proper state management&lt;/li&gt;
&lt;li&gt;Measure performance using DevTools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you apply even &lt;strong&gt;5–6 of these tips&lt;/strong&gt;, you’ll already notice a huge improvement in your app’s speed and smoothness.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 FF Designer: AI-Powered UI Generation for FlutterFlow Builders</title>
      <dc:creator>Codexlancers</dc:creator>
      <pubDate>Wed, 06 May 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/codexlancers/ff-designer-ai-powered-ui-generation-for-flutterflow-builders-3me1</link>
      <guid>https://dev.to/codexlancers/ff-designer-ai-powered-ui-generation-for-flutterflow-builders-3me1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6noi0azvdjyayvgnzmc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6noi0azvdjyayvgnzmc3.png" alt=" " width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
💡 &lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
If you’re building apps with &lt;strong&gt;FlutterFlow&lt;/strong&gt;, there’s an exciting new tool you should definitely explore —** FF Designer**.&lt;/p&gt;

&lt;p&gt;It’s an AI-powered design tool that can generate &lt;strong&gt;high-quality app screens in seconds,&lt;/strong&gt; while still giving you full control to edit and customize everything.&lt;/p&gt;

&lt;p&gt;In this article, let’s take a quick look at what FF Designer offers and why it’s a game-changer for developers and designers.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;What is FF Designer?&lt;/strong&gt;&lt;br&gt;
FF Designer is a newly launched tool by FlutterFlow that uses &lt;strong&gt;AI to generate UI screens from natural language prompts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of manually designing every screen, you can simply describe what you want — and the tool creates a ready-to-use UI instantly.&lt;/p&gt;

&lt;p&gt;👉 Think of it as combining &lt;strong&gt;design + AI + FlutterFlow&lt;/strong&gt; workflow into one powerful experience.&lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Key Features&lt;/strong&gt;&lt;br&gt;
🧠 &lt;strong&gt;AI-Powered UI Generation&lt;/strong&gt;&lt;br&gt;
Create complete app screens using simple prompts like:&lt;/p&gt;

&lt;p&gt;“Create a fitness dashboard with stats and progress charts”&lt;/p&gt;

&lt;p&gt;Within seconds, FF Designer generates a structured, visually appealing layout.&lt;/p&gt;

&lt;p&gt;🎨 &lt;strong&gt;Visual Editing (Like FlutterFlow)&lt;/strong&gt;&lt;br&gt;
You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modify components visually&lt;/li&gt;
&lt;li&gt;Adjust layouts, colors, and spacing&lt;/li&gt;
&lt;li&gt;Customize elements just like you would in FlutterFlow
No learning curve — it feels familiar and intuitive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;Easy Integration with FlutterFlow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import generated designs directly into your FlutterFlow project&lt;/li&gt;
&lt;li&gt;Export assets for other workflows
This makes it easy to move from idea → design → development seamlessly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 &lt;strong&gt;Why This Matters&lt;/strong&gt;&lt;br&gt;
This launch reflects a bigger shift:&lt;br&gt;
👉 AI is no longer just experimental — it’s becoming a practical productivity tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfzwsqnncu33ickhno3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfzwsqnncu33ickhno3q.png" alt=" " width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With FF Designer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Designers can prototype faster&lt;/li&gt;
&lt;li&gt;🧑‍💻 Developers can skip repetitive UI work&lt;/li&gt;
&lt;li&gt;🚀 Teams can move from idea to execution much quicker
🧪 &lt;strong&gt;Inspired by Dreamflow&lt;/strong&gt;
FF Designer builds on concepts introduced in Dreamflow, showing how AI can assist in real-world development workflows — not just generate ideas, but actually help build usable UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 &lt;strong&gt;Who Should Use It?&lt;/strong&gt;&lt;br&gt;
FF Designer is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📱 App developers using FlutterFlow&lt;/li&gt;
&lt;li&gt;🎨 UI/UX designers&lt;/li&gt;
&lt;li&gt;🚀 Startup founders building MVPs&lt;/li&gt;
&lt;li&gt;🧪 Anyone prototyping ideas quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;Try It Yourself&lt;/strong&gt;&lt;br&gt;
You can explore FF Designer here:&lt;br&gt;
👉 &lt;a href="https://designer.flutterflow.io/" rel="noopener noreferrer"&gt;https://designer.flutterflow.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔚 &lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
FF Designer is a strong step toward the future of app development — where &lt;strong&gt;AI assists creativity instead of replacing it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you’re already using FlutterFlow, this tool can significantly speed up your workflow and help you build better UI faster.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
Low-code is evolving.&lt;br&gt;
AI is accelerating it.&lt;/p&gt;

&lt;p&gt;And tools like FF Designer are bringing both together in a powerful way.&lt;/p&gt;

&lt;h1&gt;
  
  
  FlutterFlow #AI #Mobile Development #UI Design #No Code
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>design</category>
      <category>flutter</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
