<?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: Majid Hajian</title>
    <description>The latest articles on Forem by Majid Hajian (@mhadaily).</description>
    <link>https://forem.com/mhadaily</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%2F121648%2F379f05dc-e141-4713-866a-dd5bed1263eb.jpg</url>
      <title>Forem: Majid Hajian</title>
      <link>https://forem.com/mhadaily</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mhadaily"/>
    <language>en</language>
    <item>
      <title>Announcing Zapp! Build Flutter apps in browser</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Thu, 14 Jul 2022 11:41:22 +0000</pubDate>
      <link>https://forem.com/mhadaily/announcing-zapp-build-flutter-apps-in-browser-2i67</link>
      <guid>https://forem.com/mhadaily/announcing-zapp-build-flutter-apps-in-browser-2i67</guid>
      <description>&lt;p&gt;As a Flutter or Dart developer, having an online IDE environment that allows you to create and share your prototypes as quickly as possible in a browser is important. &lt;/p&gt;

&lt;p&gt;You may wonder why this is even important? Having a sandbox in your browser to develop a Flutter application will open up a lot of windows, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can share code and embed examples in your documentation&lt;/li&gt;
&lt;li&gt;You can rapidly prototype your idea and build an application and share it with your stack holders&lt;/li&gt;
&lt;li&gt;You can reproduce bugs and attach them to your issue when you open it, which will help maintainers to start debugging quickly&lt;/li&gt;
&lt;li&gt;You can learn different packages and save a lot of time setting up an environment; you can even share what you have learned&lt;/li&gt;
&lt;li&gt;You can teach Flutter and Dart without needing to set up any environment, which will speed up.
&lt;/li&gt;
&lt;li&gt;You can even collaborate live together on a project or prototype. &lt;/li&gt;
&lt;li&gt;&amp;amp; perhaps so many other opportunities &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Zapp
&lt;/h2&gt;

&lt;p&gt;We proudly announce Zapp, an in-browser tool that will help you build Flutter and Dart applications in your browser. &lt;/p&gt;

&lt;p&gt;With Zapp, you will enjoy building Flutter apps as you make that in your favorite IDE, especially if you are a VsCode user; You will feel at home.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5SOTysn_evg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let's me introduce to you the most important features of Zapp,&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Pub.dev packages
&lt;/h3&gt;

&lt;p&gt;Add any package that supports the Web platform in Flutter and Dart to your &lt;code&gt;pubspec.yaml&lt;/code&gt; file and download it right into your editor in the browser with Zapp! &lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;h3&gt;
  
  
  IntelliSense
&lt;/h3&gt;

&lt;p&gt;Zapp provides syntax highlighting and autocomplete. Step in and out of your code and find the definitions and documentation! Get code completion, parameter info, quick info, member lists, and more. &lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;h3&gt;
  
  
  Live Preview, Unique URL
&lt;/h3&gt;

&lt;p&gt;Rename your project, get a unique URL that everyone can access, and send it to your community member to preview and load it instantly! &lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;h3&gt;
  
  
  Command Palette
&lt;/h3&gt;

&lt;p&gt;Search, find your command, run it and complete your action in a second! The command palette helps you to find out your favorite activities with ease! &lt;/p&gt;


  
  Your browser does not support the video tag.


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theme:&lt;/strong&gt; Zapp will provide you with dark and light mode as of now, but we have in the roadmap to add "themes" in the editor where you can select what your favorite is. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs:&lt;/strong&gt; You can see logs and output of the Dart analyzer. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging:&lt;/strong&gt; Zapp helps you to debug the application as quickly as possible. You may even have breakpoints and debug your application! &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding:&lt;/strong&gt; You can create a rapid prototype; for example, get a minimal embedded edition of Zapp and add it to your documentation! &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pair programming:&lt;/strong&gt; What if you can jump into one Zapp with your team, community member, or an interviewee to pair a program on a problem and get it fixed together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git features:&lt;/strong&gt; Edit, change, organize and see the difference under your branch management to find out what you have changed. Ready to commit and push to a different branch!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run Tests:&lt;/strong&gt; In Zapp, you can write your tests and run them in your browser. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many more:&lt;/strong&gt; Many more features will be added to Zapp soon, but we would love to hear your feedback and prioritize what the community needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Zapp Public Board
&lt;/h3&gt;

&lt;p&gt;We are building Zapp to help the community. Therefore, we have opened &lt;a href="https://github.com/orgs/invertase/projects/16"&gt;Zapp Public Board&lt;/a&gt;, where you can see all backlogs and even help us prioritize them by giving your vote. &lt;/p&gt;

&lt;h2&gt;
  
  
  Early Access
&lt;/h2&gt;

&lt;p&gt;Zapp is evolving, and we are actively developing. Hence, we now invite you to join &lt;a href="https://invertase.link/rZqR"&gt;Zapp Early Access Program&lt;/a&gt; and help make this product even better for everyone.&lt;br&gt;
Once you navigate to &lt;a href="https://invertase.link/rZqR"&gt;zapp.run&lt;/a&gt;, sign in with your Github account, then wait until your access is given. You'll be notified by email.&lt;/p&gt;

&lt;p&gt;If you found a bug or have a feature in mind that we need to develop, please open an issue on &lt;a href="https://github.com/invertase/zapp.run/issues"&gt;Github Zapp.run repository&lt;/a&gt; and let us know what you are looking for. We appreciate it. &lt;/p&gt;
&lt;h2&gt;
  
  
  Watch our live stream
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/DNJOf7aNkOI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

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

&lt;p&gt;Stay tuned for more updates and exciting news that we will share in the future. Follow us on &lt;a href="https://twitter.com/zapp_run"&gt;Zapp_run Twitter&lt;/a&gt;,  &lt;a href="https://twitter.com/invertaseio"&gt;Invertase Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/invertase"&gt;Invertase Linkedin&lt;/a&gt;, and &lt;a href="https://www.youtube.com/channel/UCmKHYC6esonv-xSYJ9i5F6g"&gt;Invertase Youtube&lt;/a&gt;, and subscribe to our monthly newsletter to always stay up-to-date.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>tooling</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Firestore to BigQuery via Firebase Extensions</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Tue, 24 May 2022 11:35:06 +0000</pubDate>
      <link>https://forem.com/mhadaily/firestore-to-bigquery-via-firebase-extensions-3220</link>
      <guid>https://forem.com/mhadaily/firestore-to-bigquery-via-firebase-extensions-3220</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Welcome to part one of our new series on Firebase Extensions. Here we explore what we can gain from using these features and how to fully optimize usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Firestore?
&lt;/h2&gt;

&lt;p&gt;Firestore is a real-time, highly scalable NoSQL document database. It is most often found on the client-side web and mobile applications.&lt;/p&gt;

&lt;p&gt;Data management within this type of database allows users to be fast-paced and flexible when editing data.&lt;/p&gt;

&lt;p&gt;This provides developers with a flexible approach to storing data as well as easy integration when using one of the language SDKs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why BigQuery?
&lt;/h2&gt;

&lt;p&gt;BigQuery can be considered the opposite of Firestore from a data structured point of view. Using an advanced querying engine, large complex datasets can be found and organized with minimal effort.&lt;/p&gt;

&lt;p&gt;Using a form of SQL(structured-query-language), BigQuery allows data to be queried with minimal time between queries.&lt;/p&gt;

&lt;p&gt;The defined relationships between tables mean data can be formed between multiple&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Data Studio
&lt;/h2&gt;

&lt;p&gt;The final piece of the puzzle. This application allows users to visualize data through a series of tools. &lt;/p&gt;

&lt;p&gt;We have all experienced a time when simply showing data on a screen is simply not enough - charts, diagrams, and other advanced visualizations have provided an easier and more concise way to view and understand complex data.&lt;/p&gt;

&lt;p&gt;As an advanced reporting tool, Google Data Studio is ideal for generating easy-to-present information to any audience. One of the main strengths of this tool is the range of databases that can be connected to import data and this includes BigQuery data!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Firebase Extensions?
&lt;/h2&gt;

&lt;p&gt;Extensions allow well-tested pre-defined functions to be deployed and used in conjunction with the Firebase ecosystem like Auth, Firestore, Cloud Storage, etc.&lt;/p&gt;

&lt;p&gt;Designed to increase productivity, a suite of features is available to improve automation through highly configurable functions.&lt;/p&gt;

&lt;p&gt;Authentication, Database, and Cloud Storage triggers are just some of the functions used to enhance database data.&lt;/p&gt;

&lt;p&gt;The plugins allow custom code to be built on top of Google product-based events, allowing many forms of integration (local or third party) or to even enriching Firestore data.&lt;/p&gt;

&lt;p&gt;You can read more about triggers here:&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/firestore-events"&gt;Cloud Firestore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/database-events"&gt;Realtime Database&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firebase.google.com/docs/functions/rc-events"&gt;Remote Config&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/auth-events"&gt;Authentication&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/analytics-events"&gt;Analytics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/gcp-storage-events"&gt;Cloud Storage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/pubsub-events"&gt;Pub/Sub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://firebase.google.com/docs/functions/test-lab-events"&gt;Test Lab&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together, via the extension
&lt;/h2&gt;

&lt;p&gt;Combining the above technologies would normally require a lot of manual setup and configuration, such as manually creating tables, and views and importing Firestore data.&lt;/p&gt;

&lt;p&gt;The Firestore BigQuery extension does all of the heavy liftings and ensures that data is consistently synchronized between Firestore and BigQuery.&lt;/p&gt;

&lt;p&gt;To get started, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the extension &lt;a href="https://firebase.google.com/products/extensions/firebase-firestore-bigquery-export"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create some data on Firestore&lt;/li&gt;
&lt;li&gt;Query data via big query&lt;/li&gt;
&lt;li&gt;Present your data all fancy in Google Data Studio&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Firestore-BigQuery-Export
&lt;/h2&gt;

&lt;p&gt;Why an extension? Manually importing data to BigQuery can be a tedious task and even more so when data is required to be synchronized in real-time between two databases. This is where the extension comes in!&lt;/p&gt;

&lt;p&gt;Using well-tested and designed cloud functions, the extension utilizes triggers to update specified BigQuery tables with data synced from Firestore!&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic configuration
&lt;/h3&gt;

&lt;p&gt;Configuration options make this easy to choose which data will be copied to BigQuery, with the use of wildcards as a way of choosing your document data, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;chatrooms&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;chatid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/messag&lt;/span&gt;&lt;span class="err"&gt;e
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above configuration will sync all chatroom sub-collections along with the document contained in the message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syncing to Big Query
&lt;/h3&gt;

&lt;p&gt;One aspect to note is that the relevant BigQuery tables are not created on the installation of the extension. Table development is organized when the first record sync is recorded, on Firestore &lt;code&gt;write&lt;/code&gt; the extension by default will create a table and a view specific to the configuration entered when setting up the extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  raw_changelog
&lt;/h3&gt;

&lt;p&gt;The change-log is a standard SQL table that contains all of the updates that have occurred when syncing from Firestore. Following a pre-defined schema this will provide:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;document_id&lt;/strong&gt;: The document id of the synchronized Firestore document upon creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;event_id&lt;/strong&gt;: The id of the document that triggered the update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;operation&lt;/strong&gt;: What type of Firestore CRUD event triggered the update. This can be INSERT, UPDATE, DELETE, or IMPORT.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;document_name&lt;/strong&gt;: This is the Firestore path of the updated document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;data&lt;/strong&gt;: A plain text JSON representation of the Firestore document. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;timestamp&lt;/strong&gt;: The Firestore timestamp at which the event took place.&lt;/p&gt;

&lt;h3&gt;
  
  
  raw_latest
&lt;/h3&gt;

&lt;p&gt;This is a predefined BigQuery View that selects the latest unique changes from the changelog table. &lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Schemas
&lt;/h3&gt;

&lt;p&gt;The raw_latest view provided by the extension provides a basic view of the imported data, however, this does not mean that more advanced views can be created to show the data.&lt;/p&gt;

&lt;p&gt;All Firestore data types are covered in the toolkit which means you can complex data structures.&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;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"favorite_numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"array"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"last_login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"last_location"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"geopoint"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"geo_point"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stringified_map"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&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;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"friends"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"map"&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;span class="p"&gt;]&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;Simply, define a test schema as above and run the following command:&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="nv"&gt;$ &lt;/span&gt;npx @firebaseextensions/fs-bq-schema-views &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;:PROJECT_ID&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;:DATASET_ID&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--table-name-prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;:TABLE_ID&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--schema-files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./test_schema.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An advanced view modeled on your imported data will now exist in BigQuery!&lt;/p&gt;

&lt;h3&gt;
  
  
  Backfilling Data
&lt;/h3&gt;

&lt;p&gt;As mentioned previously, table and view creation occur on the first record change following the installation of the extension.&lt;/p&gt;

&lt;p&gt;So this provides an obvious question, how do I import previously existing data? We have an &lt;a href="https://github.com/firebase/extensions/blob/master/firestore-bigquery-export/guides/IMPORT_EXISTING_DOCUMENTS.md"&gt;import&lt;/a&gt; script for that!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @firebaseextensions/fs-bq-import-collection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to the &lt;code&gt;generate-schema&lt;/code&gt; tool,  this can be run interactively and also in a non-interactive. The following information is required to run an import:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;${PROJECT_ID}&lt;/code&gt;: the ID of the Firebase project in which you installed the extension&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${COLLECTION_PATH}&lt;/code&gt;: the collection path that you specified during extension installation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${COLLECTION_GROUP_QUERY}&lt;/code&gt;: uses a &lt;code&gt;collectionGroup&lt;/code&gt; query if this value is &lt;code&gt;"true"&lt;/code&gt;. For any other value, a &lt;code&gt;collection&lt;/code&gt; query is used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${DATASET_ID}&lt;/code&gt;: the ID that you specified for your dataset during extension installation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For larger datasets, this tool also has a &lt;code&gt;multi-threaded&lt;/code&gt; option to improve performance and memory! Use the &lt;code&gt;-multi-threaded&lt;/code&gt; flag for non-interactive or select to run &lt;code&gt;multiple threads&lt;/code&gt; when prompted interactively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running Multiple Instances
&lt;/h3&gt;

&lt;p&gt;A question that is asked quite often with extensions is how to handle different configurations once an extension has been installed. The answer here is easy, install another instance!&lt;/p&gt;

&lt;p&gt;Firebase extensions will allow more than one instance of an extension to be installed, they will simply create another set of resources and operate under another ID.&lt;/p&gt;

&lt;p&gt;If for example a &lt;code&gt;wildcard&lt;/code&gt; query, does not cover all the required collections, install another extension and point the configuration to the required collections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualizing the results
&lt;/h3&gt;

&lt;p&gt;For this example, we are going to demonstrate, the &lt;code&gt;wildcard&lt;/code&gt; path using the information on countries around the world.&lt;/p&gt;

&lt;p&gt;To begin, with an extension instance will be required with the minimum following configuration:&lt;/p&gt;

&lt;p&gt;Collection path: &lt;code&gt;regions/{regionId}/countries&lt;/code&gt;&lt;br&gt;
Dataset name: &lt;code&gt;regions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Table name: &lt;code&gt;countries&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Wildcards: &lt;code&gt;true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Firestore data can be added using the sample script located &lt;a href="https://github.com/invertase/samples/blob/main/firebase/extensions/firestore-bigquery-export/datasource/addRegionsandCountries.js"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we have data synced from Firestore to BigQuery, we can use reporting tools to provide a clearer view of the information.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;a href="https://datastudio.google.com/reporting/"&gt;https://datastudio.google.com/reporting/&lt;/a&gt; to create a new report.&lt;/p&gt;

&lt;p&gt;(Sign up if prompted.)&lt;/p&gt;

&lt;p&gt;Select BigQuery as your data source and authorize if required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RmWgUcTI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RmWgUcTI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/1.png" alt="Untitled" width="373" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, we are going to use a &lt;code&gt;Custom Query&lt;/code&gt; to allow specific data to appear in our dataset.&lt;/p&gt;

&lt;p&gt;Select:&lt;/p&gt;

&lt;p&gt;CustomQuery ⇒ {Billing ProjectId} and enter the following query...&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="n"&gt;document_id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSON_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"$.population"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Population&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`{my-project-id}.regions.countries_raw_changelog`&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will present the queried dataset that we can now use to visualise the data.&lt;/p&gt;

&lt;p&gt;To include the relevant field, you can customize the columns. In this case, select &lt;code&gt;metric&lt;/code&gt; and choose population:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tqsx8r56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tqsx8r56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/2.png" alt="Untitled" width="176" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the dataset is ready, we can now create a pie chart.&lt;/p&gt;

&lt;p&gt;Choose &lt;code&gt;Add a chart&lt;/code&gt;, select &lt;code&gt;Pie Chart&lt;/code&gt;, and place it onto your editor canvas.&lt;/p&gt;

&lt;p&gt;Finally, repeat the previous steps. Try updating the &lt;code&gt;Metric&lt;/code&gt; data source on the Pie chart to show &lt;code&gt;population&lt;/code&gt; if the chart does not automatically include the correct metric.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SH5ytCqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SH5ytCqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/3.png" alt="Untitled" width="880" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tada! 🎉 &lt;/p&gt;

&lt;p&gt;We can now visualize our Firestore data through BigQuery and DataStudio.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Features
&lt;/h2&gt;

&lt;p&gt;The team behind Firebase Extensions has been hard at work ensuring that the cutting-edge features from BigQuery have now been adopted as part of the extension. From the latest release, you can now take advantage of those features when configuring your extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wildcards
&lt;/h3&gt;

&lt;p&gt;By default, data synchronized from Firestore is stored in a single column called “Data”. This will store all data based on a pre-configured collection path, for example…&lt;/p&gt;

&lt;p&gt;“categories/{category}/products”&lt;/p&gt;

&lt;p&gt;Before this feature, engineers would struggle to associate data in a query without knowing the wildcard path of how the data was synchronized.&lt;/p&gt;

&lt;p&gt;Now you can query with the following:&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;Countries&lt;/span&gt;  &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wildcard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"europe"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let's look at an example.&lt;/p&gt;

&lt;p&gt;As a developer, I have been asked if I can provide a report on countries around the world! I have been provided a handy API for providing the data for my database &lt;a href="https://restcountries.com/#api-endpoints-v3-all"&gt;https://restcountries.com/#api-endpoints-v3-all&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After scanning the API it seems reasonable that the collections and sub-collections would be divided into the following categories.&lt;/p&gt;

&lt;p&gt;Regions (Collection)&lt;/p&gt;

&lt;p&gt;Countries (SubCollection)&lt;/p&gt;

&lt;p&gt;This provides me with the following wildcard path for my BigQuery installation:&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="n"&gt;regions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;regionId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;countries&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed. I can give the new parameters a test! Run the following query to get all countries that are currently in South America.&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="n"&gt;document_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSON_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"$.regionId"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`extensions-testing.countries_example.regions_raw_changelog`&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;JSON_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"$.regionId"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"South America"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8oW51cZ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8oW51cZ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/4.png" alt="Untitled" width="298" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Partitioning
&lt;/h3&gt;

&lt;p&gt;As databases continue to grow, query performance and costs can often be the first to suffer when it comes to querying data. One solution to this is Table partitioning.&lt;/p&gt;

&lt;p&gt;To improve performance BigQuery will divide table content based on the specific column data used in partitioning. Smaller and specific tables will mean faster querying and better results. Additionally, this will reduce costs as less data read will mean less cost-per-read for the owner of the project!&lt;/p&gt;

&lt;p&gt;There are three types of partitioning offered by BigQuery&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time-unit allows a user to partition on three different data types, specifically TIMESTAMP, DATE, and DATETIME.&lt;/li&gt;
&lt;li&gt;Ingestion Time based on the TIMESTAMP value of when the data was created&lt;/li&gt;
&lt;li&gt;Integer Range specifically partitions based on an integer value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The BigQuery Firebase extension will automatically create the column and data type partitioning based on which configuration is used when installing the extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fR2V5BMu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fR2V5BMu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/5.png" alt="Untitled" width="607" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Users can then query data based on the specified partitioning field.&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="nv"&gt;`extensions-testing.20220309_6.20220309_6_raw_changelog`&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"2022-04-18"&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clustering
&lt;/h3&gt;

&lt;p&gt;Clustering is a feature that organizes table data by sorting specified columns and is an ideal solution for reducing the number of reads made on a table through a query. &lt;/p&gt;

&lt;p&gt;When defining clustering, multiple columns can be defined allowing specific ordering of records to minimize the number of unnecessary reads on a query.&lt;/p&gt;

&lt;p&gt;Through the extension, adding clustering is as simple as adding a comma-separated list of the columns you would like to cluster by -  this is then applied to any new table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7dUvwAfD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7dUvwAfD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/firestore-to-bigquery-via-firebase-extensions/6.png" alt="Untitled" width="686" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Big Query will then take care of the rest!&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross Project Support
&lt;/h3&gt;

&lt;p&gt;Previously Firestore and Big Query databases were synchronized based on the Firestore project name. &lt;/p&gt;

&lt;p&gt;The extension now allows support for choosing which Big Query project is used for synchronization.  &lt;/p&gt;

&lt;p&gt;A typical scenario for this would be to install multiple instances of the extension to share the data across multiple (separate) instances without having to support multiple Firestore instances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transform Function
&lt;/h3&gt;

&lt;p&gt;As some data may require additional processing, developers are offered the opportunity to intercept the payload and modify it as needed.&lt;/p&gt;

&lt;p&gt;When data from Firestore has been created or modified, the entire payload is copied to the BigQuery table under the data column in the following format.&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="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;insertId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;document_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;document_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//CREATE, UPDATE, DELETE or IMPORT&lt;/span&gt;
      &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;By providing a custom URL, users can receive the original payload and modify it as required. The returned data from the response is then saved into the BigQuery table.&lt;/p&gt;

&lt;p&gt;You can access example functions provided by Invertase &lt;a href="https://github.com/invertase/samples/blob/main/firebase/extensions/firestore-bigquery-export/cloudfunctions/noShoutingPlz.js"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may follow us on &lt;strong&gt;&lt;a href="https://twitter.com/invertaseio"&gt;Twitter&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://www.linkedin.com/company/invertase"&gt;Linkedin&lt;/a&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;a href="https://www.youtube.com/channel/UCmKHYC6esonv-xSYJ9i5F6g"&gt;Youtube&lt;/a&gt;&lt;/strong&gt; to get our latest updates.&lt;/p&gt;

&lt;p&gt;PS: This post was initially written by &lt;a href="https://twitter.com/dacks_developer"&gt;Darren Ackers&lt;/a&gt;, the lead developer at invertase.io. You may find original content at &lt;a href="https://invertase.link/koCT"&gt;https://invertase.link/koCT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>cloud</category>
      <category>gcp</category>
      <category>google</category>
    </item>
    <item>
      <title>Introducing Extension Events</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Thu, 19 May 2022 09:13:44 +0000</pubDate>
      <link>https://forem.com/mhadaily/introducing-extension-events-16f4</link>
      <guid>https://forem.com/mhadaily/introducing-extension-events-16f4</guid>
      <description>&lt;p&gt;Amongst all of the exciting news at Google IO last week, one, in particular, stood out for us amongst the Firebase community, Extensions events! Here we will discuss what this means for Firebase Extensions while looking at some use cases for better understanding.&lt;/p&gt;

&lt;h1&gt;
  
  
  What are events?
&lt;/h1&gt;

&lt;p&gt;In a nutshell, events are pub-sub events. Built on top of the &lt;a href="https://cloud.google.com/eventarc/docs"&gt;Eventarc&lt;/a&gt;, this allows developers to write decoupled code to listen to a specific pre-defined subscription.&lt;/p&gt;

&lt;p&gt;This update became available in the latest &lt;code&gt;10.2.0&lt;/code&gt; release of the &lt;a href="https://www.npmjs.com/package/firebase-admin/v/10.2.0"&gt;Firebase admin SDK&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Firebase Extensions
&lt;/h1&gt;

&lt;p&gt;Ok, sounds good! So how do I use this with Firebase?&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing an event
&lt;/h2&gt;

&lt;p&gt;Topics are a fundamental part of the pub-sub ecosystem. Like any other implementation, these are also fully customizable in Firebase Extensions.&lt;/p&gt;

&lt;p&gt;In this example, we are going to use the &lt;a href="https://github.com/stripe/stripe-firebase-extensions"&gt;Stripe Payment Extension&lt;/a&gt; updates, which will allow an enhancement of the Stripe Webhook events. In this example, we are going to focus on when a product has been created.&lt;/p&gt;

&lt;p&gt;A new series of topics have been defined in this extension, specifically&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;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.stripe.v1.product.created&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Occurs whenever a product is created.&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.stripe.v1.product.deleted&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Occurs whenever a product is deleted.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Extension configuration
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Events&lt;/code&gt; are the input type, this will allow a customized list of events to be defined.&lt;/p&gt;

&lt;p&gt;To define an individual event topic:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Type&lt;/code&gt; is the topic name to which developers can subscribe, this guide provides an example of how to define a topic name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{provider_id}.{version}.{topic_name}&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ProviderId&lt;/code&gt; (required): Event types must contain a pre-fix of the provider as a unique definition.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Version&lt;/code&gt; (recommended): A unique version number.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TopicName&lt;/code&gt;: A unique relatable name for the event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Description&lt;/code&gt; A free text explanation to easily describe the intention of the event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up a channel
&lt;/h3&gt;

&lt;p&gt;To publish an event, first ensure the Firebase admin SDK is a minimum version of &lt;code&gt;10.2.0&lt;/code&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;"firebase-admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^10.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&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 will provide module access to the &lt;code&gt;eventarc&lt;/code&gt; import:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getEventarc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin/eventarc&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;Next, a channel is required to publish the event. The Admin SDK, will create a series of environmental variables, which will provide supporting arguments for creating a channel.&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;eventChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EVENTARC_CHANNEL&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;getEventarc&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EVENTARC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;allowedEventTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EXT_SELECTED_EVENTS&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;code&gt;EVENTARC_CHANNEL&lt;/code&gt; Contains the fully qualified resource name generated from the extension configuration. This follows a &lt;code&gt;projects/{project}/locations/{location}/channels/{channel-id}&lt;/code&gt; format. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXT_SELECTED_EVENTS&lt;/code&gt; Includes a list of all event topics defined in the extension YAML configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pushing an event
&lt;/h3&gt;

&lt;p&gt;Once a channel has been created, we can now send information to a specified event type.&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;await&lt;/span&gt; &lt;span class="nx"&gt;eventChannel&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`com.stripe.v1.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&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;object&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;Publish is a &lt;code&gt;promise&lt;/code&gt; based function than requires a &lt;code&gt;type&lt;/code&gt; matching a type defined in the extensions YAML configuration.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Data&lt;/code&gt; is the information we want to send as part of the published event, in this case, we will be forwarding the result from the relevant &lt;a href="https://stripe.com/docs/api/webhook_endpoints"&gt;Stripe webhooks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subscribing to an event
&lt;/h2&gt;

&lt;p&gt;So now we have successfully set up the publishing event, we would now like to receive and extend our cloud functions to do something useful with it!&lt;/p&gt;

&lt;p&gt;As part of the original setup, our Stripe extension will have already updated the relevant Firestore and Stripe references.&lt;/p&gt;

&lt;p&gt;In this example, we are going to send a &lt;code&gt;Slack&lt;/code&gt; notification informing us that an event has been completed along with any relevant data!&lt;/p&gt;

&lt;p&gt;Deploy a function using the following &lt;a href="https://github.com/invertase/samples/blob/main/firebase/extensions/events/functions/index.js"&gt;source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once our setup has been completed, simply add a new product in Stripe to receive the following update in Slack...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t4f4ncpq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/slack-message-hook.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t4f4ncpq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://invertase.io/slack-message-hook.png" alt="slack-message-hook" width="475" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What next?
&lt;/h1&gt;

&lt;p&gt;Events in extensions allow unlimited possibilities.  Let us know what you’ve been making or how you feel Events can make developing easier!&lt;/p&gt;

&lt;p&gt;You may follow us on &lt;a href="https://twitter.com/invertaseio"&gt;Twitter&lt;/a&gt;,&lt;a href="https://www.linkedin.com/company/invertase"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://www.youtube.com/channel/UCmKHYC6esonv-xSYJ9i5F6g"&gt;Youtube&lt;/a&gt; or sign-up for our &lt;a href="https://invertase.link/newsletter"&gt;newsletter&lt;/a&gt; to get our latest updates.&lt;/p&gt;

&lt;p&gt;PS: This post was initially written by &lt;a href="https://twitter.com/dacks_developer"&gt;Darren Ackers&lt;/a&gt;, the lead developer at invertase.io. You may find original content &lt;a href="https://invertase.link/4heg"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>flutter</category>
    </item>
    <item>
      <title>Announcing stable FlutterFire Auth for Desktop</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Thu, 12 May 2022 16:27:05 +0000</pubDate>
      <link>https://forem.com/mhadaily/announcing-stable-flutterfire-auth-for-desktop-455o</link>
      <guid>https://forem.com/mhadaily/announcing-stable-flutterfire-auth-for-desktop-455o</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;If you're just coming from this year's IO Flutter keynotes, the Flutter team has announced that Flutter on desktop platforms moved to the stable channel, which includes Linux and MacOS. Windows was announced a couple of months back. Therefore, Flutter developers now have the full power to create great experiences for desktop users, regardless of the operating system! &lt;/p&gt;

&lt;p&gt;With that comes an important question: how much of the Flutter ecosystem is ready for Desktop? We can't tell yet, but we have great news for you. &lt;a href="https://github.com/invertase/flutterfire_desktop" rel="noopener noreferrer"&gt;FlutterFire on Desktop&lt;/a&gt; is making its first big step, and as of today we're excited to announce that our sponsored package &lt;strong&gt;&lt;a href="https://pub.dev/packages/firebase_auth_desktop" rel="noopener noreferrer"&gt;FlutterFire Auth&lt;/a&gt; on Linux and Windows is moving to stable&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;In a previous blog where &lt;a href="https://invertase.io/blog/announcing-flutterfire-desktop" rel="noopener noreferrer"&gt;we announced preview&lt;/a&gt;, we explained the approach followed in developing the packages and the reasoning behind it, so if you're curious, give it a read.&lt;/p&gt;

&lt;p&gt;With Firebase Auth on Linux and Windows, In addition to all user-specifc operations, you get support for the following authentication methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Email and password&lt;/li&gt;
&lt;li&gt;Anonymous (guests)&lt;/li&gt;
&lt;li&gt;Phone number&lt;/li&gt;
&lt;li&gt;OAuth providers including: Google, Facebook, Twitter, and GitHub&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Get started on Linux and Windows
&lt;/h1&gt;

&lt;p&gt;If you're already using Firebase Auth in your Flutter app, you don't need to do much. We built the packages as a platform implementation above the same API of FlutterFire. This means nothing will change for developers, it's already the same API thanks to Flutter's federated plugin system.&lt;/p&gt;

&lt;p&gt;In the root of your Flutter project, run the following command:&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 add firebase_core_desktop 
flutter pub add firebase_auth_desktop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install and add the package into your &lt;code&gt;pubspec.yaml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you're not already using &lt;code&gt;firebase_auth&lt;/code&gt; in your app, you need to add it:&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 add firebase_core
flutter pub add firebase_auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Inside your code, you can import it this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;import &lt;span class="s1"&gt;'package:firebase_auth/firebase_auth.dart'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that we're not importing it as &lt;code&gt;package:firebase_auth_desktop/firebase_auth_desktop.dart&lt;/code&gt;, that's because &lt;code&gt;firebase_auth_desktop&lt;/code&gt; is not a standalone package, it's just a delegate implementation that will be used when you compile your app on Windows or Linux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firebase configurations
&lt;/h2&gt;

&lt;p&gt;If you go to the Firebase console and try to setup an app, you won't find a Linux/Windows option. The configurations you will use with &lt;code&gt;firebase_core_desktop&lt;/code&gt; are web configurations. &lt;/p&gt;

&lt;p&gt;You can manually create a new web app in the console, copy the configurations and paste them into your app. You will need to do a couple of if-statements to return the correct configurations for each platform your app supports.&lt;/p&gt;

&lt;p&gt;There's another option to save you some time and effort. The &lt;a href="https://github.com/invertase/flutterfire_cli" rel="noopener noreferrer"&gt;FlutterFire CLI&lt;/a&gt; latest update &lt;strong&gt;v0.2.2&lt;/strong&gt; added support for Linux and Windows, where the configurations will be generated and added automatically for you if it finds &lt;code&gt;firebase_core_desktop&lt;/code&gt; in your &lt;code&gt;pubspec.yaml&lt;/code&gt; file. Let's see an example!&lt;/p&gt;

&lt;p&gt;First, make sure you update to the latest version of FlutterFire CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dart pub global activate flutterfire_cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the root of your project, run:&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;flutterfire&lt;/span&gt; &lt;span class="n"&gt;configure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will ask you for the platforms which you want to configure Firebase for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? Which platforms should your configuration support &lt;span class="o"&gt;(&lt;/span&gt;use arrow keys &amp;amp; space to &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;? › 
✔ android
✔ ios
✔ macos
✔ web
✔ windows
✔ linux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose your platforms, then hit enter. A new file named &lt;code&gt;firebase_options.dart&lt;/code&gt; will be generated under &lt;code&gt;lib/&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Taking a look inside &lt;code&gt;firebase_options.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;class DefaultFirebaseOptions &lt;span class="o"&gt;{&lt;/span&gt;  
    static FirebaseOptions get currentPlatform &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;kIsWeb&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;web&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
      switch &lt;span class="o"&gt;(&lt;/span&gt;defaultTargetPlatform&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.web:
          &lt;span class="k"&gt;return &lt;/span&gt;web&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.android:
          &lt;span class="k"&gt;return &lt;/span&gt;android&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.iOS:
          &lt;span class="k"&gt;return &lt;/span&gt;ios&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.macOS:
          &lt;span class="k"&gt;return &lt;/span&gt;macos&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.windows:
          &lt;span class="k"&gt;return &lt;/span&gt;windows&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; TargetPlatform.linux:
          &lt;span class="k"&gt;return &lt;/span&gt;linux&lt;span class="p"&gt;;&lt;/span&gt;
        default:
          throw UnsupportedError&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'DefaultFirebaseOptions are not supported for this platform.'&lt;/span&gt;,
          &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="o"&gt;}&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;The last step is to initialize Firebase using the generated options.&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  OAuth authentication
&lt;/h1&gt;

&lt;p&gt;Authenticating users with third-party providers on Firebase is a 2-steps process: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, you use a third-party package or the REST API of some provider to get the required credentials (usually access token). &lt;/li&gt;
&lt;li&gt;Next, you will call signInWithCredentials in the Firebase SDK and pass in the credentials you just got from the provider. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's take Google sign-in as an example, we first need to get an &lt;code&gt;accessToken&lt;/code&gt; and &lt;code&gt;idToken&lt;/code&gt; from Google's API, which should happen in a browser or WebView, then we use the credentials to sign the user in using Firebase. Therefore, your user is authenticated on Firebase with Google as an authentication provider.&lt;/p&gt;

&lt;p&gt;During the development of FlutterFire Desktop, we faced a limitation. All the third-party packages providing OAuth authentication for famous providers (such as Googe, Apple, Facebook ... etc) only supports iOS and Android, some have web. &lt;/p&gt;

&lt;p&gt;As a solution, we released &lt;a href="https://pub.dev/packages/desktop_webview_auth" rel="noopener noreferrer"&gt;&lt;code&gt;desktop_webview_auth&lt;/code&gt;&lt;/a&gt;, which makes use of the native WebView on Linux, Windows and MacOS to authenticate users using Google, Facebook, Twitter and GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's see an example
&lt;/h2&gt;

&lt;p&gt;First, add the required packages:&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 add firebase_core firebase_auth
flutter pub add firebase_core_desktop firebase_auth_desktop
flutter pub add desktop_webview_auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let the user sign in using their preferred social provider using &lt;code&gt;desktop_webview_auth&lt;/code&gt; plugin.&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:desktop_webview_auth/desktop_webview_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:desktop_webview_auth/github.dart'&lt;/span&gt;&lt;span class="o"&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;DesktopWebviewAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;GitHubSignInArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;clientId:&lt;/span&gt; &lt;span class="n"&gt;_githubClientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;clientSecret:&lt;/span&gt; &lt;span class="n"&gt;_githubClientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;redirectUri:&lt;/span&gt; &lt;span class="n"&gt;_redirectUri&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="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="o"&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;accessToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user will see a window popping up to authenticate them with GitHub.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Finvertase-git-flutterfire-desktop-stable-invertase.vercel.app%2Fdesktop_webview_auth_github.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Finvertase-git-flutterfire-desktop-stable-invertase.vercel.app%2Fdesktop_webview_auth_github.gif" alt="desktop_webview_auth_github.gif"&gt;&lt;/a&gt;&lt;br&gt;
There are 2 possible scenarios here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user closes the window without signing in, the will cancel the operation and you will get a null result.&lt;/li&gt;
&lt;li&gt;The user sign in successfully, and we get a &lt;code&gt;accessToken&lt;/code&gt; back, in which case you will go to the next step: authenticating with Firebase.
&lt;/li&gt;
&lt;/ol&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;accessToken&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="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create a new Google credential.&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;GithubAuthProvider&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="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Once signed in, return the UserCredential.&lt;/span&gt;
  &lt;span class="k"&gt;await&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="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="k"&gt;else&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can view the &lt;a href="https://github.com/invertase/samples/tree/main/flutter_samples/flutter_oauth_signin" rel="noopener noreferrer"&gt;full working example on our samples repository.&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What's next for Desktop
&lt;/h1&gt;

&lt;p&gt;Firebase Auth is only the beginning, we have &lt;a href="https://github.com/invertase/flutterfire_desktop/issues/52" rel="noopener noreferrer"&gt;an issue tracking the progress&lt;/a&gt;, we would love to hear your feedback and thoughts!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>firebase</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Please Welcome Flutter 3.0!</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Thu, 12 May 2022 07:45:35 +0000</pubDate>
      <link>https://forem.com/mhadaily/please-welcome-flutter-30-3e37</link>
      <guid>https://forem.com/mhadaily/please-welcome-flutter-30-3e37</guid>
      <description>&lt;p&gt;I can't believe it's time again for another major Flutter stable release. Yes, everybody, please welcome Flutter 3.0. &lt;/p&gt;

&lt;p&gt;Last year in Google I/O, the Flutter team announced &lt;a href="https://medium.com/flutter/announcing-flutter-2-2-at-google-i-o-2021-92f0fcbd7ef9" rel="noopener noreferrer"&gt;Flutter 2.2&lt;/a&gt;. Since then, there have been a few significant improvements and stable releases to Flutter. At &lt;a href="http://invertase.io/" rel="noopener noreferrer"&gt;Invertase&lt;/a&gt;, as an &lt;a href="http://invertase.io/" rel="noopener noreferrer"&gt;open-source company&lt;/a&gt;, we appreciate all the hard work that hundreds of community contributors have done for Flutter, too; kudos, everyone! It shows how great Flutter is performing and how responsive its team is to address critical issues, upgrade Flutter, and take it to the next level. &lt;/p&gt;

&lt;p&gt;This article will summarize what's new in Flutter and Dart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Flutter 3.0
&lt;/h2&gt;

&lt;p&gt;Flutter is primarily designed to be portable and able to create beautiful apps. Flutter developer tooling focus on making our development process fast and productive.&lt;/p&gt;

&lt;p&gt;At Google I/O 2022, Flutter 3.0 was announced! Let’s take a look at what is new to this major version! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F54vt34oczj8fj56mvq07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F54vt34oczj8fj56mvq07.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;macOS &amp;amp; Linux are finally stable!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Windows, Web, Android, and iOS&lt;/strong&gt; have been stable for a while, and finally, we can welcome &lt;strong&gt;macOS&lt;/strong&gt; and &lt;strong&gt;Linux&lt;/strong&gt; to the list of stable support. Flutter 3 is one of the most significant milestones in the journey of Flutter up to today because Flutter 3.0 supports all six platforms on the stable channel officially. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fjc0rg7m4pswb32uu6qkc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fjc0rg7m4pswb32uu6qkc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Improvement on Flutter Web
&lt;/h3&gt;

&lt;p&gt;Flutter web has not received many upgrades in this version. However, there are a few significant enhancements, especially for performance. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App lifecycle API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A new API that provides you full control over the Flutter framework, engine, and content. This lets you run the Flutter in headless mode on the web. An example could be preloading the content while showing a login screen or a progress bar! &lt;/p&gt;

&lt;p&gt;You can see this new change on the &lt;strong&gt;&lt;a href="http://gallery.flutter.dev" rel="noopener noreferrer"&gt;gallery.flutter.dev&lt;/a&gt; (&lt;a href="https://github.com/flutter/gallery/" rel="noopener noreferrer"&gt;source code&lt;/a&gt;),&lt;/strong&gt; where you will see a splash screen that zooms in and loads the entire application. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster image decoding and scrolling&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Flutter 3 for the web comes with a big improvement in image decoding and scrolling, particularly using the Chrome 99+. &lt;/p&gt;

&lt;p&gt;In fact, Flutter is levering the new web-codec API in the browsers to improve decoding images and introduces way better scrolling with a high chance of getting 60 fps while decoding images.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Flutter DevTools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Flutter DevTools is a great addition to Flutter that helps to debug any Flutter app as productive as possible. There are a few updates in Flutter DevTools 2.12.2&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance Tracing under the performance tab&lt;/li&gt;
&lt;li&gt;Improvement on the Network tab&lt;/li&gt;
&lt;li&gt;Dedicated plugin for Provider to keep track of change notifier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2F0i9ngg5zb06wca491fyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F0i9ngg5zb06wca491fyz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Android and iOS updates
&lt;/h3&gt;

&lt;p&gt;Android and iOS were the leading platforms from the very beginning, and in Flutter 3, they have received a few major upgrades. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Foldable device support&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Flutter team and Microsoft have collaborated to bring better support for foldable devices. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Material 3 widgets&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;We all have been waiting for &lt;a href="https://m3.material.io/" rel="noopener noreferrer"&gt;Material 3&lt;/a&gt;, and YES, it has landed on Flutter for Android. This is a massive update on Material widgets, and it enables developers to welcome Material You for their Android applications. &lt;/p&gt;

&lt;p&gt;Material 3 (also known as Material You) is the next generation of Material Design. The significant changes include color system improvements, typography improvements, and updates for many components. &lt;/p&gt;

&lt;p&gt;The Material 3 widgets in Flutter were introduced with features including &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adaptive colors&lt;/li&gt;
&lt;li&gt;New buttons&lt;/li&gt;
&lt;li&gt;New app menu&lt;/li&gt;
&lt;li&gt;Variable font support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ff34h3hkhi4svd70xg6jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff34h3hkhi4svd70xg6jk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you need to do to use Material 3 in Flutter 3.0 is to enable it via a parameter to &lt;code&gt;ThemeData&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;useMaterial3&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="c1"&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;Enhanced platform views&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The platform view support on Android has been re-architected which will make native inline add much smoother. &lt;/p&gt;

&lt;h3&gt;
  
  
  Put Flutter to Work
&lt;/h3&gt;

&lt;p&gt;This project is a demo intended to help people test drive Flutter by integrating it into their existing applications. Included in this repo is a Flutter add-to-app module, which contains the UI and logic for displaying a popup to capture user feedback (a "net promoter score"). Alongside the module are three newsfeed applications for iOS, Android, and web, built with SwiftUI, Kotlin, and Angular, respectively. &lt;a href="https://github.com/flutter/put-flutter-to-work" rel="noopener noreferrer"&gt;Read more here about Put Flutter to Work&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  *&lt;strong&gt;&lt;em&gt;Flutter Casual Games Toolkit&lt;/em&gt;&lt;/strong&gt;*
&lt;/h3&gt;

&lt;p&gt;Flutter is taking advantage of the hardware-accelerated graphics support provided by Flutter and open source game engines like Flame, making it easier for casual game developers to get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6rsu00kmdbv8sbjyrc0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6rsu00kmdbv8sbjyrc0n.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other updates&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance code lints&lt;/li&gt;
&lt;li&gt;Improve desktop accessibility&lt;/li&gt;
&lt;li&gt;Cascading menus&lt;/li&gt;
&lt;li&gt;Desktop system menu support&lt;/li&gt;
&lt;li&gt;Theme Extensions&lt;/li&gt;
&lt;li&gt;The simplified release model for iOS&lt;/li&gt;
&lt;li&gt;CJK desktop support&lt;/li&gt;
&lt;li&gt;Signed executables&lt;/li&gt;
&lt;li&gt;Apple Silicon native binaries (&lt;a href="https://docs.flutter.dev/get-started/install/macos" rel="noopener noreferrer"&gt;read more here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introducing Dart 2.17
&lt;/h2&gt;

&lt;p&gt;Dart 2.17 stable was announced along with Flutter 3.0 with many long-awaited features that developers have been waiting for. Dart is the secret sauce behind Flutter, and any improvements in Dart would help improve Flutter's development. Let’s take a look at the new features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxmppbhmlfp6xiy3n89s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxmppbhmlfp6xiy3n89s0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhanced Enumerations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A massive update has landed for &lt;code&gt;enum&lt;/code&gt; to super-charge them. We use leverage &lt;code&gt;extensions&lt;/code&gt; to extend the functionality of &lt;code&gt;enums&lt;/code&gt; including defining methods. Starting from Dart 2.17, we no longer need to use our older model to work with &lt;code&gt;enum&lt;/code&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;enum&lt;/span&gt; &lt;span class="n"&gt;Cars&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tesla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Model X'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;bmw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'X6'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;porsche&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Tycon'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;price&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;Cars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;);&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;nameAndPrice&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;'&lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$price&lt;/span&gt;&lt;span class="s"&gt;'&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;greeting&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;yourName&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="s"&gt;'My name is &lt;/span&gt;&lt;span class="si"&gt;$yourName&lt;/span&gt;&lt;span class="s"&gt; and I have a &lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s"&gt; that costs &lt;/span&gt;&lt;span class="si"&gt;$price&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="nd"&gt;@override&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;toString&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="s"&gt;'The name is &lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s"&gt; and price is &lt;/span&gt;&lt;span class="si"&gt;$price&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;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="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;Cars&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tesla&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Majid'&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;Cars&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bmw&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;Cars&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;porsche&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;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;Super constructors&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;This is perhaps one of my favorites that will shorthand our coding, in which you may pass constructor arguments to the superclass. &lt;/p&gt;

&lt;p&gt;Let’s explore what the new syntax looks like. We used to have the old syntax like below&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;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Old way: before Dart 2.17&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Dog&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;The new syntax is straightforward&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;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// New way: Dart 2.17 and above&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Dog&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&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;Name args anywhere&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Previously, we had to add name arguments in the last position of the constructor. From Dart 2.17, we no longer need to do that. You can put your named arguments anywhere in the constructor.&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;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Dog&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;bark&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="si"&gt;$age&lt;/span&gt;&lt;span class="s"&gt; year-old and is barking'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;age:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Lucy'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bark&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;
  
  
  &lt;strong&gt;What’s next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I have tried to summarize and give you the best features of Flutter 3.0. However, I recommend watching the keynote and enjoying the excellent presentations and exciting interviews.  &lt;/p&gt;

&lt;p&gt;You can read &lt;a href="https://medium.com/flutter/introducing-flutter-3-5eb69151622f" rel="noopener noreferrer"&gt;Introducing Flutter 3&lt;/a&gt; and &lt;a href="https://medium.com/dartlang/dart-2-17-b216bfc80c5d" rel="noopener noreferrer"&gt;Dart 2.17: Productivity and integration&lt;/a&gt; blogs for more information. &lt;/p&gt;

&lt;p&gt;I am sure that the Flutter continues to surprise us with way more features in the features, and I am hoping that the Flutter community, which is a big part of the Flutter's success, can help enhance the Flutter ecosystem. &lt;/p&gt;

&lt;p&gt;Nonetheless, we at Invertase aim to support the Flutter community in different ways and hope to improve the Dart and Flutter ecosystem. We started filling in the gaps that we have recognized and strive to serve with our open-source mindset and efforts.&lt;/p&gt;

&lt;p&gt;In fact, we have already started doing that with projects such as FlutterFire, Melos, Spec, and more are to come! We have fantastic news and updates for you and the Flutter community in the upcoming weeks. &lt;/p&gt;

&lt;p&gt;You may follow us on &lt;a href="https://twitter.com/invertaseio" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/invertase" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://www.youtube.com/channel/UCmKHYC6esonv-xSYJ9i5F6g" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt; to get our latest updates.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>programming</category>
    </item>
    <item>
      <title>Appreciate your achievements!</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Tue, 07 Sep 2021 07:20:53 +0000</pubDate>
      <link>https://forem.com/mhadaily/appreciate-your-achievements-3h7o</link>
      <guid>https://forem.com/mhadaily/appreciate-your-achievements-3h7o</guid>
      <description>&lt;p&gt;In a blink of an eye, time passes. I had a period in my life where I always thought, what I have is not enough. &lt;/p&gt;

&lt;p&gt;I want more.&lt;/p&gt;

&lt;p&gt;Consequently, I worked harder, longer, and I didn't notice that my precious time of the moment is passing by, and I didn't enjoy it as I must! &lt;/p&gt;

&lt;p&gt;I didn't sleep enough sometimes just because I thought I had to work more to gain more!&lt;/p&gt;

&lt;p&gt;It may happen to you, or probably you have even faced it already. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5bVgAd2k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f290g8mlntkmanx83kpa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5bVgAd2k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f290g8mlntkmanx83kpa.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having so much on your shoulder and feeling pressure for achieving more will result in unhappiness. &lt;/p&gt;

&lt;p&gt;When I was initially introduced to "The Subtle Art of Not Giving a F*CK," I thought, ok, probably this is another cliche in the genre. I started to learn more about it on Goodreads. I learned so much from the book below to address unpleasantness.&lt;/p&gt;

&lt;p&gt;Soon after reading a few reviews, I realized that it's about the time that I had! The book is the one that might help me to become better at handling similar situations and inspiring me to enjoy my life and appreciating what I have.&lt;/p&gt;

&lt;p&gt;I read the book within a short time a few years ago, and about a week ago, I started to listen to the book for the second time.&lt;/p&gt;

&lt;p&gt;I decided this time to note down what I learned from the book and share it with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  More isn't always better
&lt;/h2&gt;

&lt;p&gt;The first listen that I learned!&lt;/p&gt;

&lt;p&gt;You might think, well, who doesn't want more money? Who doesn't want a good car, or a house and so on!&lt;/p&gt;

&lt;p&gt;Well, you are absolutely right. Those are valuable. Sometimes these assets come by sacrificing your time without you notice it.&lt;/p&gt;

&lt;p&gt;Yes, The PRECIOUS time. Let me give you an example of my life.&lt;/p&gt;

&lt;p&gt;Back in 2014-2015, I was trying very hard to earn more money. Thus, I worked harder, day and night, sometime around 16 to 17 hours a day! I had enough money to enjoy my life with my family and be happy, but I chose to be insatiable.&lt;/p&gt;

&lt;p&gt;As a result, I earned more money, but I was not happy! I decided to travel less, spend less time with family and friends, and be more isolated for about two years. You see, I wanted more, but it wasn't better for me because I sacrificed my happiness, the best time of my life that could be with my family and friends, and enjoy every second of it. Those times never return. That's why I really regret it, even though I earned more money and became wealthier.&lt;/p&gt;

&lt;p&gt;There are many of these examples in my life and probably yours.&lt;/p&gt;

&lt;p&gt;The point here is that I could have appreciated what I have and be happier, which could have yielded a better income at the end because I could have been thinking of a better way to earn more! Mental health is a real thing!&lt;/p&gt;

&lt;p&gt;Sometimes, you should stop, think and enjoy what you have and try to find another way.&lt;/p&gt;

&lt;p&gt;If time goes, it never comes back!&lt;/p&gt;

&lt;h2&gt;
  
  
  Take Responsibility
&lt;/h2&gt;

&lt;p&gt;Many of us start to blame others when there is a problem. That's poisonous. I learned that I should be more responsible because this prevents me from thinking better to find a solution to the problem.&lt;/p&gt;

&lt;p&gt;Let me elaborate with an example of my real life.&lt;/p&gt;

&lt;p&gt;In my issue one, when I was talking about the job interview, it was quite easy to blame my family, child, friend, or even work that stopped me from educating myself to win a job!&lt;/p&gt;

&lt;p&gt;What I did, after each failure, I took responsibility instead; I said, this is my problem, I own it, and I have to become better at it! I must find a way to resolve this problem.&lt;/p&gt;

&lt;p&gt;Not even a single time, I blamed anyone or anything for my failure; I learned every single time about the process and tried to level up because I took 100% responsibility for what I did wrong.&lt;/p&gt;

&lt;p&gt;Manson, in the book, says: "With great responsibility comes great power."&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop comparing
&lt;/h2&gt;

&lt;p&gt;Perhaps the most toxic experience is when I compare myself with someone else! In the era of social media, this is even worse!&lt;/p&gt;

&lt;p&gt;It's quite often that I open my Twitter, and I see many of my friends share their amazing works, and unconsciously, my mind tells me that what the F* I am doing then!&lt;/p&gt;

&lt;p&gt;I learned that I have to stop this way of thinking! We are very different. If someone is doing something, that doesn't mean I have to do that same thing! Or I have to follow what they have done! In fact, I should be proud of what I have done so far.&lt;/p&gt;

&lt;p&gt;Let me be honest with you; authenticity is the key! Enjoy what you have achieved. Be proud of yourself! Definitely, be inspired and encouraged but do not blame yourself.&lt;/p&gt;

&lt;p&gt;Manson, in the book, is pointing out The Backwards law which says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pursuit of a positive experience is itself a negative experience &lt;/li&gt;
&lt;li&gt;The acceptance of a negative experience is itself a positive experience. 
Think about it; This is what actually comparing may affect you! The more you think that someone is rich and you have to become rich, the poorer you feel and the more you want to write articles or want more salary, the less you enjoy what you have written or you have earned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn't mean you should not try to go to the next level. But it means you should enjoy what you have, plan properly and execute and stay on your mission path; you will finally reach your goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find your values
&lt;/h2&gt;

&lt;p&gt;When I found what really are my values, I tend to become more comfortable with my life and what I do. I started to enjoy it more. &lt;/p&gt;

&lt;p&gt;It is absolutely worth the time to sit with yourself and find out your real values.&lt;/p&gt;

&lt;p&gt;Manson, in the book, defines Good values and Bad values.&lt;/p&gt;

&lt;p&gt;Good values in his option are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reality-based&lt;/li&gt;
&lt;li&gt;Socially constructive&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Immediate and controllable&lt;br&gt;
Bad values are:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Superstitious&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Socially destructive&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not immediate and controllable&lt;br&gt;
I found the principles great to start with. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, honesty is one of my values. It tends to be a good value because it's something that I have complete control over, and it reflects reality. Others can also benefit from it, even if it's unpleasant.&lt;/p&gt;

&lt;p&gt;Now that I found this value, I will know what I should sacrifice for or give a f* for.&lt;/p&gt;

&lt;p&gt;It's good to have a shortlist to give a f* about rather than everything around us. &lt;/p&gt;

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

&lt;p&gt;"The Subtle Art of Not Giving a F*CK" comes with lots of great examples and advice that perhaps every one of us has faced in our real life!&lt;/p&gt;

&lt;p&gt;This book helped me think a bit differently about narrowing down things that I have to really care about and, consequently, making my life less miserable. I recommend you either listen or read this book.&lt;/p&gt;

&lt;p&gt;That's it for this week.&lt;/p&gt;

&lt;p&gt;I'll be gladly read your feedback and like to hear what you think. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>devjournal</category>
      <category>books</category>
      <category>writing</category>
    </item>
    <item>
      <title>The Art of Failing Job Interviews and Winning a Job! [Personal story]</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Wed, 01 Sep 2021 07:30:44 +0000</pubDate>
      <link>https://forem.com/mhadaily/the-art-of-failing-job-interviews-and-winning-a-job-personal-story-18e1</link>
      <guid>https://forem.com/mhadaily/the-art-of-failing-job-interviews-and-winning-a-job-personal-story-18e1</guid>
      <description>&lt;p&gt;Dear Friends,&lt;/p&gt;

&lt;p&gt;A while ago, I shared my personal experiences on Twitter of when I was applying for jobs around 2015-16. Many folks liked it so I decided to write more in this newsletter.&lt;/p&gt;

&lt;p&gt;Here is the original tweet: &lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6 years ago, I decided to live in Europe! for doing that, I had to apply for jobs. &lt;br&gt;&lt;br&gt;I have had over 50 interviews within 1.5 years, which I was rejected by all of them! It was like every week one rejection letter! &lt;br&gt;&lt;br&gt;I am now in Oslo because of my 51st job interview.&lt;br&gt;&lt;br&gt;read more👇&lt;/p&gt;— Majid Hajian 💙 (&lt;a class="mentioned-user" href="https://dev.to/mhadaily"&gt;@mhadaily&lt;/a&gt;) &lt;a href="https://twitter.com/mhadaily/status/1427990556949557252?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;August 18, 2021&lt;/a&gt;
&lt;/blockquote&gt; 

&lt;p&gt;The story began when I decided to migrate to Europe back in 2015-2016. After living for 4 years in Kuala Lumpur, Malaysia, I thought it’s time for a big change. I had so many friends, most of whom had been offered jobs in Australia, Canada, the USA, and Europe. Meanwhile, I was doing the immigration process for both Australia and New Zealand.&lt;/p&gt;

&lt;p&gt;To be honest, I really wanted to go to Canada, but some things happened, and that dream never came true.&lt;/p&gt;

&lt;p&gt;In late 2015, I started looking for jobs in Europe. I mainly targeted Germany and the Netherlands; however, I had an eye on different western European countries too, such as France, Denmark, Sweden, etc. &lt;/p&gt;

&lt;p&gt;I started by creating a Google sheet to track where I applied for each position, with the details about the job, including how I performed in the interview and a lot more.&lt;/p&gt;

&lt;p&gt;I have created a simple template, and if you would like &lt;a href="https://docs.google.com/spreadsheets/d/1aE-eJyI4q2kzTQIO3IOXPbDos4nB5-Fqi4qywQRBPAo/edit#gid=0" rel="noopener noreferrer"&gt;it downloaded from this link&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;I search many different sources of jobs, but my main sources were Linkedin, Glassdoor, Stackoverflow.&lt;/p&gt;

&lt;p&gt;I always needed visa sponsorship because I had to get a work permit to relocate to the company’s country, which was so challenging for two main reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I held an Iranian passport, and well, it was more difficult for companies to sponsor me.&lt;/li&gt;
&lt;li&gt;Not many companies generally sponsor relocation and work permits as it’s hard to apply for the immigration process. It is sometimes very time-consuming and risky; what if the applicant gets rejected, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But anyway, I didn’t give up. As soon as I could find a job, I immediately applied and added it to my sheet for tracking.&lt;/p&gt;

&lt;p&gt;All in all, for about 1.5 years, I tried and applied to over 100 Jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interviews
&lt;/h2&gt;

&lt;p&gt;Among all the jobs I applied for, I only received responses for about half, inviting me for interviews. Now you can imagine, I had about one interview each week. In reality, it was much like that; I had several interviews in a week and sometimes nothing for a month.&lt;/p&gt;

&lt;p&gt;However, from the very beginning, I told myself that I would go to all of the interviews, and right after each, I would think then write about my strengths and weaknesses (as you see on my sheet)&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;Because I was ready to get rejected, I know that probably to get a job, I have to become way better. I was confident that I am good, but the rejection was part of becoming better. I was not afraid of it. In fact, I knew that part of being successful has so many failures.&lt;/p&gt;

&lt;p&gt;So What did you do with rejections then?&lt;/p&gt;

&lt;p&gt;Well, easy! I started to fill my gaps in terms of personal, technical, and behavioral aspects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let me give one example.
&lt;/h3&gt;

&lt;p&gt;In one of my interviews, I was called to a remote whiteboard for pair programming in the first session. The interviewer started writing code and asked me to complete lines by lines. Guess what? I didn’t have any confidence in doing it. I was stressed to death.&lt;/p&gt;

&lt;p&gt;Imagine in such a stressful situation how you would perform? Probably not well, and I didn’t either. I completely forgot everything! My heartbeat was high enough that I could hear it clearly.&lt;/p&gt;

&lt;p&gt;I was so embarrassed and disappointed. After the meeting, I was down for a few hours, but you know, I couldn’t let that go. I had to improve this skill.&lt;/p&gt;

&lt;p&gt;I wrote everything in my weakness and started to sharpen it. I researched and found videos and blogs and started to write codes without any help from my head, so on and so forth. &lt;/p&gt;

&lt;p&gt;I practiced.&lt;/p&gt;

&lt;p&gt;Since I had an awful experience, in my next interviews, I asked whether they had pair programming (whiteboard style) or not? I actually decided not to attend those interviews because I already knew I was not good at it and would fail.&lt;/p&gt;

&lt;p&gt;But you know, it also was great practice for me, I could see if I have improved or not. So, in any subsequent interviews, I went along much more prepared than previously for at least this skill. At a minimum, I was not as nervous and stressed out as I had been initially. &lt;/p&gt;

&lt;h3&gt;
  
  
  Another example
&lt;/h3&gt;

&lt;p&gt;Lack of technical knowledge was another reason I got rejected in many of the interviews. But, after every single interview, I started to research questions I didn’t answer well or something that they asked, and I didn’t know about it.&lt;/p&gt;

&lt;p&gt;ES6 was so hyped in the JavaScript world in those years, but I was not really familiar with it. Still, interviews helped me understand the most important things in JavaScript ES6. I started learning them one by one until I remember in one of the interviews, I answered all questions and pair programmed with no issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn from mistakes but give yourself room
&lt;/h3&gt;

&lt;p&gt;This is what I did, even though I got rejected in almost 50 interviews over 1.5 years. I didn’t stop applying and learning to fill my mistakes and hone my skills, and in fact, eventually, I got a job!&lt;/p&gt;

&lt;p&gt;Each failure, especially in a technical interview, is a great opportunity to level up your skills. Just embrace it. Learn from your mistakes and be ready for the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not underestimate or overestimate yourself.
&lt;/h3&gt;

&lt;p&gt;The last thing I wanted to tell you was that I got a job from a company and from a country that I didn’t even consider.&lt;br&gt;
For example, the majority of my interviews and jobs were for Germany. I was confident that I could get a job there, which I think I overestimated. In reality, I got a job in Norway! A place where I never thought there might be an opportunity for me.&lt;/p&gt;

&lt;p&gt;Find all possibilities and study them well. I am sure you’ll find a way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last words
&lt;/h2&gt;

&lt;p&gt;These are my closing words which I have learned in my life, the hard way, and I repeat them every day:&lt;/p&gt;


&lt;blockquote&gt;
&lt;p&gt;1- Be consistent&lt;br&gt;2- Be persistent &lt;br&gt;3- Never disappoint&lt;br&gt;4- Think about your ultimate goals &lt;br&gt;5- Never give up&lt;br&gt;6- Success is earned&lt;br&gt;7- Dream big &lt;br&gt;8- Focus&lt;br&gt;9- Do what you love&lt;br&gt;10- Stay humble &lt;br&gt;&lt;br&gt;YOU CAN DO IT&lt;/p&gt;— Majid Hajian 💙 (&lt;a class="mentioned-user" href="https://dev.to/mhadaily"&gt;@mhadaily&lt;/a&gt;) &lt;a href="https://twitter.com/mhadaily/status/1427990562146299908?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;August 18, 2021&lt;/a&gt;
&lt;/blockquote&gt; 

&lt;p&gt;I kept my story short, but if you’d like to know more, please tell me, and I will write it in more detail later.&lt;/p&gt;

&lt;p&gt;This is my first newsletter issue where you can find it here &lt;a href="https://newsletter.majidhajian.com" rel="noopener noreferrer"&gt;https://newsletter.majidhajian.com&lt;/a&gt;, I will be happy to see you subscribed to my newsletter. You can always unsubscribe at any time. &lt;/p&gt;

&lt;p&gt;Meanwhile, enjoy this beautiful lake that I shot. &lt;br&gt;
&lt;a href="https://media.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%2F8ui6091rdulww771n3od.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8ui6091rdulww771n3od.JPG" alt="Norway, Sognsvann"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>career</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Devfest Norway 2020, A free conference with diversity in mind</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Fri, 28 Aug 2020 07:10:20 +0000</pubDate>
      <link>https://forem.com/mhadaily/devfest-norway-2020-a-free-conference-with-diversity-in-mind-47n7</link>
      <guid>https://forem.com/mhadaily/devfest-norway-2020-a-free-conference-with-diversity-in-mind-47n7</guid>
      <description>&lt;p&gt;September, October and November are months with lots of conferences and meetups. It's the best time to not only sharpen your skills but also become a speaker and share your knowledge.&lt;br&gt;
This year, due to the Covid19 situation, the number of online conferences goes up; I guess there's no excuse not to participate in some of our favorite ones!&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;Among all conferences, DevFest is usually a local event from GDG (Google Developers Group), which happens in October with lots of participants. &lt;a href="https://devfest.no/"&gt;Devfest Norway 2020&lt;/a&gt; will be one of them, which is an effort from &lt;a href="https://devfest.no/team/"&gt;the Norwegian GDG and GDG Cloud groups&lt;/a&gt; including GDG Oslo, GDG Cloud Oslo, GDG Bergen, GDG Trondheim, GDG Sørlandet, GDG Stavanger. &lt;/p&gt;

&lt;h2&gt;
  
  
  CFP
&lt;/h2&gt;

&lt;p&gt;Of course, no conferences can become successful without their speakers. Therefore, we are looking for you to submit your excellent talk. &lt;a href="http://bit.ly/devfest-norway-2020-cfp"&gt;Devfest Norway 2020's CFP&lt;/a&gt; is open until 15th September. Please let us know your cool idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diversity
&lt;/h2&gt;

&lt;p&gt;DevFest Norway 2020 is a unique conference this year as not only are we looking for excellent well-known (international) speakers, but we are also striving to create a platform for local, first-time, and underrepresented groups speakers to let them speak. If you are falling into one of these groups, do not be shy and let us know. I am sure you have something to share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Special Help
&lt;/h2&gt;

&lt;p&gt;If you feel you want to speak and you need some help with things like checking your presentation, rehearsing, or relieving your stress, etc, you can contact us at &lt;a href="mailto:contact@devfest.no"&gt;contact@devfest.no&lt;/a&gt;, or you can &lt;a href="https://twitter.com/mhadaily"&gt;directly message me on twitter&lt;/a&gt;. You may find me on &lt;a href="https://majidhajian.com"&gt;majidhajian.com&lt;/a&gt;. I will be more than happy to help if I can enable you to achieve your dreams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics
&lt;/h2&gt;

&lt;p&gt;You may wonder which topics are the focus of DevFest Norway. Generally, DevFest covers a wide range of issues such as Frontend, Backend, ML/AI, Cloud, and Mobile development. This year, we are planning a two-day conference, held at two different times each day. This way we can cover most of these topics, as well as most of the timezones as we go online on October 14th and 15th.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schedule
&lt;/h2&gt;

&lt;p&gt;We have allotted 6 hours for talks over the course of 2 days. On the first day, October 14th, we will run from 12 PM (GMT+2) until 3 PM (GMT+2).On the second day, October 15th, we will run from 9:30 AM (GMT+2) until 12:30 (GMT+2). So, we hope that these times will cover most of the time zones around the world and that you won't miss your favorite talk. &lt;/p&gt;

&lt;h2&gt;
  
  
  Free ticket
&lt;/h2&gt;

&lt;p&gt;DevFest Norway 2020 is free of charge; however, you still need to get your free ticket as we are going to generate badges for you. &lt;a href="http://bit.ly/free-ticket-devfest-no"&gt;To get your free ticket click here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Win one of our prizes
&lt;/h2&gt;

&lt;p&gt;We have a surprise for you! Join us and perhaps win one of our prizes, which we will announce soon!&lt;br&gt;
Last but not least, We hope that we can bring a pleasant experience online for you to sharpen your skills and learn more.&lt;br&gt;
Hope to see you all on the 14th and 15th of October.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://devfest.no/"&gt;https://devfest.no/&lt;/a&gt;&lt;br&gt;
CFP: &lt;a href="http://bit.ly/devfest-norway-2020-cfp"&gt;http://bit.ly/devfest-norway-2020-cfp&lt;/a&gt;&lt;br&gt;
Free ticket: &lt;a href="http://bit.ly/free-ticket-devfest-no"&gt;http://bit.ly/free-ticket-devfest-no&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*Feel free to comment below or DM me if you have any questions or concerns. &lt;/p&gt;

</description>
      <category>devrel</category>
      <category>devlive</category>
      <category>inclusion</category>
      <category>womenintech</category>
    </item>
    <item>
      <title>How to capture errors and send platform-specific information to Sentry in Flutter? </title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Mon, 16 Dec 2019 18:15:09 +0000</pubDate>
      <link>https://forem.com/mhadaily/how-to-capture-errors-and-send-platform-specific-information-to-sentry-in-flutter-4l6m</link>
      <guid>https://forem.com/mhadaily/how-to-capture-errors-and-send-platform-specific-information-to-sentry-in-flutter-4l6m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;If you don't use Sentry, this article still might be helpful. You may replace Sentry with your error tracking service solution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the aspects of developing software is to handle errors and log them properly in order to mitigate them at the right time.&lt;/p&gt;

&lt;p&gt;When we develop for Flutter, indeed, we have several options to capture and log the errors. One of the greatest tools which come with an easy-to-use &lt;a href="https://pub.dev/packages/sentry"&gt;dart package&lt;/a&gt; is Sentry.io. &lt;/p&gt;

&lt;p&gt;It is not always easy to reproduce the errors that occur if there is no extra information about the platform or environment as recreating the exact same situation could be difficult and time-consuming. &lt;/p&gt;

&lt;p&gt;So, in this article, I will share my experience in Flutter with Sentry by generating a custom event with extra platform-specific information for Android and iOS respectively to report to the Sentry.&lt;/p&gt;

&lt;p&gt;So, you will learn: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get a DSN from Sentry&lt;/li&gt;
&lt;li&gt;Import the Sentry package&lt;/li&gt;
&lt;li&gt;Initialize &lt;code&gt;SentryClient&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Generate Event with the platform-specific information&lt;/li&gt;
&lt;li&gt;Detect Debug mode&lt;/li&gt;
&lt;li&gt;Catch and report Dart Errors&lt;/li&gt;
&lt;li&gt;Catch and report Flutter Errors&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  1- Get a DSN from Sentry
&lt;/h2&gt;

&lt;p&gt;I assume you already have a Sentry account or you are considering it. &lt;/p&gt;

&lt;p&gt;To get a DSN, use the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an account with &lt;a href="https://www.sentry.io"&gt;Sentry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Log in to the account.&lt;/li&gt;
&lt;li&gt;Create a new app.&lt;/li&gt;
&lt;li&gt;Copy the DSN.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2- Import the Sentry package
&lt;/h2&gt;

&lt;p&gt;Before you import the dart package to your code, you need to add the library to the &lt;code&gt;pubspec.yaml&lt;/code&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;sentry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.0.0+1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of writing this article, the latest version is &lt;code&gt;^3.0.0+1&lt;/code&gt; but you may upgrade if you read this later. &lt;/p&gt;

&lt;h2&gt;
  
  
  3- Initialize &lt;code&gt;SentryClient&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In your Dart code, &lt;code&gt;import package:sentry/sentry.dart&lt;/code&gt; and create a &lt;code&gt;SentryClient&lt;/code&gt;. for this purpose, I recommend creating a file named &lt;code&gt;sentry_handler.dart&lt;/code&gt; and keep all relevant code in this file, it helps to keep the code organized.&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;/// sentry_handler.dart&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:sentry/sentry.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// replace sentryDSN with your DSN&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;SentryClient&lt;/span&gt; &lt;span class="n"&gt;sentry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SentryClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;dsn:&lt;/span&gt; &lt;span class="n"&gt;sentryDSN&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to capture errors and stack traces, but before that, let's generate an even that contains all of the platform information while reporting the errors. &lt;/p&gt;

&lt;p&gt;If you don't need this step you can simply skip it and instead use &lt;code&gt;captureException&lt;/code&gt; which is default in &lt;a href="https://pub.dev/packages/sentry"&gt;Sentry dart package documentation&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  4- Generate Event with the platform-specific information
&lt;/h2&gt;

&lt;p&gt;Let's create a function named &lt;code&gt;getSentryEvent&lt;/code&gt; where it returns an Event that is required by the &lt;code&gt;capture&lt;/code&gt; method on &lt;code&gt;sentry&lt;/code&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getSentryEnvEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&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;code&gt;Platform&lt;/code&gt; from &lt;code&gt;dart:io&lt;/code&gt; provides information such as the operating system, the hostname of the computer, the value of environment variables, the path to the running program, and so on. You can get the name of the operating system as a string with the &lt;code&gt;operatingSystem&lt;/code&gt; getter. You can also use one of the static boolean getters: &lt;code&gt;isMacOS&lt;/code&gt;, &lt;code&gt;isLinux&lt;/code&gt;, and &lt;code&gt;isWindows&lt;/code&gt;. So, let's leverage this:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getSentryEnvEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isIOS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAndroid&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&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;In order to get device information in Flutter, You can use &lt;a href="https://pub.dev/packages/device_info"&gt;Device Info dart package&lt;/a&gt; to help us getting device information with ease! Simply, add it to &lt;code&gt;pubspec.yaml&lt;/code&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;device_info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.4.1+4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then import it to your code and create &lt;code&gt;DeviceInfoPlugin&lt;/code&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;DeviceInfoPlugin&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeviceInfoPlugin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, get IOS or Android platform information.&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;IosDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iosInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&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;AndroidDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;androidInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and finaly, create your Sentry event with these &lt;code&gt;extra&lt;/code&gt; information so the final code will look like:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getSentryEnvEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;/// return Event with IOS extra information to send it to Sentry&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isIOS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;IosDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iosInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;release:&lt;/span&gt; &lt;span class="s"&gt;'0.0.2'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;environment:&lt;/span&gt; &lt;span class="s"&gt;'production'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// replace it as it's desired&lt;/span&gt;
      &lt;span class="nl"&gt;extra:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'model'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'systemName'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;systemName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'systemVersion'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;systemVersion&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'localizedModel'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localizedModel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'utsname'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;utsname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sysname&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'identifierForVendor'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;identifierForVendor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'isPhysicalDevice'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iosDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPhysicalDevice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;},&lt;/span&gt;
      &lt;span class="nl"&gt;exception:&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;stackTrace:&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// return Event with Andriod extra information to send it to Sentry&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isAndroid&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;AndroidDeviceInfo&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;androidInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;release:&lt;/span&gt; &lt;span class="s"&gt;'0.0.2'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;environment:&lt;/span&gt; &lt;span class="s"&gt;'production'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// replace it as it's desired&lt;/span&gt;
      &lt;span class="nl"&gt;extra:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'model'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'device'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'androidId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;androidId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'brand'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'display'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'hardware'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hardware&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'manufacturer'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manufacturer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'product'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'version'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'supported32BitAbis'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supported32BitAbis&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'supported64BitAbis'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supported64BitAbis&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'supportedAbis'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supportedAbis&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'isPhysicalDevice'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;androidDeviceInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPhysicalDevice&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;},&lt;/span&gt;
      &lt;span class="nl"&gt;exception:&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;stackTrace:&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Return standard Error in case of non-specifed paltform&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// if there is no detected platform, &lt;/span&gt;
&lt;span class="c1"&gt;/// just return a normal event with no extra information &lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;release:&lt;/span&gt; &lt;span class="s"&gt;'0.0.2'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;environment:&lt;/span&gt; &lt;span class="s"&gt;'production'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
    &lt;span class="nl"&gt;exception:&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;stackTrace:&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;,&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;Awesome, now when you capture an error, not only you see stack traces but also you'll see extra information which might be helpful for debugging and reproducing the bug. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dx7wU18y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/60inrlvtg6am726pd6x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dx7wU18y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/60inrlvtg6am726pd6x4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5- Detect Debug mode
&lt;/h2&gt;

&lt;p&gt;With Sentry set up, you can begin to report errors. Since you don’t want to report errors to Sentry during development, first create a function that lets you know whether you’re in debug or production mode.&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;/// Whether the VM is running in debug mode.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// This is useful to decide whether a report should be sent to sentry.&lt;/span&gt;
&lt;span class="c1"&gt;/// Usually reports from dev mode are not very&lt;/span&gt;
&lt;span class="c1"&gt;/// useful, as these happen on developers' workspaces&lt;/span&gt;
&lt;span class="c1"&gt;/// rather than on users' devices in production.&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;isInDebugMode&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;inDebugMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inDebugMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inDebugMode&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;I suggest adding &lt;code&gt;isInDebugMode&lt;/code&gt; function to your utility file where you can use it globally throughout your application. &lt;/p&gt;

&lt;h2&gt;
  
  
  6- Catch and report Dart Errors
&lt;/h2&gt;

&lt;p&gt;Next, use this &lt;code&gt;isDebugMode&lt;/code&gt; in combination with the &lt;code&gt;SentryClient&lt;/code&gt; to report errors when the app is in production mode.&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;/// Reports dart [error] along with its [stackTrace] to Sentry.io.&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reportError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StackTrace&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isInDebugMode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// In development mode, simply print to console.&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'No Sending report to sentry.io as mode is debugging DartError'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Print the full stacktrace in debug mode.&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// In production mode, report to the application zone to report to Sentry.&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getSentryEnvEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stackTrace&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Sending report to sentry.io &lt;/span&gt;&lt;span class="si"&gt;$event&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sentry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;event:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Sending report to sentry.io failed: &lt;/span&gt;&lt;span class="si"&gt;$e&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Original error: &lt;/span&gt;&lt;span class="si"&gt;$error&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&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;In your main dart file entry for Flutter, Where you call &lt;code&gt;runApp&lt;/code&gt;, import &lt;code&gt;reportError&lt;/code&gt; function and assign it to &lt;code&gt;onError&lt;/code&gt; callback.&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;// Runs the app in a zone to be able to capture and send events to sentry.&lt;/span&gt;
    &lt;span class="n"&gt;runZoned&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;(()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SystemChrome&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPreferredOrientations&lt;/span&gt;&lt;span class="o"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DeviceOrientation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[&lt;/span&gt;&lt;span class="n"&gt;DeviceOrientation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;portraitUp&lt;/span&gt;&lt;span class="o"&gt;]).&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YouAwesomeApp&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
      &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;},&lt;/span&gt; &lt;span class="nl"&gt;onError:&lt;/span&gt; &lt;span class="n"&gt;reportError&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  6- Catch and report Flutter Errors
&lt;/h2&gt;

&lt;p&gt;In addition to Dart errors, Flutter can throw errors such as platform exceptions that occur when calling native code. To capture Flutter errors, override the &lt;code&gt;FlutterError.onError&lt;/code&gt; property. If you’re in debug mode, use a convenience function from Flutter to properly format the error. If you’re in production mode, send the error to the &lt;code&gt;onError&lt;/code&gt; callback defined in the previous step.&lt;/p&gt;

&lt;p&gt;So, In your main dart file entry for Flutter, Where you call &lt;code&gt;runApp&lt;/code&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;FlutterError&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlutterErrorDetails&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;forceReport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isInDebugMode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// In development mode, simply print to console.&lt;/span&gt;
        &lt;span class="n"&gt;FlutterError&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dumpErrorToConsole&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// In production mode, report to the application zone to report to Sentry.&lt;/span&gt;
        &lt;span class="n"&gt;Zone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;handleUncaughtError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;);&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;h2&gt;
  
  
  7- Summary
&lt;/h2&gt;

&lt;p&gt;Since buggy apps lead to unhappy users and customers, it’s important to understand how often your users experience bugs and where those bugs occur. That way, you can prioritize the bugs with the highest impact and work to fix them. However, sometimes it's crucial to know the specific information about the running platform where the errors occurred in order to reproduce and debug and at the end of the day fix. &lt;/p&gt;

&lt;p&gt;Adding more platform-specific information to your error tracking service event whether is Sentry or other services helps to find out the details to resolve the bugs and errors easier by reproducing in the exact same environment. &lt;/p&gt;

&lt;p&gt;I hope this small tutorial can help you to manage your errors with better and more extra information. &lt;/p&gt;

&lt;p&gt;If you found this article helpful, consider following me here or on &lt;a href="https://twitter.com/mhadaily"&gt;Twitter&lt;/a&gt; and react to the article. &lt;/p&gt;

&lt;p&gt;Your feedback is also highly appreciated. &lt;br&gt;
Happy debugging, &lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Upgrade to Bloc Library from v0.x to v2.x for Flutter and Angular Dart</title>
      <dc:creator>Majid Hajian</dc:creator>
      <pubDate>Thu, 31 Oct 2019 10:30:28 +0000</pubDate>
      <link>https://forem.com/mhadaily/upgrade-to-bloc-library-v1-0-0-for-flutter-and-angular-dart-2np0</link>
      <guid>https://forem.com/mhadaily/upgrade-to-bloc-library-v1-0-0-for-flutter-and-angular-dart-2np0</guid>
      <description>&lt;p&gt;There has been a great improvement to Bloc library by &lt;a href="https://twitter.com/felangelov"&gt;Felix Angelov&lt;/a&gt; which has been published &lt;a href="https://medium.com/flutter-community/bloc-library-v1-0-0-is-here-1f64bd6d3518"&gt;here&lt;/a&gt; after a great contribution by the community &lt;a href="https://github.com/felangel/bloc/issues/558"&gt;for an issue on Github&lt;/a&gt;. This is the power of the community in order to shape a great library. So, As a community person, I love it! &lt;/p&gt;

&lt;p&gt;Since then, I was asked several times regarding the upgrade to the new version. Although changelogs are available by Felix, I still decided to write a short blog in order to share my knowledge after upgrading to the new version on a huge codebase.&lt;/p&gt;

&lt;p&gt;The main changes in Bloc v2.0.0 are:&lt;/p&gt;

&lt;p&gt;1- Bloc as a Stream, that means all blocs are now &lt;code&gt;Stream&lt;/code&gt;. Therefore, you can &lt;code&gt;listen&lt;/code&gt; to &lt;code&gt;bloc&lt;/code&gt; right away and it enables us to get &lt;code&gt;state&lt;/code&gt; as the latest state available. In short, &lt;code&gt;currentState&lt;/code&gt; in &lt;code&gt;bloc&lt;/code&gt; is no longer makes sense instead it becomes &lt;code&gt;state&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;2- Bloc as a Sink, which enables us to use &lt;code&gt;add&lt;/code&gt; on &lt;code&gt;sink&lt;/code&gt; API in order to notify the bloc of a new event. &lt;/p&gt;

&lt;p&gt;So, in order to make your code compatible, technically in your &lt;code&gt;Bloc&lt;/code&gt; you need to do the following changes: &lt;/p&gt;

&lt;p&gt;from&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;exampleMethod&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;);&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;to&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;exampleMethod&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;);&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;When you need to manipulate your state you had &lt;code&gt;dispatch&lt;/code&gt; method where you could pass an event to, now you can simply use &lt;code&gt;add&lt;/code&gt; instead as all blocs are now &lt;code&gt;Sinks&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;from&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;BlocProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AnyBloc&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&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;dispatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YourEvent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&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;BlocProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AnyBloc&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&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;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YourEvent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and simply if you are in Bloc itself,&lt;/p&gt;

&lt;p&gt;from&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ExampleBloc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExampleInitialEvent&lt;/span&gt;&lt;span class="o"&gt;());&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;to&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ExampleBloc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExampleInitialEvent&lt;/span&gt;&lt;span class="o"&gt;());&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;and now if you have cleaned up your &lt;code&gt;bloc&lt;/code&gt; by &lt;code&gt;override&lt;/code&gt; the &lt;code&gt;dispose&lt;/code&gt; method, you should be able to replace it with &lt;code&gt;close&lt;/code&gt; due to the change as mentioned above. Simply like: &lt;/p&gt;

&lt;p&gt;from&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ExampleBloc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExampleInitialEvent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;StreamSubscription&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleStream&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_subscription&lt;/span&gt;&lt;span class="o"&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="n"&gt;dispose&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_subscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="o"&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;dispose&lt;/span&gt;&lt;span class="o"&gt;();&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;to&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleBloc&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Bloc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ExampleState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ExampleBloc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExampleInitialEvent&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;StreamSubscription&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ExampleStream&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_subscription&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_subscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&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;close&lt;/span&gt;&lt;span class="o"&gt;();&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;These changes should make your code compatible with version v2.0.0. &lt;/p&gt;

&lt;p&gt;Post your comment if you still have issues or share your experience on what you have done.&lt;/p&gt;

&lt;p&gt;I hope this short blog can help those you have faced problems while upgrading or have worries to start upgrading. &lt;/p&gt;

&lt;p&gt;Happy upgrading! &lt;/p&gt;

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