{"id":10661,"date":"2024-01-23T13:09:56","date_gmt":"2024-01-23T13:09:56","guid":{"rendered":"https:\/\/www.capitalnumbers.com\/blog\/?p=10661"},"modified":"2025-10-08T10:55:00","modified_gmt":"2025-10-08T10:55:00","slug":"home-screen-widgets-for-flutter-app","status":"publish","type":"post","link":"https:\/\/www.capitalnumbers.com\/blog\/home-screen-widgets-for-flutter-app\/","title":{"rendered":"How to Create and Add Home Screen Widgets in a Flutter Mobile Application"},"content":{"rendered":"\n<p>In the dynamic world of mobile app development, creating a personalized and engaging user experience is crucial. Flutter, a framework by Google for building beautiful, natively compiled, multi-platform applications from a single codebase, has gained immense popularity for its flexibility and ease of use. If you want to improve the user\u2019s engagement with your Flutter mobile app, one of the options is to provide the home screen widget of your app, and the <a href=\"https:\/\/pub.dev\/packages\/home_widget\" target=\"_blank\" rel=\"nofollow noopener\">home_widget<\/a> package from pub.dev can be a game-changer for this purpose.<\/p>\n<h2 class=\"h2-mod-before-ul\">What is home_widget Package?<\/h2>\n<p>HomeWidget is a package that makes creating HomeScreen Widgets easier on Android and iOS. HomeWidget does not allow writing Widgets with Flutter itself. <b>It still requires writing the Widgets with native code<\/b>. However, it provides a unified interface for sending data, retrieving data, and updating the Widgets. This package lets you easily create and update live widgets on the user&#8217;s home screen, providing a more personalized and interactive experience.<\/p>\n<h2 class=\"h2-mod-before-ul\">Getting Started<\/h2>\n<p>Create a new Flutter project and replace the `main.dart` file with the below code &#8211; <\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>import 'package:flutter\/material.dart';\nvoid main() {\n runApp(const MyApp());\n}\n\n\nclass MyApp extends StatelessWidget {\n const MyApp({super.key});\n\n\n @override\n Widget build(BuildContext context) {\n   return MaterialApp(\n     title: 'Flutter Demo',\n     theme: ThemeData(\n       colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),\n       useMaterial3: true,\n     ),\n     home: const MyHomePage(title: 'Flutter Demo Home Page'),\n   );\n }\n}\n\n\nclass MyHomePage extends StatefulWidget {\n const MyHomePage({super.key, required this.title});\n final String title;\n\n\n @override\n State createState() =&gt; _MyHomePageState();\n}\n\n\nclass _MyHomePageState extends State {\n List todo = ['TODO 1', 'TODO 2'];\n final TextEditingController taskNameController = TextEditingController();\n\n\n addTodo() {\n   showDialog(\n     context: context,\n     builder: (BuildContext context) {\n       return AlertDialog(\n         content: StatefulBuilder(\n           builder: (context, setState) {\n             return SizedBox(\n               height: 200,\n               child: Column(\n                 children: [\n                   const Text('Add new todo', style: TextStyle(fontSize: 22)),\n                   const SizedBox(height: 24),\n                   TextFormField(\n                     maxLines: 3,\n                     controller: taskNameController,\n                     style: const TextStyle(fontSize: 14),\n                     decoration: InputDecoration(\n                       contentPadding: const EdgeInsets.all(20),\n                       hintText: 'Task',\n                       border: OutlineInputBorder(\n                         borderRadius: BorderRadius.circular(15),\n                       ),\n                     ),\n                   ),\n                 ],\n               ),\n             );\n           },\n         ),\n         actions: [\n           ElevatedButton(\n             onPressed: () =&gt; Navigator.of(context, rootNavigator: true).pop(),\n             child: const Text('Cancel'),\n           ),\n           ElevatedButton(\n             onPressed: () {\n               if (taskNameController.value.text.isNotEmpty) {\n                 setState(() {\n                   todo.add(taskNameController.value.text);\n                   taskNameController.clear();\n                 });\n               }\n               Navigator.of(context, rootNavigator: true).pop();\n             },\n             child: const Text('Save'),\n           ),\n         ],\n       );\n     },\n   );\n }\n\n\n @override\n Widget build(BuildContext context) {\n   final ColorScheme colorScheme = Theme.of(context).colorScheme;\n   final Color oddItemColor = colorScheme.primary.withOpacity(0.05);\n   final Color evenItemColor = colorScheme.primary.withOpacity(0.15);\n\n\n   return Scaffold(\n     appBar: AppBar(\n       backgroundColor: Theme.of(context).colorScheme.inversePrimary,\n       title: Text(widget.title),\n     ),\n     body: ReorderableListView(\n       padding: const EdgeInsets.symmetric(horizontal: 40),\n       children: [\n         for (int index = 0; index &lt; todo.length; index += 1)\n           ListTile(\n             key: Key('$index'),\n             tileColor: (index + 1).isOdd ? oddItemColor : evenItemColor,\n             title: Text(todo[index]),\n             trailing: const Icon(Icons.drag_handle),\n           ),\n       ],\n       onReorder: (int oldIndex, int newIndex) {\n         setState(() {\n           if (oldIndex &lt; newIndex) {\n             newIndex -= 1;\n           }\n           final String item = todo.removeAt(oldIndex);\n           todo.insert(newIndex, item);\n         });\n       },\n     ),\n     floatingActionButton: FloatingActionButton(\n       onPressed: addTodo,\n       tooltip: 'Add Task',\n       child: const Icon(Icons.add),\n     ),\n   );\n }\n}\n<\/code>\n<\/pre>\n<\/div>\n<p>Here, we have created a basic TODO app where you can add todos and reorder them. <\/p>\n<p><img src=\"https:\/\/www.capitalnumbers.com\/blog\/wp-content\/uploads\/2024\/01\/flutter-blog-inner-1.gif\" alt=\"To-Do List Widget\"><\/p>\n<p>Now our objective is to show the first task from this TODO List in the widget on the Home screen of the device. For that, we need to perform the following steps:<\/p>\n<ol>\n<li>We will create a basic home screen widget for iOS and Android using Xcode and Android Studio, respectively.<\/li>\n<li>We will write dart code to update the content for the widget using the home_widget package.<\/li>\n<li>Adding native iOS functionality to show updated content.<\/li>\n<li>Adding native Android functionality to show updated content.<\/li>\n<\/ol>\n<h2 class=\"h2-mod-before-ul\">Creating a basic iOS Home Screen widget<\/h2>\n<ol>\n<li>To add a Home Screen widget in iOS, open the project in Xcode.<\/li>\n<li>Select <b>File \u2192 New \u2192 Target<\/b> from the menu. This adds a new target to the project.<\/li>\n<li>A list of templates appears. Select <b>Widget Extension<\/b>.<\/li>\n<li>Type <b>&#8220;SimpleTodoWidget&#8221;<\/b> into the Product Name box for this widget. <b>Clear<\/b> both the <b>Include Live Activity<\/b> and <b>Include Configuration Intent<\/b> check boxes and Activate.<\/li>\n<li>Xcode creates and updates several files. We will work on the relevant files later.<\/li>\n<\/ol>\n<div style=\"padding-left: 2rem\">\n<p><strong>Update your bundle identifier<\/strong><\/p>\n<p>In Xcode, navigate to the settings for your target. In the Signing &amp; Capabilities tab, check that your team and bundle identifier are set.<\/p>\n<p>Add the App Group to both the <b>Runner<\/b> target and the <b>SimpleTodoWidgetExtention<\/b> target in Xcode:<\/p>\n<p><b>Select + Capability -&gt; App Groups<\/b> and add a new <b>App Group<\/b>. Repeat for both the <b>Runner<\/b> (parent app) target and <b>the widget<\/b> target.<\/p>\n<\/div>\n<h2 class=\"h2-mod-before-ul\">Creating a basic Android Home Screen Widget<\/h2>\n<ol>\n<li>To add a Home Screen widget in Android, open the project&#8217; in Android Studio. <\/li>\n<li>After the project builds, locate the app directory in the top-left corner. Add your new Home Screen widget to this directory. Right click the directory, select <b>New -&gt; Widget -&gt; App Widget<\/b>.<\/li>\n<li>\nAndroid Studio displays a new form. Add basic information about your Home Screen widget including its class name, placement, size, and source language\n<ul style=\"list-style-type: circle !important\">\n<li>Class Name box to <b>SimpleTodoWidget<\/b><\/li>\n<li>Minimum Width (cells) dropdown to 3<\/li>\n<li>Minimum Height (cells) dropdown to 3<\/li>\n<\/ul>\n<\/li>\n<li>Android Studio creates and updates several files. We will work on the relevant files later.<\/li>\n<\/ol>\t\n<h2 class=\"h2-mod-before-ul\">Adding the Dart Code<\/h2>\n<p>Now, we have the basic widgets created in Android and iOS. Please run and test them. We will now write dart code to update the content for the widget using the home_widget package.<\/p>\n<p>To begin using the <b>`home_widget`<\/b> package, include it in your project&#8217;s dependencies. Open your pubspec.yaml file and add the following line:<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>dependencies:\n home_widget: ^0.4.1<\/code>\n<\/pre>\n<\/div>\n<p>After adding the dependency, run <b>flutter pub get<\/b> to fetch the package.<\/p>\n<p>Update the <b>`main.dart`<\/b> file with the following code &#8211; <\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>import 'package:flutter\/material.dart';\n\n\n\/\/ ADDED\nimport 'package:home_widget\/home_widget.dart';\n\n\nvoid main() {\n runApp(const MyApp());\n}\n\n\nclass MyApp extends StatelessWidget {\n const MyApp({super.key});\n\n\n @override\n Widget build(BuildContext context) {\n   return MaterialApp(\n     title: 'Flutter Demo',\n     theme: ThemeData(\n       colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),\n       useMaterial3: true,\n     ),\n     home: const MyHomePage(title: 'Flutter Demo Home Page'),\n   );\n }\n}\n\n\n\/\/ ADDED\n\/\/ TO DO: Replace with your App Group ID\nconst String appGroupId = '';\nconst String iOSWidgetName = 'SimpleTodoWidget';\nconst String androidWidgetName = 'SimpleTodoWidget';\n\n\nclass MyHomePage extends StatefulWidget {\n const MyHomePage({super.key, required this.title});\n final String title;\n\n\n @override\n State createState() =&gt; _MyHomePageState();\n}\n\n\n\/\/ ADDED\nvoid updateHeadline(String todo) {\n HomeWidget.saveWidgetData('todo', todo);\n HomeWidget.updateWidget(\n   iOSName: iOSWidgetName,\n   androidName: androidWidgetName,\n );\n}\n\n\nclass _MyHomePageState extends State {\n List todo = ['TODO 1', 'TODO 2'];\n final TextEditingController taskNameController = TextEditingController();\n\n\n\/\/ ADDED\n @override\n void initState() {\n   super.initState();\n\n\n   \/\/ Set the group ID\n   HomeWidget.setAppGroupId(appGroupId);\n\n\n   final newHeadline =\n       todo.isNotEmpty ? todo.elementAt(0) : 'No task available';\n   updateHeadline(newHeadline);\n }\n\n\n addTodo() {\n   showDialog(\n     context: context,\n     builder: (BuildContext context) {\n       return AlertDialog(\n         content: StatefulBuilder(\n           builder: (context, setState) {\n             return SizedBox(\n               height: 200,\n               child: Column(\n                 children: [\n                   const Text('Add new todo', style: TextStyle(fontSize: 22)),\n                   const SizedBox(height: 24),\n                   TextFormField(\n                     maxLines: 3,\n                     controller: taskNameController,\n                     style: const TextStyle(fontSize: 14),\n                     decoration: InputDecoration(\n                       contentPadding: const EdgeInsets.all(20),\n                       hintText: 'Task',\n                       border: OutlineInputBorder(\n                         borderRadius: BorderRadius.circular(15),\n                       ),\n                     ),\n                   ),\n                 ],\n               ),\n             );\n           },\n         ),\n         actions: [\n           ElevatedButton(\n             onPressed: () =&gt; Navigator.of(context, rootNavigator: true).pop(),\n             child: const Text('Cancel'),\n           ),\n           ElevatedButton(\n             onPressed: () {\n               if (taskNameController.value.text.isNotEmpty) {\n                 setState(() {\n                   todo.add(taskNameController.value.text);\n                   taskNameController.clear();\n                 });\n               }\n               Navigator.of(context, rootNavigator: true).pop();\n             },\n             child: const Text('Save'),\n           ),\n         ],\n       );\n     },\n   );\n }\n\n\n @override\n Widget build(BuildContext context) {\n   final ColorScheme colorScheme = Theme.of(context).colorScheme;\n   final Color oddItemColor = colorScheme.primary.withOpacity(0.05);\n   final Color evenItemColor = colorScheme.primary.withOpacity(0.15);\n\n\n   return Scaffold(\n     appBar: AppBar(\n       backgroundColor: Theme.of(context).colorScheme.inversePrimary,\n       title: Text(widget.title),\n     ),\n     body: ReorderableListView(\n       padding: const EdgeInsets.symmetric(horizontal: 40),\n       children: [\n         for (int index = 0; index &lt; todo.length; index += 1)\n           ListTile(\n             key: Key('$index'),\n             tileColor: (index + 1).isOdd ? oddItemColor : evenItemColor,\n             title: Text(todo[index]),\n             trailing: const Icon(Icons.drag_handle),\n           ),\n       ],\n       onReorder: (int oldIndex, int newIndex) {\n         setState(() {\n           if (oldIndex &lt; newIndex) {\n             newIndex -= 1;\n           }\n           final String item = todo.removeAt(oldIndex);\n           todo.insert(newIndex, item);\n\n\n           \/\/ ADDED\n           if (newIndex == 0) {\n             updateHeadline(item);\n           }\n         });\n       },\n     ),\n     floatingActionButton: FloatingActionButton(\n       onPressed: addTodo,\n       tooltip: 'Add Task',\n       child: const Icon(Icons.add),\n     ),\n   );\n }\n}<\/code>\n<\/pre>\n<\/div>\n<p><b>Update the iOS code to display the task<\/b><\/p>\n<p>Open the <b>`SimpleTodoWidget.swift`<\/b> file in Xcode:<\/p>\n<p>Replace the <b>SimpleEntry<\/b> struct with the following code:<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>\/\/ The date and any data you want to pass into your app must conform to TimelineEntry\nstruct SimpleEntry: TimelineEntry {\n   let date: Date\n   let task: String\n}<\/code>\n<\/pre>\n<\/div>\n<p>This <b>SimpleEntry<\/b> struct defines the incoming data to pass into the Home Screen widget when updated. The <b>TimelineEntry<\/b> type requires a date parameter<\/p>\n<p>Edit <b>SimpleTodoWidgetEntryView<\/b> to display the Task: <\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>struct SimpleTodoWidgetEntryView : View {\n   var entry: Provider.Entry\n\n\n   var body: some View {\n       Text(entry.task)\n   }\n}<\/code>\n<\/pre>\n<\/div>\n<p>Edit the <b>Provider<\/b> to tell the Home Screen widget when and how to update<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>struct Provider: TimelineProvider {\n   func placeholder(in context: Context) -&gt; SimpleEntry {\n       SimpleEntry(date: Date(), task: \"Placeholder Task\")\n   }\n\n\n   func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -&gt; ()) {\n       let entry: SimpleEntry\n       if context.isPreview{\n           entry = placeholder(in: context)\n       }\n       else{\n           \/\/ Get the data from the user defaults to display\n\/\/            let userDefaults = UserDefaults(suiteName: )\n           let userDefaults = UserDefaults(suiteName: \"group.todowidget\")\n           let task = userDefaults?.string(forKey: \"todo\") ?? \"No task available\"\n           entry = SimpleEntry(date: Date(), task: task)\n         }\n       completion(entry)\n   }\n\n\n   \/\/    getTimeline is called for the current and optionally future times to update the widget\n   func getTimeline(in context: Context, completion: @escaping (Timeline) -&gt; ()) {\n       \/\/This just uses the snapshot function you defined earlier\n       getSnapshot(in: context) { (entry) in\n           let timeline = Timeline(entries: [entry], policy: .atEnd)\n           completion(timeline)\n       }\n   }\n}<\/code>\n<\/pre>\n<\/div>\n<p>Comment out the SimpleTodoWidget_Previews<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>\/\/struct SimpleTodoWidget_Previews: PreviewProvider {\n\/\/    static var previews: some View {\n\/\/        SimpleTodoWidgetEntryView(entry: SimpleEntry(date: Date()))\n\/\/            .previewContext(WidgetPreviewContext(family: .systemSmall))\n\/\/    }\n\/\/}<\/code>\n<\/pre>\n<\/div>\n<p>Save all files and re-run the app and widget target. You can now see the First Task of the TODO list of your Flutter app in the widget on the Home Screen.<\/p>\n<p class=\"read-also\"><strong>You May Also Read: <\/strong> <a href=\"https:\/\/www.capitalnumbers.com\/blog\/flutter-ui-design-best-practices\/\">Flutter UI Design: Best Practices &amp; Pro Tips for Beautiful Apps<\/a><\/p>\n<h2 class=\"h2-mod-before-ul\">Update the Android code to display the task<\/h2>\n<p>Open the <b>res\/layout\/simple_todo_widget.xml file<\/b>. It defines the structure and layout of your home screen widget. Select Code in the top right-hand corner and replace the contents of that file with the following code:<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>&lt;RelativeLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\n   style=\"@style\/Widget.Android.AppWidget.Container\"\n   android:layout_width=\"wrap_content\"\n   android:layout_height=\"match_parent\"\n   android:background=\"@android:color\/white\"\n   android:theme=\"@style\/Theme.Android.AppWidgetContainer\"&gt;\n\n\n   &lt;TextView\n       android:id=\"@+id\/appwidget_text\"\n       style=\"@style\/Widget.Android.AppWidget.InnerView\"\n       android:layout_width=\"wrap_content\"\n       android:layout_height=\"wrap_content\"\n       android:layout_centerHorizontal=\"true\"\n       android:layout_centerVertical=\"true\"\n       android:layout_margin=\"8dp\"\n       android:background=\"@android:color\/white\"\n       android:text=\"Placeholder Task\"\n       android:textSize=\"24sp\"\n       android:textStyle=\"bold|italic\" \/&gt;\n&lt;\/RelativeLayout&gt;<\/code>\n<\/pre>\n<\/div>\n<p>This XML defines one text view to display the Task. We need to open the <b>`SimpleTodoWidget.kt`<\/b> file to update its functionality. In this file, we need to modify the onUpdate method. Android calls this method for widgets at fixed intervals. The home_widget package tells Android to call onUpdate whenever we call updateWidget in the dart code. Replace the <b>onUpdate<\/b> method with the below code &#8211; <\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {\n   \/\/ There may be multiple widgets active, so update all of them\n   for (appWidgetId in appWidgetIds) {\n       \/\/ Get reference to SharedPreferences\n       val widgetData = HomeWidgetPlugin.getData(context)\n       val views = RemoteViews(context.packageName, R.layout.simple_todo_widget).apply {\n\n\n           val title = widgetData.getString(\"todo\", null)\n           setTextViewText(R.id.appwidget_text, title ?: \"No task available\")\n       }\n\n\n       appWidgetManager.updateAppWidget(appWidgetId, views)\n   }\n}<\/code>\n<\/pre>\n<\/div>\n<p>And make sure to add the below import in the imports section<\/p>\n<div class=\"code-block\">\n<pre style=\"display: flex;align-items: flex-start;justify-content: flex-start\"><code>import es.antonborri.home_widget.HomeWidgetPlugin<\/code>\n<\/pre>\n<\/div>\n<p>Save all files and re-run the app and widget target. You can now see the First Task of the TODO list of your Flutter app in the widget on the Home Screen.<\/p>\n<p>\n<\/p><div class=\"row\">\n<div class=\"col-lg-6 col-md-12\">\n<img src=\"https:\/\/www.capitalnumbers.com\/blog\/wp-content\/uploads\/2024\/01\/flutter-blog-inner-2.gif\" alt=\"To-Do List Widget On The Home Page\">\n<\/div>\n<div class=\"col-lg-6 col-md-12\">\n<img src=\"https:\/\/www.capitalnumbers.com\/blog\/wp-content\/uploads\/2024\/01\/flutter-blog-inner-3.gif\" alt=\"iOS Home Screen To-Do List Widget\">\n<\/div>\n<\/div>\n<p><\/p>\n<p class=\"read-also\"><strong>You may also read: <\/strong> <a href=\"https:\/\/www.capitalnumbers.com\/blog\/beacon-technology-mobile-app-development\/\">Beacon Technology \u2013 A Game Changer for Mobile App Development<\/a><\/p>\n<h2 class=\"h2-mod-before-ul\">Conclusion<\/h2>\n<p>The home_widget package in Flutter is a powerful tool in the realm of <a href=\"https:\/\/www.capitalnumbers.com\/mobile-app.php\">custom mobile app development<\/a>. It empowers developers to manage home screen widgets, thereby offering a more personalized and interactive user experience. By integrating this package into your Flutter app, you can easily build and update widgets on the user&#8217;s home screen, enhancing overall engagement. Experiment with the provided examples, and start creating a more dynamic home screen experience for your users today! For a more in-depth exploration, you can access the <a href=\"https:\/\/github.com\/vinaythakurcn\/flutter-simple-widget\" target=\"_blank\" rel=\"nofollow noopener\">source code here<\/a>.<\/p>\n<p>Seeking expert <a href=\"https:\/\/www.capitalnumbers.com\/flutter-development.php\">Flutter development services<\/a>? Your search ends here! Our team, composed of highly skilled and experienced developers, is dedicated to delivering top-notch, custom-tailored solutions for your needs. Interested in exploring how we can help with your project? <a href=\"https:\/\/www.capitalnumbers.com\/contact-us.php\">Book a call<\/a> with us today to get started!<\/p>\n<div class=\"o-sample-author\">\n<div class=\"sample-author-img-wrapper\">\n<div class=\"sample-author-img\"><img src=\"https:\/\/www.capitalnumbers.com\/blog\/wp-content\/uploads\/2024\/01\/Vinay-removebg-preview-1.jpg\" alt=\"Vinay Thakur\"><\/div>\n<p><a class=\"profile-linkedin-icon\" href=\"https:\/\/www.linkedin.com\/in\/vinay-thakur\/\" target=\"_blank\" rel=\"nofollow noopener\"><img src=\"https:\/\/www.capitalnumbers.com\/blog\/wp-content\/uploads\/2023\/09\/317750_linkedin_icon.png\" alt=\"Linkedin\"><\/a><\/p>\n<\/div>\n<div class=\"sample-author-details\">\n<h4>Vinay Thakur<span class=\"single-designation\"><i>, <\/i>Tech Lead<\/span><\/h4>\n<p>Vinay is a seasoned Full-Stack developer specializing in cross-platform development. With extensive expertise in technologies like Angular, React, and Node.js, and versatile frameworks including Flutter, React Native, and Ionic, he excels in collaborating closely with clients. Vinay is dedicated to delivering efficient, scalable, and user-centric solutions that address real-world challenges.<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In the dynamic world of mobile app development, creating a personalized and engaging user experience is crucial. Flutter, a framework by Google for building beautiful, natively compiled, multi-platform applications from a single codebase, has gained immense popularity for its flexibility and ease of use. If you want to improve the user\u2019s engagement with your Flutter &#8230;<\/p>\n","protected":false},"author":32,"featured_media":10662,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false},"categories":[728],"tags":[],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/posts\/10661"}],"collection":[{"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/users\/32"}],"replies":[{"embeddable":true,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/comments?post=10661"}],"version-history":[{"count":17,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/posts\/10661\/revisions"}],"predecessor-version":[{"id":17158,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/posts\/10661\/revisions\/17158"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/media\/10662"}],"wp:attachment":[{"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/media?parent=10661"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/categories?post=10661"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.capitalnumbers.com\/blog\/wp-json\/wp\/v2\/tags?post=10661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}