<?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>Forem: Ishaq Hassan</title>
    <description>The latest articles on Forem by Ishaq Hassan (@ishaquehassan).</description>
    <link>https://forem.com/ishaquehassan</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%2F813054%2F487ebf49-efc4-4453-8aae-f8a0e07613b4.png</url>
      <title>Forem: Ishaq Hassan</title>
      <link>https://forem.com/ishaquehassan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ishaquehassan"/>
    <language>en</language>
    <item>
      <title>Building Production Flutter Plugins: A 156-Likes pub.dev Case Study</title>
      <dc:creator>Ishaq Hassan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 12:58:48 +0000</pubDate>
      <link>https://forem.com/ishaquehassan/building-production-flutter-plugins-a-156-likes-pubdev-case-study-4e3a</link>
      <guid>https://forem.com/ishaquehassan/building-production-flutter-plugins-a-156-likes-pubdev-case-study-4e3a</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The native code is rarely the hard part of a Flutter plugin. The hard parts are: lifecycle correctness across both iOS and Android, permission flows, async cancellation, supporting users who file half-formed issues, and shipping breaking changes without breaking the world. A successful plugin costs 4 to 8 engineer-weeks before launch and a few hours per month forever after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plugin in numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pub.dev likes&lt;/td&gt;
&lt;td&gt;156&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pub points&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly downloads&lt;/td&gt;
&lt;td&gt;470&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In production&lt;/td&gt;
&lt;td&gt;5+ years&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The plugin in one paragraph
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/document_scanner_flutter" rel="noopener noreferrer"&gt;document_scanner_flutter&lt;/a&gt; is a cross-platform Flutter plugin that lets an app capture a photo of a document, auto-detect the paper edges, perform perspective correction, and return the cropped, rectified image. It uses Apple Vision on iOS and Google ML Kit on Android. Apps using it include KYC flows, expense reporting tools, and field-data collection apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture, layer by layer
&lt;/h2&gt;

&lt;p&gt;A Flutter plugin lives at the edge between the Dart VM and the native platform. There are four layers, and getting any one of them wrong shows up as a 1-star review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Dart-facing API.&lt;/strong&gt; This is what your users see. It must read like a normal Dart package: simple async functions, well-documented parameters, sensible defaults, type-safe results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The platform channel.&lt;/strong&gt; Dart talks to native code through a &lt;code&gt;MethodChannel&lt;/code&gt;. Calls are async, named, and arguments are JSON-encodable. Lesson learned the hard way: name your channel under your domain. Generic names collide with other plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The native bridge.&lt;/strong&gt; On iOS, a Swift &lt;code&gt;FlutterPlugin&lt;/code&gt; class. On Android, a Kotlin &lt;code&gt;FlutterPlugin&lt;/code&gt;. Both must validate arguments, hold no implicit state, handle cancellation, and tear down listeners on detach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The native UI / system call.&lt;/strong&gt; Where 80% of user-reported bugs hide. iPad split-view, Android camera permissions, foldable rotations: all edge cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lifecycle: the silent killer
&lt;/h2&gt;

&lt;p&gt;Flutter plugin lifecycle is the most frequently misunderstood topic. The plugin is attached to a Flutter engine, but the engine can be detached and re-attached when the user backgrounds and foregrounds the app. If your plugin holds an Activity reference (Android) or a UIViewController reference (iOS) past detach, you crash the next time the engine reattaches.&lt;/p&gt;

&lt;p&gt;On Android, implement &lt;code&gt;ActivityAware&lt;/code&gt; and store the Activity reference only between &lt;code&gt;onAttachedToActivity&lt;/code&gt; and &lt;code&gt;onDetachedFromActivity&lt;/code&gt;. On iOS, never hold the Flutter engine UIViewController; resolve it lazily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Federated plugins: when to bother
&lt;/h2&gt;

&lt;p&gt;The federated plugin pattern splits the package into API + platform interface + per-platform implementations. Should you federate from day one? &lt;strong&gt;No.&lt;/strong&gt; Start as a single package with iOS + Android folders. Federate only when you have either a credible second platform (web, desktop) or a co-maintainer for one of the platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pub.dev scoring is deterministic
&lt;/h2&gt;

&lt;p&gt;Pub points reward sound null safety, valid pubspec, OS support declarations, comprehensive README with example, documentation on public API, up-to-date dependencies, and clean static analysis. Likes and downloads are social signals on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verified publisher: a trust multiplier
&lt;/h2&gt;

&lt;p&gt;The shield icon next to my publisher name on pub.dev means the package is published under a verified domain (&lt;code&gt;ishaqhassan.com&lt;/code&gt;). DNS TXT verification, takes 10 minutes, meaningfully shifts trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would build differently in 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Pigeon from day one&lt;/strong&gt; for type-safe platform channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Federate from second platform&lt;/strong&gt;, not from launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native UI in dev mode only&lt;/strong&gt;: ship native-only flow first, Flutter-styled UI only when truly needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot tests for the native bridge&lt;/strong&gt; to catch contract drift early.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The full version with the support burden chapter, the iOS/Android lifecycle deep dive, and the full pub.dev scoring breakdown is on my site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ishaqhassan.dev/blog/building-production-flutter-plugins-case-study.html" rel="noopener noreferrer"&gt;Read the complete article on ishaqhassan.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am a verified pub.dev publisher (&lt;code&gt;ishaqhassan.com&lt;/code&gt;) and Flutter Framework Contributor with 6 merged PRs into flutter/flutter. More writing at &lt;a href="https://ishaqhassan.dev/blog/" rel="noopener noreferrer"&gt;ishaqhassan.dev/blog/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>opensource</category>
      <category>plugin</category>
    </item>
    <item>
      <title>Flutter State Management in 2026: A Decision Guide for Production Apps</title>
      <dc:creator>Ishaq Hassan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 12:58:04 +0000</pubDate>
      <link>https://forem.com/ishaquehassan/flutter-state-management-in-2026-a-decision-guide-for-production-apps-4b36</link>
      <guid>https://forem.com/ishaquehassan/flutter-state-management-in-2026-a-decision-guide-for-production-apps-4b36</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;For widgets that own their state, &lt;strong&gt;&lt;code&gt;setState&lt;/code&gt; is correct&lt;/strong&gt;. For app-wide state in 2026, &lt;strong&gt;Riverpod&lt;/strong&gt; has the best ergonomics. For event-sourced enterprise apps, &lt;strong&gt;Bloc&lt;/strong&gt; still wins. &lt;strong&gt;Provider&lt;/strong&gt; is fine if you already have it. &lt;strong&gt;Signals&lt;/strong&gt; (via signals_flutter, solidart) are the rising option for fine-grained reactivity. Pick by team scale and app boundaries, not by Twitter discourse.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest hierarchy
&lt;/h2&gt;

&lt;p&gt;Every state management decision sits on three axes: &lt;strong&gt;scope&lt;/strong&gt; (one widget, one screen, the whole app), &lt;strong&gt;team scale&lt;/strong&gt; (solo, 5 engineers, 50 engineers), and &lt;strong&gt;auditability&lt;/strong&gt; (do you need a log of every state transition for compliance or replayability). Most state management debates ignore those axes and argue Twitter aesthetics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tier 1: setState
&lt;/h2&gt;

&lt;p&gt;If your state lives inside one widget and is never read by widgets outside, &lt;code&gt;setState&lt;/code&gt; is the right call. It is framework-native, zero dependencies, zero indirection. The reason engineers reach past it too early is that they confuse "state inside the widget" with "state inside the file." Start with setState; lift the moment a sibling widget needs to read a value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tier 2: InheritedWidget
&lt;/h2&gt;

&lt;p&gt;Every state management library is, under the hood, an &lt;code&gt;InheritedWidget&lt;/code&gt; with extra ergonomics. Provider wraps it. Riverpod wraps a smarter version. &lt;code&gt;Theme.of&lt;/code&gt;, &lt;code&gt;MediaQuery.of&lt;/code&gt;, &lt;code&gt;Navigator.of&lt;/code&gt;: all InheritedWidgets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tier 3: Provider (the safe default)
&lt;/h2&gt;

&lt;p&gt;Provider was the official recommendation from 2018 to roughly 2022 and is still in heavy production use. It wraps InheritedWidget into a familiar API: &lt;code&gt;ChangeNotifierProvider&lt;/code&gt;, &lt;code&gt;context.watch&lt;/code&gt;, &lt;code&gt;context.read&lt;/code&gt;, &lt;code&gt;Selector&lt;/code&gt; for fine-grained rebuilds. If you have a Provider codebase, keep it. Migration mid-project rarely pays back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tier 4: Riverpod (the 2026 default for new apps)
&lt;/h2&gt;

&lt;p&gt;Riverpod is what Provider's author wrote when he had a chance to start over. The headline differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compile-time safety&lt;/strong&gt;: a provider that does not exist will not compile. No &lt;code&gt;ProviderNotFoundException&lt;/code&gt; at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code generation&lt;/strong&gt;: &lt;code&gt;@riverpod&lt;/code&gt; annotation produces type-safe providers, eliminating boilerplate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AsyncNotifier&lt;/strong&gt;: first-class support for async state with &lt;code&gt;AsyncValue&lt;/code&gt; (data, loading, error variants).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Family providers&lt;/strong&gt;: parameterized providers (per user ID, per item ID) without manual disposal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-dispose&lt;/strong&gt;: providers can release resources automatically when no widget reads them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tier 5: Bloc (the enterprise pattern)
&lt;/h2&gt;

&lt;p&gt;Bloc separates events (intents) from state (results). UI dispatches events, the Bloc maps events to states, the UI rebuilds on state changes. Where Bloc shines: large teams (10+ engineers per app), strict architectural review, compliance contexts where every state transition must be logged and replayable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tier 6: signals (the rising star)
&lt;/h2&gt;

&lt;p&gt;Signals (in Flutter via packages like &lt;code&gt;signals_flutter&lt;/code&gt; and &lt;code&gt;solidart&lt;/code&gt;) implement the SolidJS / Vue / Svelte approach: a value wrapped in an object that automatically tracks its readers and only rebuilds those readers. No &lt;code&gt;watch&lt;/code&gt;, no &lt;code&gt;ref&lt;/code&gt;, no Provider scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;Recommendation in 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State inside one widget&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setState&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solo dev, new app, &amp;lt; 10 screens&lt;/td&gt;
&lt;td&gt;Riverpod (or signals)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-engineer team, new app&lt;/td&gt;
&lt;td&gt;Riverpod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing Provider codebase&lt;/td&gt;
&lt;td&gt;Stay on Provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20+ engineer team, enterprise&lt;/td&gt;
&lt;td&gt;Bloc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance / audit log needed&lt;/td&gt;
&lt;td&gt;Bloc (or Redux for time travel)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time collab, complex async&lt;/td&gt;
&lt;td&gt;Bloc or custom RxDart streams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The trap to avoid
&lt;/h2&gt;

&lt;p&gt;Do not pick state management based on a Twitter thread. Pick by walking through three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where does this specific piece of state live, and who reads it?&lt;/li&gt;
&lt;li&gt;How many engineers will touch this code in the next year?&lt;/li&gt;
&lt;li&gt;Does anyone outside the engineering team need to audit how this state changed?&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The full version with what changed in 2026 vs 2024 and concrete code patterns for each tier is on my site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ishaqhassan.dev/blog/flutter-state-management-2026-guide.html" rel="noopener noreferrer"&gt;Read the complete article on ishaqhassan.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am a Flutter Framework Contributor with 6 merged PRs into flutter/flutter and Engineering Manager at DigitalHire. More writing at &lt;a href="https://ishaqhassan.dev/blog/" rel="noopener noreferrer"&gt;ishaqhassan.dev/blog/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>statemanagement</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Flutter Three-Tree Architecture Explained: Widgets, Elements, RenderObjects</title>
      <dc:creator>Ishaq Hassan</dc:creator>
      <pubDate>Sat, 25 Apr 2026 12:57:12 +0000</pubDate>
      <link>https://forem.com/ishaquehassan/flutter-three-tree-architecture-explained-widgets-elements-renderobjects-2h28</link>
      <guid>https://forem.com/ishaquehassan/flutter-three-tree-architecture-explained-widgets-elements-renderobjects-2h28</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Flutter renders by maintaining three parallel trees. The &lt;strong&gt;Widget tree&lt;/strong&gt; is immutable configuration, rebuilt on every &lt;code&gt;setState&lt;/code&gt;. The &lt;strong&gt;Element tree&lt;/strong&gt; is the persistent identity layer that decides whether to update or replace. The &lt;strong&gt;RenderObject tree&lt;/strong&gt; is the heavyweight layout, paint, and hit-test machine. Bugs that look like "random state loss" or "ListView jank" almost always live in the Element layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why three trees instead of one
&lt;/h2&gt;

&lt;p&gt;If Flutter rebuilt the entire rendered UI on every state change, no app would hold 60fps. Native frameworks solve this with mutable view objects you imperatively update. React solves it with a virtual DOM diff against a real DOM. Flutter splits the problem into three layers, each with one job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Widgets are immutable build instructions.&lt;/strong&gt; They are cheap to allocate, cheap to throw away, and trivially comparable. When you call &lt;code&gt;setState&lt;/code&gt;, Flutter does not rebuild any pixels. It rebuilds the widget subtree below the StatefulWidget into fresh widget instances. Widgets are fast because they are dumb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elements are the persistent identity layer.&lt;/strong&gt; Every widget gets exactly one Element when first mounted. The Element holds the parent pointer, the state object (for StatefulWidgets), the InheritedWidget dependencies, and a reference to the RenderObject if it has one. Elements survive across &lt;code&gt;setState&lt;/code&gt; calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RenderObjects are the real work.&lt;/strong&gt; Layout, paint, hit-testing, semantics, accessibility tree generation. RenderObjects are expensive to create and expensive to throw away, so the Element layer works hard to keep them around across rebuilds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reconciliation algorithm
&lt;/h2&gt;

&lt;p&gt;When the framework asks an Element to update with a new widget, the algorithm is:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&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;canUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldWidget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newWidget&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newWidget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// reuse this Element + RenderObject&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;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deactivate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;           &lt;span class="c1"&gt;// unmount old subtree&lt;/span&gt;
  &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inflateWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newWidget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// create fresh Element + RenderObject&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;canUpdate&lt;/code&gt; check returns true when the runtimeType &lt;strong&gt;and&lt;/strong&gt; the key are equal. Same type, same key (or both null) means the Element is reused. Anything else means a full mount/unmount cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keys and why they matter more than you think
&lt;/h2&gt;

&lt;p&gt;Keys are the manual override on the reconciliation algorithm. By default, Flutter pairs new widgets to existing Elements &lt;strong&gt;positionally&lt;/strong&gt;. The first child of the new widget tree pairs with the first child Element. If you reorder a list of &lt;code&gt;Card&lt;/code&gt; widgets without keys, every Card looks at its new widget, sees a Card with the same runtimeType and a null key, and updates in place. The visible content moves, but the &lt;em&gt;state&lt;/em&gt; stays at its original position.&lt;/p&gt;

&lt;p&gt;This is the source of the most reported "Flutter is broken" bug: a list of &lt;code&gt;TextField&lt;/code&gt; widgets where the user types in the second row, then the row gets reordered, and the typed text appears in the wrong row. The fix is to give each Card a stable key (like &lt;code&gt;ValueKey(item.id)&lt;/code&gt;) so the framework pairs by identity instead of position.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do with this knowledge
&lt;/h2&gt;

&lt;p&gt;You do not need to memorize the framework source. But you do need a working mental model of which tree is responsible for which behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your &lt;strong&gt;UI looks wrong&lt;/strong&gt; after a rebuild, suspect the Widget tree.&lt;/li&gt;
&lt;li&gt;If your &lt;strong&gt;state vanishes or moves&lt;/strong&gt;, suspect the Element tree.&lt;/li&gt;
&lt;li&gt;If your &lt;strong&gt;frame rate drops&lt;/strong&gt;, suspect the RenderObject tree.&lt;/li&gt;
&lt;li&gt;If &lt;strong&gt;InheritedWidget consumers do not update&lt;/strong&gt;, suspect the Element dependency graph.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The full version with the six-state Element lifecycle, RenderObject layer details, and a real bug case study from a merged Flutter framework PR is on my site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ishaqhassan.dev/blog/flutter-three-tree-architecture-explained.html" rel="noopener noreferrer"&gt;Read the complete article on ishaqhassan.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am a Flutter Framework Contributor with 6 merged PRs into flutter/flutter. More writing at &lt;a href="https://ishaqhassan.dev/blog/" rel="noopener noreferrer"&gt;ishaqhassan.dev/blog/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How a Pakistani Engineer Got 6 Pull Requests Merged Into Flutter's Official Framework</title>
      <dc:creator>Ishaq Hassan</dc:creator>
      <pubDate>Thu, 23 Apr 2026 21:54:53 +0000</pubDate>
      <link>https://forem.com/ishaquehassan/how-a-pakistani-engineer-got-6-pull-requests-merged-into-flutters-official-framework-51po</link>
      <guid>https://forem.com/ishaquehassan/how-a-pakistani-engineer-got-6-pull-requests-merged-into-flutters-official-framework-51po</guid>
      <description>&lt;p&gt;&lt;em&gt;My journey as a Flutter Framework Contributor from Karachi, Pakistan, and why it's a big deal for the Pakistani Flutter community.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;strong&gt;TL;DR&lt;/strong&gt;: I'm Ishaq Hassan, Engineering Manager at DigitalHire, Flutter course instructor on the official Flutter docs, and a Pakistani Flutter developer with &lt;strong&gt;6 Pull Requests merged into the Flutter framework&lt;/strong&gt; (the official repository maintained by Google). This post walks through why framework-level contributions matter, how I landed mine, and a short guide for other Pakistani (and South Asian) developers who want to do the same.&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Live portfolio:&lt;/strong&gt; &lt;a href="https://ishaqhassan.dev" rel="noopener noreferrer"&gt;https://ishaqhassan.dev&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;The Gap Nobody Talks About&lt;/h2&gt;

&lt;p&gt;Pakistan has thousands of Flutter developers now. You'll find Flutter jobs in Karachi, Lahore, Islamabad. You'll find Flutter-based startups, Flutter courses on YouTube, Flutter meetups, Flutter Facebook groups.&lt;/p&gt;

&lt;p&gt;But there's a difference between &lt;strong&gt;using&lt;/strong&gt; a framework and &lt;strong&gt;contributing to it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you open the Flutter repository on GitHub and search the contributor graph for Pakistani engineers with multiple merged PRs, the list is short. Surprisingly short. Most Pakistani engagement with Flutter stops at the app layer, building apps, building plugins, teaching courses. Direct contributions to the framework itself remain rare.&lt;/p&gt;

&lt;p&gt;This article exists partly to normalize it. If you're from Pakistan and you want to contribute to the Flutter framework, &lt;strong&gt;you can&lt;/strong&gt;. Here's how I did it.&lt;/p&gt;




&lt;h2&gt;My 6 Merged Pull Requests&lt;/h2&gt;

&lt;p&gt;As of April 2026, these are the ones that made it in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/184572" rel="noopener noreferrer"&gt;#184572 Fix LicenseRegistry docs to reference NOTICES&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/184569" rel="noopener noreferrer"&gt;#184569 Add disposal guidance to CurvedAnimation and CurveTween docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/184545" rel="noopener noreferrer"&gt;#184545 Add clipBehavior parameter to AnimatedCrossFade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183109" rel="noopener noreferrer"&gt;#183109 Add scrollPadding property to DropdownMenu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183097" rel="noopener noreferrer"&gt;#183097 Fix RouteAware.didPushNext documentation inaccuracy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183081" rel="noopener noreferrer"&gt;#183081 Use double quotes in settings.gradle.kts template&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And 3 currently open in review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183110" rel="noopener noreferrer"&gt;#183110 Suppress browser word-selection in SelectableText on web right-click&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183079" rel="noopener noreferrer"&gt;#183079 Guard auto-scroll against Offset.infinite in ScrollableSelectionContainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/flutter/flutter/pull/183062" rel="noopener noreferrer"&gt;#183062 Reset AppBar _scrolledUnder flag when scroll context changes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;Practical Guide&lt;/h2&gt;

&lt;h3&gt;1. Pick the right kind of first PR&lt;/h3&gt;

&lt;p&gt;Don't try to rewrite the rendering pipeline on day one. The Flutter team, like any major OSS project, accepts small, well-scoped, well-tested PRs from new contributors first. Documentation fixes are underrated. Adding a single missing parameter to a widget is high-impact and low-risk.&lt;/p&gt;

&lt;p&gt;My first merged PR (#183081) literally replaces single quotes with double quotes in a Gradle template. That's the bar. Small. Correct. Tested. Useful.&lt;/p&gt;

&lt;h3&gt;2. Read CONTRIBUTING.md like your life depends on it&lt;/h3&gt;

&lt;p&gt;The Flutter team has strict style guides, commit conventions, and test coverage requirements. If you don't follow them, your PR will sit forever or get closed.&lt;/p&gt;

&lt;h3&gt;3. Find real issues via search, not browsing&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Search Flutter issues for labels: &lt;code&gt;good first issue&lt;/code&gt;, &lt;code&gt;help wanted&lt;/code&gt;, &lt;code&gt;d: api docs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Grep the codebase for &lt;code&gt;TODO&lt;/code&gt; comments near widgets you understand&lt;/li&gt;
&lt;li&gt;Use Flutter yourself, find a paper cut, reproduce it in a test, fix it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;4. Tests are non-negotiable&lt;/h3&gt;

&lt;p&gt;Every PR needs a test. If you're adding a parameter, add a unit test. If you're fixing a bug, add a regression test. No test = no merge.&lt;/p&gt;

&lt;h3&gt;5. Be patient and responsive&lt;/h3&gt;

&lt;p&gt;The Flutter team gets thousands of PRs. Reviews are thorough. My average time from PR open to merge is 2-4 weeks. Always respond to reviewer feedback within 24 hours, that moves you up the priority queue.&lt;/p&gt;




&lt;h2&gt;Why This Matters for Pakistan&lt;/h2&gt;

&lt;p&gt;Open source framework contributions are a career accelerator in a way most people underestimate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Global credibility.&lt;/strong&gt; When I say "Flutter Framework Contributor" on LinkedIn, I don't have to explain what that means. It's objectively verifiable on GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better jobs.&lt;/strong&gt; Senior Flutter roles at international companies care a lot about whether you can work at the framework level, not just app level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community leadership.&lt;/strong&gt; It earns speaking invitations, course opportunities, mentorship requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pakistani representation.&lt;/strong&gt; Every time a Pakistani name appears on a merged Flutter PR, it chips away at the assumption that serious OSS contributions only come from North America or Europe.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;About the Flutter Course in Urdu&lt;/h2&gt;

&lt;p&gt;Separately from the framework work, I teach a 35-video Flutter course in Urdu that is &lt;a href="https://docs.flutter.dev/resources/courses" rel="noopener noreferrer"&gt;officially listed on docs.flutter.dev&lt;/a&gt;. It's free. It covers Dart basics through advanced Flutter (state management, APIs, custom painters, deployment). On YouTube via Tech Idara.&lt;/p&gt;

&lt;p&gt;If you're Urdu-speaking and want to learn Flutter properly, &lt;a href="https://www.youtube.com/playlist?list=PLX97VxArfzkmXeUqUxeKW7XS8oYraH7A5" rel="noopener noreferrer"&gt;here's the playlist&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;Call to Action&lt;/h2&gt;

&lt;p&gt;If you're a Pakistani developer reading this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send your first Flutter framework PR this month. Start with docs. Don't overthink it.&lt;/li&gt;
&lt;li&gt;Ping me on &lt;a href="https://linkedin.com/in/ishaquehassan" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; if you need a review before submitting. Happy to help.&lt;/li&gt;
&lt;li&gt;Share your merged PRs publicly. Representation compounds.&lt;/li&gt;
&lt;/ul&gt;





&lt;h2&gt;Links&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="https://ishaqhassan.dev" rel="noopener noreferrer"&gt;https://ishaqhassan.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter Framework Contributor from Pakistan:&lt;/strong&gt; &lt;a href="https://ishaqhassan.dev/flutter-framework-contributor-pakistan.html" rel="noopener noreferrer"&gt;https://ishaqhassan.dev/flutter-framework-contributor-pakistan.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ishaquehassan" rel="noopener noreferrer"&gt;https://github.com/ishaquehassan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://linkedin.com/in/ishaquehassan" rel="noopener noreferrer"&gt;https://linkedin.com/in/ishaquehassan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter Course in Urdu:&lt;/strong&gt; &lt;a href="https://www.youtube.com/playlist?list=PLX97VxArfzkmXeUqUxeKW7XS8oYraH7A5" rel="noopener noreferrer"&gt;YouTube playlist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email:&lt;/strong&gt; hello@ishaqhassan.dev&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
