[MUSIC] βͺ Test. Test. Test. Test. Test. This is a Closed Captioning test. Test. Test. Test. Test. Test. This is a Closed Captioning test. Test. Test. Test. Test. Test. This is a Closed Captioning test. Test. Test. Test. Test. Test. βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ βͺ [ Birds chirping ] >> Rami Alhamad: You ever traveled somewhere and saw kids playing soccer? There's something really fascinating about how sport transcends all cultures, languages, history. Over the years, I've dabbled in every sport imaginable. [ Sound of camera shutter ] I think that's part of the reason when I launched PUSH that I was absolutely inspired by how we can help athletes across all sports. >> Robyn Birch: I've represented the British Diving Team since 2015, competing at European and World level. This is really where fine margins make all the difference, which is why I started using PUSH. >> Rami Alhamad: PUSH is an advanced strength training wearable. Part of our mission is to optimize athletic training, making sure that when an athlete is walking into the gym, they're actually getting the most that their body can afford to give that day. >> Robyn Birch: PUSH gives me rep by rep feedback in real time, so my lifting becomes more flexible and efficient, which helps me improve my strengths as A diver. >> Rami Alhamad: We were constantly getting requests for Android support, and one of our challenges is that we're a small team and we knew that trying to support two different code bases was going to be super difficult. With Flutter, we are able to save roughly a day a week in just syncing two different code bases. It's really enabled us to push out a lot more features a lot faster. Being a wearable, we really needed to make sure that the Bluetooth connection was going to be robust and reliable, that it can handle any type of data transfer that we need, and we were blown away by just how performant Flutter was. We really wanted to make sure that our technology can scale, like, can help impact athletes' lives at various levels of development, and that's something that I'm really proud of. >> Robyn Birch: PUSH gives me motivation to see how far I can go and what I can achieve. That ultimately means the Olympics. [ Cheerful music ] [ Cheerful music ] >> Three, two, one. [ Upbeat music ] [ Upbeat music ] [ Birds chirping ] >> Tim Sneath: Welcome to Flutter Engage. We're so glad to have you join us virtually wherever you are. It's been a tough year for many, and so we're thrilled to share some good news as we show you some of what we've been working on and announce some new things that we think you'll like. Our theme for this year's event is to highlight the flexibility and portability of Flutter as a complete UI toolkit for building beautiful apps for any platform, and today is a key milestone for Flutter with the launch of Flutter 2, a major upgrade to Flutter that builds on the momentum and foundation of previous releases and opens up a broad range of new target platforms for production use. Over the next hour, you're going to hear us talk about Flutter on Android and iOS, as well as Web and Desktop. You're going to hear from companies like Microsoft, Canonical, and Toyota, and you can learn more about how our work on Dart provides a unique technical envelope for your code, providing a portable, productive, and robust combination of capabilities for building apps. Flutter is the first UI platform that is designed for an ambient computing world, and this vision is unique to Flutter. A portable toolkit for building beautiful, Native, fast experiences wherever you might want to paint pixels on the screen. Our goal is to shift you from having to start with the platform you're targeting and focus instead on what you want to create. Some UI toolkits impose tight constraints on what you can build, they limit your creative expression to what fits within the toolkit, but Flutter allows you to handcraft beautiful experiences where your brand and design comes to the forefront. Flutter is fast, it compiles your source to machine code, but thanks to features like Stateful hot reload, you still get the productivity of interpreted environments, allowing you to make changes while your app is running and see the results immediately. And, of course, Flutter is open with thousands of contributors adding to the core framework and extending it with an ecosystem of packages. So, the big news in Flutter 2 is that we broadened Flutter from a mobile framework to a portable framework, unleashing your apps to run on a wide variety of different platforms with little or no change. As of right now, there are already over 150,000 Flutter apps out there, and that number has doubled just since last summer. These apps come from big teams at big companies as well as entrepreneurs and start-ups who simply want to share their idea with the world. And we thought we'd show you some of our favorites. [ Upbeat electronic music ] βͺ [ Rhythmic drumming ] [ Techno sounds ] [ Rhythmic whistles ] βͺ [ Upbeat electronic music continues ] So let's talk about what's in Flutter 2. You can think of Flutter 2 as a free upgrade for your app. We've shipped about ten updates to Flutter since our original launch, but in this release, we add support for something worthy of a major version upgrade, a major increase in the number of users you can reach. If you've built a Flutter app so far, you've probably been thinking primarily about iOS and Android. But with Flutter 2, your app can target four additional platforms, Windows, macOS, Linux, and the Web. And when you add iOS and Android to that list, you can see how uniquely flexible Flutter is. With Native support for six different platforms and the ability to tailor the experience for each platform without compromising performance, Flutter is perfectly suited to both rapid iteration and high-quality results. So, to demonstrate Flutter's versatility in action, we asked our friends at gskinner to create a demo app that spans all these platforms. Let's show you what they've created. >> Hi, everyone. Here at gskinner, we've created a variety of Flutter apps that compiled to and ran on multiple platforms, but for this project, we wanted to go beyond that and build something that purposefully considered the norms, user expectations, input devices and idioms for each platform to create an app that truly felt at home on every device. We also wanted to leverage the unique strengths of each platform to power a creative workflow. After some brainstorming, we decided to build a scrapbooking app called flutter folio. [ Upbeat funk music ] βͺ Let's take a closer look at how the app works on different devices. Mobile devices are great because they're portable, follow us everywhere, and they usually have a camera built in. Given that, we focused the small screen experience around capturing content. Let's say you were on a walk and you bumped into Tim and his rabbit Carl, you could use the mobile-friendly UI to quickly navigate to an existing scrapbook and reminisce about shared experiences. Or navigate to your furry friends folio and snap a few pictures of Carl to add in later. Of course, larger screens provide a lot more space and improved precision, which makes them ideal for creative work like editing a scrapbook. So when you get back from your walk super excited to add in your new photos of Carl, you can fire up the app, maximize it via the Native controls and the custom title bar, and use your scroll wheel or arrow keys to navigate to a scrapbook you're looking for. While editing, you can use Desktop-specific idioms like multi-select, Native menus, keyboard shortcuts, context menus, and scroll wheel zoom. But, of course, not all large screens are the same. When working on a touch device, the UI adapts in a variety of ways, such as providing larger hit areas and exposing functionality through contextual buttons instead of right click menus. Last but not least, we wanted to target the web. These days, browsers are capable of almost everything you can do in a Native app, so the full app runs there as well, but the web is unique in the ease with which content can be shared. We leverage that strength to let you share a read-only version of your scrapbook. For example, to share your amazing new page with Tim and Carl so they can follow along in real time as you make new updates. This URL is actually live right now, if you want to go check out Carl. Of course, we barely skimmed the surface today, so I'd like to invite you to visit flutter.gskinner.com where you'll find more info, source code, and links to the app. We also learned a ton building this, and we're excited to share that knowledge on our blog and via Twitter. Ultimately, we were able to build an app that runs great and feels at home on three form factors, five OSs, and the web while reusing over 95% of our code. We built flutter folio with best practices in mind. You can check out the source code to start making your apps platform adaptive today. >> Tim Sneath: If you want to experiment with this app further, the source code is available at flutter.gskinner.com. And for more on great design practices with Flutter, check out the separate talk with Filip Hracek that we're posting live today. Of course, there are hundreds of other new features in Flutter 2. We continue to make progress on foundational areas that you and your customers care about, improving performance and stability, supporting the latest UI trends and widgets, and increasing accessibility. We've completed our work on a new State restoration API with support for running on Apple Silicon. We've added multi-line text editing and keyboard shortcuts, we've added interactive scroll bars, we've implemented Null Safety throughout the framework, and we've closed nearly 6,000 issues. The full list of pull requests merged is a 200-page document, to give you a sense of the size of this upgrade, and we have a blog post with a lot more details. Flutter isn't just being used outside Google. Over 1,000 engineers inside the company are using Dart and Flutter to develop apps today, representing over 30 different teams, and the apps that you see on this list here are already shipping using Flutter. One of the largest apps from Google using Flutter is Google Pay. And Timothy Jordan recently sat down with Peeyush Ranjan, who is the Vice President of Engineering for Google Pay, to ask him about their experiences with Flutter. Let's hear what they had to say. >> Timothy Jordan: Hey, Peeyush, Timothy here. Every since Google Pay moved to Flutter, we've been getting some questions from our developers, was it an effective move for you, and would you recommend it to other teams? >> Peeyush Ranjan: Hi, Timothy. Thanks for asking. In a nutshell, I'll say, yes, it was absolutely effective. You might have heard of Google Pay, but let me first tell you the scale of the problem. You know, we are trying to launch in 30 countries on two platforms, Android and iOS, and serve users in all these countries. We have 150 million-plus users. Now, as a result, we have two code bases, right, iOS and Android, and those total 1.7 million lines. We also had feature disparity. The feature being implemented in each was happening at a different rate. Also, tech debt was building up and we needed more and more engineers to keep up development on these code bases, so we started looking at Flutter, and after weighing the pros and cons of a rewrite and a migration, we decided to rewrite everything. The good thing was we ended up with 35% smaller code base, 1.1 million lines compared to 1.7 million lines, and at the same time, our tech debt went down by 90% on a per engineer basis. Now, once the rewrite was done, we also found that our engineers were 20% more productive in terms of features implemented because of the rewrite. We were also able to merge all the duplicate release process experimentation, the launch process, security reviews because now everything was done on the Flutter code base. Plus, the best part was with every engineer working on the same code base, we were able to take the iOS engineers and Android engineers and get 50% engineering efficiency immediately because they were all working on the same thing. Now, if I had to go back, I would absolutely make this decision all over again, and to answer your question, yes, I would recommend to any team that builds on multiple platforms. >> Timothy Jordan: Okay. Thanks for joining us today, Peeyush. >> Tim Sneath: So, one of the most interesting things about mobile development is that phones come in so many different shapes and sizes. And one of the latest trends is foldable phones. One great example of this form factor is the Surface Duo from Microsoft, which combines the best of Android with the Surface team's hardware engineering expertise, and we're happy to announce that Microsoft has been contributing code to Flutter over the recent months. Here to tell us more is Guy Merin, who leads Surface Developer Experience Engineering. >> Guy Merin: In the last year, we've seen new device form factors emerge, the foldable and dual screen devices. This new form factor is great for productivity when you're in your home office or when you're on the go. The device adapts to you. When you're creating content, playing a game, watching a video, typing, or just reading and browsing the web. For us, the mobile developers, it means new scenarios and user experience to explore in our apps. First, your app can now run on two screens and not just one. You have more screen real estate to show content and interact with our users. When thinking about two screens, you can also utilize various dual screen design patterns, such as the List-Detail view, the Companion Pane, and other ways to organize your application UI. The foldable form factor also provides opportunities for your app to share content with another app. For example, when two apps are running side by side and by adding drag and drop functionality to your code. We want developers to take advantage of foldables and dual screen devices regardless of the platform or app that they're building on. Today we are happy to announce that we are collaborating with Google and bringing foldable support to Flutter. We're contributing code to enable Flutter apps to take advantage of these new opportunities with devices like the Surface Duo, but also enable it on other devices like from manufacturers like Samsung and others. Let's see a demo now. The best way to demo anything Flutter is by using the Flutter Gallery app that we are all familiar with. This is the Surface Duo Emulator, which you can download today. Let's run the Flutter Gallery app and look at the widget. The app is started on a single screen, so let's span it across both screens now. As you can see, the app reacts natively to dual screens and repositions the assets across both panes. This is typically the first step that you will take in your app. Start thinking today of the new layouts that you may want to show now that you have two screens, but Flutter is all about widgets, so let's see those in action. We've added foldable support for the existing Flutter widgets. For example, when you use the dialogue, it will now be hinge aware and will display according to your choice on the right or left pane. We've also modified other model routes, pop-up menus and other widgets. Let's move on. We've added the new widget to help you position assets on two screens. We call it the two-pane widget. You can use it to place assets on the right pane or on the left pane. It will also display correctly on a single-screen phone or a tablet-like device. The two-pane widgets makes it easy to support all these new form factors. But enough with demos. Let's dig into some code now. We've added displayFeatures to MediaQuery. You can use it to query the type of displays you have and the position of the hinge. When you're using the two-pane widget, add your own widget and content to either the left or right pane. Let's summarize what's new. Foldable and dual screen devices are available now and ready for you to try them with your app. You can use a dual screen device or a dual screen foldable emulator. The code and widgets we've previewed here are ready for your review and your feedback. We want to meet developers where they're at, and today we're super excited to share this news with you, the great Flutter community. All the samples and widgets are open source and ready for your contribution. We're excited to see what you build with them in your app. Thank you, and back to you, Tim. >> Tim Sneath: So, let's talk about portability. Last year, we gave you an early preview of Web Support, so today we're delighted to announce that Flutter's support for the Web platform has hit the stable milestone. This is a huge leap forward for Flutter, building on the portability of Dart, the power of the Web platform, and the flexibility of the Flutter framework to deliver the same experiences on the web as on mobile, and it's exactly the same Flutter framework. It's not a fork, it's not a different edition. The web is just another device target for your app. So, not every web page makes sense in Flutter, but we think that Flutter is particularly suited for app-centric experiences, things like Progressive Web Apps that integrate with a user's environment, including installation, offline support, and tailored user experiences. Single page apps that deliver a client-rendered experience, and existing Flutter mobile apps that want a fast path to the browser. So I thought it would be fun to chat with Dion Almaer, who is responsible for the web developer ecosystem here at Google, including, of course, the Chrome browser, and get his take on how Flutter fits more broadly to the web platform as a whole. Dion, thank you for joining me today. >> Dion Almaer: Thanks a lot, Tim. Thanks so much for inviting me to share my excitement, really, about Flutter 2 and the availability of Web Support. You know, we think the web is an incredibly broad tent. It was born as a content platform and enables richer capabilities for publishers than ever, but we've seen this open platform evolve into a great one for use cases such as commerce and, of course, apps. Now, the broad tent has allowed for many web frameworks and approaches to innovate, offering you, the developer, choice, and there's plenty of room for Flutter to join the fun. Now, the web has many strengths, including ubiquity and reach, so if you're building a Flutter app, you now get to reach users outside of app stores, and with the power of URLs, users across operating systems or device types can be directed to any part of your app from links that are shared by friends, clicked on in search, from an email, from anywhere. So, remember when Spotify came into CDS one year and shared their story of their first progressive web app and how to drove so much engagement because many users were simply looking to listen to a song and were now able to go straight to that action versus facing any install friction. High-quality PWAs like these are now possible due to the web pushing on two areas. First, platform improvements. These enable fast performant rendering, and we know this is really important to the Flutter community. Second, bringing capability gaps to the web in a soft, trusted manner. Project Fugu is our main umbrella for this effort. And PWAs are just a great fit for Flutter because of the marriage between on the one hand a world-class developer experience for app development, and with the other, the web platform ingredients that can be incorporated by the Flutter engine, so you get improvements for free as both Flutter and the web evolve. We've seen this at work. As Flutter's Web Support has transitioned from tech preview to beta to now production. The Flutter team were able to try different rendering approaches, you know, starting with the DOM, but then CanvasKit, taking advantage of new APIs to help with ergonomics and speed up performance. This is where WebAssembly and WebGL opened the door for massive optimizations, which the Flutter team has done wonders with. We're collaborating in many other areas, such as improving text metrics, new accessibility APIs, and more. So, I hope that you and the Flutter team collectively keep pushing us further to enable the next generation of experiences because we really do know that we've only just begun. So with the Flutter and Chrome team working well together, we can iterate on web platform features that Flutter can abstract and make easy for you to use so you can just focus on your app. Now, also, users are clamoring for high-quality PWAs. So, Flutter gives you a great way to ship them, and I can't wait to see what you, the developer, do here, because I've seen how the Flutter community always delivers on high-quality, creative experiences. >> Tim Sneath: Dion, thank you so much. It's great to have you join us. >> Dion Almaer: Thanks again, Tim. Appreciate it. >> Tim Sneath: So, since we announced Beta Support for the web, we've been focusing on some major architectural improvements that extend and optimize the core Flutter framework for the web. Perhaps the biggest thing that we've been working on since the preview, as Dion mentioned, is performance, and we've been making a ton of progress. We recently switched our defaults for the Desktop browser over to a new CanvasKit renderer that combines Skia and WASM to couple a lightning-fast web graphics engine with the productivity and ease of use of Flutter, and we're seeing huge performance gains as a result. So, I want to show you an example of this with a demo from Felix Blashchke, who is a developer in Germany who has been experimenting with Flutter graphics on the web. [ Glass shattering ] βͺ [ Upbeat music ] [ Birds chirping ] Even more fun, I can take the same demo and run it multiple times simultaneously on the same machine thanks to the power of Flutter. [ Glass shattering ] βͺ [ Upbeat music ] So, performance is important, but it's not the only thing that we need. A Flutter app that's running in the browser should feel like a web app. So we've been adding features to Flutter that help you use the best of the web. For example, hyperlink widgets, text auto fill, control over address bar URLs and routing, and PWA manifests. And thirdly, we want to make Flutter web experiences feel right, whether you're using a mobile phone or a laptop with a keyboard and mouse, and regardless of what shape and size your browser window is, so we've added interactive scroll bars and keyboard shortcuts. We've increased the default content density in Desktop modes, and we've added screen reader support for accessibility on Windows, Mac, and Chrome OS. I want to show you one example of the kind of app that shines really well on the web. iRobot is the company behind the popular Roomba robot vacuums, but they also have coding robots that empower the next generation of innovators. Let's take a look at their Root robots. >> Your child may have what it takes to become the next great digital visionary, you just have to allow it to take root. Coding shouldn't be something just computer scientists do, it should be something everyone can do, and Root makes that possible. It's easy for coding to feel abstract, but Root teaches computer programming in a new way. It starts with a language so simple that a young child can use it, even before they know how to read. >> Tim Sneath: iRobot built their app with Flutter, and today they're launching the web version of their experience. So, here, you can see the app running in the browser using the same code as their tablet app. On the left side, you can see their visual code editor, which lets you drag and drop commands and flow structures that will run on the robots, and on the right-hand side of the screen, you can see a simulator that shows a virtual robot and lets you test out your app before running it on the real thing. They have a whole library filled with different project ideas and three different coding levels within the project aimed at different age levels, and, of course, everything you see here is built with Flutter, including the simulator, with the same code shared between iOS, Android and web browser. It's really cool to see iRobot using Flutter for educational purposes, and I hope you'll check it out yourself at code.irobot.com. Of course, we're using Flutter's Web Support ourselves. One example that will be familiar to most of you is DartPad, our web-based scratch pad for exploring Flutter and Dart code. We also use it throughout our documentation so you can see how to work with a widget in line in your browser without first having to copy it into your app. There's so much more to say about running Flutter on the web, and so we have a breakout session dedicated to this topic where Mariam Hasnany and John Ryan walk through building and deploying a web app with Flutter. So, you've already seen how portable Flutter is with the ability to go from mobile to web, and the great thing about building on open-source foundations like Skia is that we can take this work further still, including three platforms that together reach well in excess of a billion users, Windows, Mac and Linux. Today, we're delighted to announce that we are also opening up Desktop to the stable channel of flutter enabled with an early release flag. This release lets you produce standalone executables for each platform, macOS, Linux and Windows, and you can even use the developer tooling provided on each platform to submit apps into the store. We're excited that now everyone can run Flutter natively on their developer work station. This isn't just our work, it's been a community partnership. Microsoft has contributed a number of pull requests to the Flutter engine to use the latest Windows runtime APIs when running on Windows 10. On Linux, Canonical has been a fantastic partner, and I'd like to have them tell you about some of their contributions to Flutter. >> Ken VanDine, Engineering Manager for Ubuntu Desktop at Canonical. When Desktop Application Support in Flutter was announced, we saw an exciting opportunity to make Linux distributions, including Ubuntu, an attractive target platform for Flutter app developers. Flutter's Native multi-platform story is growing rapidly, and we wanted to be at the vanguard. We worked with the Flutter team to bring Desktop Linux support to Flutter, making it easy for app developers to publish their apps for Linux. By making Linux a first-class platform in Flutter, we are inviting application developers to publish their apps to millions of Linux users and broaden the availability of high-quality applications available to them. We not only enabled Flutter for Linux, we also worked with the Flutter team to publish the Flutter STK as a snap in the Snap Store, the app store for Linux. By publishing the Flutter STK as a Snap, we've made it very easy to install and set up your development environment to build mobile, web, and Desktop apps with Flutter on Ubuntu. Even with just these basics in place, we're at a very exciting point in our Flutter journey. Linux support for Desktop apps is rich enough that we can recommend it for developers to use today. We continue to support Flutter for Linux, keeping in sync with other Desktop platforms, but that's just the start. We also want to give developers a rich toolbox of window types to create effective user interfaces across platforms. To do so, we will work to bring full multi-window support to Flutter for Desktop across all the Desktop platforms that Flutter supports. We are working with the Flutter team at Google on the specification now, and we will start the engineering work very soon. Of course plug-ins are an essential part of the Flutter app ecosystem as well. We are working on enabling popular Flutter plug-ins for Linux, including Flutter support for Firebase, Bluetooth, network connectivity, Desktop notifications, and more. Furthermore, while enabling app developers to bring their apps to the Linux Desktop, we thought it would be nice to bring along the Ubuntu style as well. Ubuntu has a very distinct style, which we are proud of. We call this style yaru, which is a community-led effort within Ubuntu. We have worked with the yaru team to bring yaru to Flutter, which takes material as the base and applies the Ubuntu style, colors and fonts. This enables app developers targeting Ubuntu to match the distinct Ubuntu style with ease. Now that we have enabled Flutter for Linux, for other app developers, it's time to further our commitment by building our own Linux apps with Flutter. As we've already announced, we are developing our next-generation Ubuntu Desktop Installer in Flutter. Soon every user who installs Ubuntu Desktop will be doing so with our new installer built in Flutter using the yaru style. Along with the new installer, the out of the box experience for devices preloaded with Ubuntu will also be powered by Flutter. Choosing the installer as our first app written in Flutter is a bold move, to say the least. It's the first thing our users see, and as everyone knows, that first impression is critical. It not only has to be beautiful, it has to be robust and reliable. It has to run on a wide range of hardware, ranging from old PCs or laptops to the latest hardware on the market. The user experience can also be very complex, with advanced dialogues for dispartitioning supporting a huge variety of possible configurations. We feel Flutter is up for the task, and choosing it for the installer is telling the world that choosing Flutter for Linux apps is a great choice. The Desktop team not only worked to make Linux a first-class citizen in Flutter, Flutter is the default choice for future Desktop and mobile apps created by Canonical. We look forward to working with you. Thanks. >> Tim Sneath: Thanks so much, Ken. It's a really big deal for us that you picked Flutter for the very first experience users have of Ubuntu, and we're looking forward to continuing to work with Canonical. So, we've talked about how the key theme for the Flutter 2 release is portability, upgrading your code to be able to run on six different platforms, iOS, Android, Web, Windows, macOS and Linux, but there are even more screens out there beyond the kind of operating system that you might have on your phone or your PC. So, I'm delighted to introduce another customer who is using Flutter to bring beautiful user interfaces to light in a critical part of their own product. Toyota is the world's biggest selling automaker with over 9.5 million vehicles sold in 2020. And with cars, beautiful, tailored user experiences matter. Toyota are building Flutter right into the heart of their core product, so I want to hand over to Daniel Hall to share more about their plans with Flutter. >> Daniel Hall: Hello. I'm Daniel Hall, Chief Engineer at Toyota Motor North America as well as Global Chief UX Designer at Toyota Connected. Basically what that means is I'm responsible for leading design and development for our next generation in-vehicle infotainment systems. Today we're excited to announce that Toyota's partnering with Flutter to bring a best in market digital experience to vehicles by building infotainment systems powered by Flutter. Using Flutter marks a large departure and approach from how in-vehicle software has been developed in the past. While we're not ready to share our final product just yet, we'll take a little bit of time to talk about why we chose Flutter and how we're using it at Toyota. So, why did we pick Flutter? At Toyota, we continually evaluate options for bringing the best possible user experiences to our customers. Flutter immediately caught our eye for a number of reasons. Foremost, Toyota customers expect a consistent and high performance in-vehicle user experience to match the overall quality of Toyota vehicles. Flutter's rendering engine provides good performance in a constrained environment, and features like AOT compilation give us the consistency we're looking for in an in-vehicle technology. Flutter also allows us to provide an in-vehicle user experience on par with what customers have come to expect from their Smartphones. Everyone can probably think of a bad experience they've had interacting with touch screen apps outside of their mobile phones. These apps are often sluggish or just don't feel quite right. What we're doing with Flutter at Toyota directly addresses that problem by leveraging Flutter's cross-platform mechanics. Flutter's done a great job of packaging touch mechanics that just feel right, no matter where they run. Finally, after noting Flutter's performance traits, we were really sold on Flutter's developer experience. Despite releasing our apps on a single-target platform, we leveraged all the multi-platform tools that Flutter provides for the pipeline from design all the way to release. Even as an alpha feature, Desktop Support combined with hot reload provides a fast development workflow. The variety of different release targets that Flutter supports, such as iOS and Android tablets, are useful for all sorts of physical and digital user testing. We can even leverage Web Support as an integration into design tools to improve our feedback cycle with product designers. Of course this developer-friendly workflow isn't just for our own benefit as we create software. Our ultimate goal in using Flutter is to streamline in-vehicle software development, resulting in a better customer experience. A technology that enables high productivity with a relatively low barrier to entry allows us to create a tighter overall feedback loop in our design and engineering processes. These faster iteration cycles allow us to collect and integrate feedback from our customers earlier and more often, which helps us create the best experience for our customers. We talked a little bit about why we chose Flutter, but what are we doing with it that is unique to Toyota? Well, to start with, we're using Flutter's Embedder API to leverage the technology in our infotainment systems powered by automotive-grade Linux. The Flutter engine's architecture makes it relatively easy to support embedding in our target environment, it's just a matter of cross-compiling the engine and wrapping it in an embedder. The Embedder API is fairly easy to use and allows us to integrate our Flutter apps with in-vehicle systems. Additionally, we've created several in-house tools that enhance Flutter's developer ergonomics by extending them to include our design process all under the same umbrella. Our overall goal is to support a workflow that enables design tools to generate code so that validation and running software is immediate. Both Dart's language design and the Flutter STK software design have enabled us to support such tooling. For example, Flutter's approach to declarative UI and code as configuration allows to us very easily perform code generation based on designs without any complicated or confusing middle tiers of configuration. Most importantly, while developing these Toyota-specific tools, Flutter's open-source principles and high-growth developer community have been critical to our success. Without the support of the large and open ecosystem, we couldn't extend Flutter to enable our in-vehicle use cases. At Toyota, we see working with open-source software as a point Positive investment towards our in-vehicle user experiences, and we look forward to playing a role in the open-source Flutter community. We can't wait to share more details of Toyota's partnership with Flutter in the near future. >> Tim Sneath: So, from cars to web browsers to laptops to phones and tablets, Flutter truly is unique as a UI toolkit in its flexibility. By bringing together beautiful, fast user experiences with a productive development environment that lends itself to exploration and iteration, all delivered as free open source from Google, there's nothing quite like it. Let's now go one level deeper and talk about Dart, our client-optimized language for fast apps on any platform. Why does Dart matter? Well, Dart combines a unique set Of capabilities for building apps. For starters, as you've seen already, Dart is portable with compilers that generate highly performant Intel and ARM machine code for mobile and Desktop as well as highly optimized JavaScript output from the web. The same Flutter framework source code compiles to all these targets. Secondly, Dart enables true iterative development with Stateful hot reload on Desktop and mobile as well as language constructs designed for the asynchronous concurrent patterns of the web. And thirdly, Dart offers Google-class performance across all of these platforms with sound Null Safety, guaranteeing Null constraints at run time as well as development. There really is no other language that combines all three of these capabilities together, and it's the reason why we often talk Dart as the secret sauce behind Flutter. Now, we've not been standing still with Dart, so Bob Nystrom is going to tell you about some of the work we've been doing in Dart to upgrade your app. >> Bob Nystrom: Thanks, Tim. I'm very happy to tell you that we have shipped Null Safety for Dart, so now the type system helps you eliminate Null Reference bugs. This is the biggest change to Dart since we added sound static types in Dart 2. With Null Safety, we didn't just add non-nullable types to the type system, we also added a slew of features like smarter flow analysis, late variables and required named parameters so that your Dart code isn't just safe but easy to write. These changes are so big, in fact, that the only reason we aren't calling this release Dart 3 is we managed to ship Null Safety without breaking your code. Instead, we allow Null-safe code to co-exist with Null-unsafe code. This lets you migrate to Null Safety incrementally when you want, and we provide automated tooling to help you. When you migrate and return, Dart gives you more than most other languages with non-Nullable types too. Null Safety in Dart is sound. That means that when your program is fully migrated, the type system guarantees like a mathematical proof that no non-nullable expression can ever evaluate to Null. This guarantees great for confidence in your code, but it's even more valuable for the compiler. Chips are so complex today that we need sophisticated compilers to make the most of the hardware. Compiler optimization is often about detecting that some operation isn't needed and eliminating it, but that optimization's only safe to perform if the compiler can prove that the operation is never needed. Sound Null Safety gives the compiler that proof when it comes to Null checks. Here is some Dart code. The getAge function simply returns the value of a field on a given instance. Here is the assembly code our compiler generated before Null Safety. Since the parameter to getAge could be Null, the compiler has to emit a Null check before the field access. Here's what you get today with Null Safety. Since the field's type is non-nullable, there's no need to check for Null. The generated code simply accesses the field. Our 10 instruction function is now only 3. That's a small change, but real programs contain thousands of these checks, so eliminating them means less code to download at install time and less to execute at run time. Of course working on Dart isn't just about new features, we are constantly improving the performance of existing features, too. The quote I love from an algorithms book is, "efficiency determines the boundary of what is possible." When we make something twice as fast, your app can be twice as rich and interactive. Here are a couple of other improvements we've made. The Google Pay team recently rewrote their flagship app using Flutter. They ramped up fast and wrote a ton of Dart code. So much that they started hitting the wall where the size of their application was going to harm adoption, so we worked to unblock them so that they could use Flutter's compile sized optimizations which got their app 14% smaller than it was with the default compilation settings. Servers often speak UTF-8, but Dart's internal string representation is UTF-16. We found out that UTF-8 decoding was a bottleneck for the assistant team, so Aska on the VM team rewrote our decoder, hand authoring some parts in X64 and ARM Assembly to take advantage of Vector instructions. The result is anywhere from 2 to 20 times faster than before. When you want to access features unique to a hardware platform, you need some kind of inter-op system which Flutter has long had using asynchronous platform channels. Recently, we've been working on a new lower-level synchronous way to call Native code called Dart FFI. That system is now out of beta and ready for production use. With Null Safety out the door, we get to turn towards the next batch of language features. I want to talk about one area we're exploring to give you a feel for how we look at language design. Whenever I talk to developers coming to Dart from Kotlin, the top three requests they have are non-Nullable types, extension methods and data classes. So we have the first two now, so let's talk about the last one. With the data class, you define a type of the set of fields, and then the language gives you a constructer, a quality, hashCode and copying operations for free. It's essentially baked-in behavorial policy. The problem is that methodologies change faster than programming languages. If a few years from now, users decide that persistent data structures are better than immutable value types, we can end up with dead weight language features. So what would it take to be able to define policy at the library level? How could we enable a Dart user to essentially add data classes to the language themselves? What I'm talking about here is metaprogramming, code that produces other code. Metaprogramming is already common in Dart using code generation. If you've used Angular Dart or the built_value package, you've already run Dart code that generated other Dart into your app. But code generators can feel Heavyweight and opaque and kind of bolted on, so we're exploring adding static metaprogramming features directly to the language. Our goal is to enable frameworks like Flutter to eliminate some of the verbose code you have to write today. I'd love a metaprogramming feature expressive enough that you could use it to define a data class system that feels as natural as data classes do in Kotlin. Now, we don't know what the solution will look like yet, but we're actively exploring the design space. Okay, that's a lot to absorb about the language, but a fast language is no use if you can't productively write code in it, so next, Kenzie's going to talk about developer tools. >> Kenzie Schmoll: Thanks, Bob. Hi, everyone. I'm Kenzie from the Flutter team, and today I'll be showing off four new tooling highlights available with Flutter 2. The first new feature we'll look at is one we call Flutter Fix. As part of Flutter 2, we've done a lot of work on consistency and tidying up the framework to make our APIs more approachable and to make your code cleaner. Now, I know what you're thinking, framework improvements are great and bring all sorts of new and improved functionality to you, but usually they also come with some breaking changes to your code. Well, fear not, because what we've also done as part of Flutter 2 is created a tool called Flutter Fix that does all the heavy lifting for you to migrate deprecated APIs in your code base. For example, I have the BudgetTracker project open in IntelliJ. And this is a sample app that hasn't been updated in a couple years now, so now that I updated to Flutter 2, there is some analysis errors to address. You can see that it's use a couple deprecated APIs, so let's click on one of these warnings and see how we can solve the problem. I can see the deprecated member here as well as the quick fix icon. And the quick fix option allows me to automatically migrate my code to the new API. So now I can see my code has been updated, and the warnings have gone away. We've added quick fix rules just like this one all throughout Flutter, and as we move forward with new breaking changes in future versions, we'll add new quick fixes to help you migrate your code. Flutter Fix helps us keep the API fresh without breaking your code, so give it a try. And now that we've moved our BudgetTracker to Flutter 2, let's move on to the second feature I'll be showing off today, Null Safety in Dart. To do this, we'll fire up the Null Safety migration tool with the Dart migrate command. Right now my code is in a state where Null Safety is not enabled, but the migration tool will enable Dart Null Safety and help me migrate my code so that it's compatible with the Null Safe run time. So, I'll open the tool, and this tool analyzes our code to determine what can be non-Null and what should be Nullable. And from this, the analysis tool displays suggested changes with the explanations for those changes. So, for our case, all looks good to me, and I'm just going to go ahead and accept the changes and apply this migration. So if I come back into my code, I can see that my code has been updated to Null Safe Dart. And now have we've migrated our code to Null Safety, we can still use Nullable types, but by default our object references will not be Nullable, eliminating a whole class of bugs from our app, making our app smaller, faster and more robust, and that's just the tip of the iceberg on Null Safety in Dart and on the migration tool, so check out the Null Safety deep dive to learn more. For the third tooling highlight of the day, I'm going show you some new Flutter debugging tools, so let's do a little bit of work on the BudgetTracker app. I'll get it running here next to IntelliJ, and if I play with the app a little bit, everything looks good, but I want to make sure that everything looks good also in landscape mode. Oh, and it does not, so it looks like we have an exception here in the run console, and I can see that a RenderFlex overflowed by 282 pixels on the bottom. Now, looking at this error output, I can actually directly navigate to the error-causing widget in my code, but that's not as helpful as we'd like, because what I'd really like to be able to do is go directly from an error message to inspecting that widget in Flutter DevTools, but luckily we have created a new feature that allows me to do Exactly this. So when an overflow error occurs, your IDE will show you a message in the bottom-right window of your screen, and this message describes the error that occurred, as well as gives you the option to inspect the error-causing widget in the Flutter DevTools Inspector, so let's do that. This opens up the Flutter Inspector directly selected to the error-causing widget, and moreover, we can see this directly in our IDE. Using the Inspector in the past would have required you to open DevTools in your browser, but now we've actually embedded DevTools directly in your IDE. So whether you're using VS Code, IntelliJ or Android Studio, you will always have access to this powerful tool that gives you insights into your running Flutter app. So, let's get back to the problem at hand and use the Layout Explorer to solve this issue. I can see that I have some unconstrained heights here, so let's fiddle with the flex values in the Layout Explorer to see if I can fix the problem. And there we go. Problem solved. The overflow error went away, and now I know that the SingleChildScroolView was just missing a flex value of 1, and that means it needs to be wrapped in a flexible widget, so what I will do is come over here and wrap this SingleChildScroolView in a flexible widget. So now it has the flex value of 1 that it needs. And if I come into the run console here, do a hot reload, I can see there are no more exceptions and the issue has been resolved in the app. Over time, we'll be adding similar functionality for other common errors to make it easier for you to go from problem to solution using Flutter DevTools all without leaving your IDE. And last but not least of our tooling highlights, I'm going show you some new features in Flutter DevTools. I've already shown you how the Inspector can be embedded in the IDE, but you can also open DevTools in the browser where you'll not only have access to the Inspector, but also more sophisticated debugging tools for things like performance, network, memory and more. Some of this new functionality is available in the Layout Explorer itself. By popular demand, we have added the ability to show a visual representation of fixed layout details in the Layout Explorer, in addition to the flex layouts we already support. So now you can debug layout issues for all kinds of layouts. We have also added an app-sized debugging tool to DevTools, so let's see this in action with the BudgetTracker app. I have already created the size analysis file for my app, so I'll go ahead and import that and analyze the size. We can use this tree map in the tree table below to explore our app size and visualize the space occupied by different classes and libraries. Looking at the overview of my app, the assets are a little concerning. I only used one image in this application called headshot and it's rendered as a really small Avatar in the app, but I can see here it's taking up 1.6 megabytes of space, which seems like way too much for such a small image. So now I can revisit my assets and optimize the image or use a smaller version, and then I can verify the improvement using the Diff Viewer in the app-sized tool. But, unfortunately, that is all the time we have, so be sure to check out the Flutter 2 announcement posts to see all the highlights and new features. To get these tools, all you have to do is run Flutter upgrade to get the latest Flutter 2 build. Thanks for tuning in. Back to you, Tim. >> Tim Sneath: Thanks, Kenzie. Our developer tools are another example of the unique flexible of Flutter, built with Flutter for Flutter and integrated into whatever tool you're running. And for those of you who want to hear more about how Dart Null Safety works and how to migrate your apps to Null Safety, check out the Breakout Session from Leif Peterson. Okay. So, we've seen how Flutter 2 expands Flutter from mobile to web, Desktop and embedded devices. We've talked about Dart as the secret sauce that provides Flutter with a portable, productive language run time with new features such as sound Null Safety that offer increased robustness and performance. But the Flutter ecosystem is much broader than just what we provide. In fact, there are over 15,000 packages now for Flutter and Dart from big companies like Amazon, Microsoft, Adobe, Huawei, Alibaba, eBay and Square. To packages like Lottie, SQLite and SVG. As well as individual developers like you and me who are packaging up useful functionality for others to use. One great example of a useful package is from Sentry, who are publishing a major update to their Flutter STK for their popular crash management and release tooling. This package provides tools to help developers ensure their app is healthy on all their target platforms, offering deep insights into exceptions and crashes whether they occur in Flutter or in underlying components. We're also today announcing a major update to our Flutter plug-ins for several core Firebase Services. Authentication, Cloud Firestore, Cloud Functions, Cloud Messaging, Cloud Storage, and Crashlytics. We've updated all these packages to support sound Null Safety, and we've overhauled the Cloud Messaging package in particular. But there is another major package we're releasing today, and I want to hand it over to Zoey Fan to tell you all about it. >> Zoey Fan: Thanks, Tim. Hello, everyone. My name is Zoey. I am a Product Manager on the Flutter team. There are many ways that mobile developers get paid for their work. Monetizing apps via ads is probably one of the most popular paths for many mobile developers. Today we support ad formats such as overlay banner, interstitial, and rewarded video ads. However, many developers have been asking us, where is inline banner, where is Native ad? Because in order to create a beautiful and seamless user experience, developers want to display ads as part of their content in existing Flutter View and customize it to match the look and feel of the app. Therefore, today, we're excited to announce an open beta for the Google Mobile Ads SDK for Flutter. This is a brand-new plug-in that provides inline banner and Native ads in addition to existing overlay formats. Also, in this plug-in, we're unifying the support for Ad Manager an AdMob, so no matter what size publisher you are, this plug-in is able to tailor to your scenarios. We've been piloting this plug-in with some of our early customers in a private beta program, and many of them have successfully launched their apps with these new formats. Sua MΓΊsica is one of them. Today it is our great pleasure to have Alan, the CTO of Sua MΓΊsica, to share his experience with us all. Let's welcome Alan. >> Alan Trope: Hi, I'm Alan, and as Zoey told you, I'm the CTO of Sua MΓΊsica. Sua MΓΊsica is the biggest Latin American music platform for independent artists in the world. We support more than 16,000 verified artists in publishing and distributing their music on the platform to more than 10 million monthly active users. Our content is 100% user generated, meaning anyone is invited to upload music they've created. In 2020, we rewrote our Android and iOS apps in Flutter and started testing the Google Ads beta plug-in. [ Upbeat keyboard solo ] βͺ Since we are a free platform and we need monetize each user the best way possible, we must have a great UX UI, but how it's done today with overlay banners, we can hardly call it an okay experience. Because of that, we were excited to be invited to participate in the private beta of the ads plug-in where we could implement those banners in widget tree at last, just like a normal widget, simple and clean. This made it possible for us to create the best experience possible for our users while still monetizing from advertising. Okay, let me show you how it works. We want to put our banner right here on this part of the album page so when we scroll it will scroll together. We start by created a Stateless widget that receives a unit name and a list of sizes. Then we will define our banner as the PublisherBannerAd that receives our sizes and unit listeners and the PublisherAdRequest. We can never forget to load the banner. On our listeners, we are going to listen for the loaded and the failed events, and print on screen if needed. Or our Container Now, we just need to put our width and height, and the magic widget that will do the trick, the AdWidget that received our defining banner. Now we just need to add our newly created widget to that part of the page. The SMBanner. AdUnit, I'm going to put the AdUnit defined before. It's the admobBannerApp. With the sizes, I will put the large banner. It's 220 by 100. I just need to save. Now it reloads, and it should appear right now. Ah, okay, we forgot to save the widget. Okay, hot reloading. And there is the banner. It should also appear in every page. As you can see it scrolls together with all the widgets, as we wanted. That's it. You don't have to only take my word. We've had amazing metrics showing an increase of performance since we made the change. When we launched the new app with the Google Mobile Ad for Flutter, we saw 350% increase on impressions with a 43% increase on CTR and a 13% increase on our eCPM. That's it. Hope you guys liked and saw how easy it is to insert ads in our apps with the new ads plug-in. >> Zoey Fan: Thank you, Alan, for sharing your experience, and also, huge thanks to many, many other developers who helped to beta test this new plug-in and make our mobile ad solution more robust. The Google Mobile Ad STK for Flutter, it's available today for you to develop from pub.dev. We hope this new plug-in helps you unlock more revenue growth for your Flutter apps. If you're interested to learn more about how to monetize your apps via ads, we have a breakout session later, and we look forward to seeing you there. Back to you, Tim. >> Tim Sneath: Thank you, Zoey. You know, community is at the heart of what we do as an open-source project. We have over 750 contributors to the core Flutter framework alone. To say nothing of the tens of thousands of you from around the world who organize and attend meet-ups, write blogs and samples, create packages, and file issues and feature requests. Flutter is an attempt to raise the bar for UI development everywhere, and so it's not just a Google product, it belongs to all of us. As someone who has been privileged to be able to travel around the world and meet with people using Flutter, I'm particularly excited by the impact Flutter has made in Africa, where there are some of the most creative and entrepreneurial developers I know drawing attention to an often overlooked part of the world, so I wanted to introduce you to a few friends now. [ Upbeat Music ] >> I'm a Flutter developer from Lagos, Nigeria. >> A Software engineer from Ghana. >> Mombassa, Kenya. >> Nigeria. >> Angola. >> I'm a Flutter Dev from Ghana. >> It was the end of 2017. I just saw that Flutter is released and it's by Google. >> I discovered Flutter in 2018. >> I discovered Flutter from community. >> From a friend of mine. >> A friend of mine introduced me to Flutter. >> Turning my designs into a full-fledged applications was always a painful process until I stumbled upon the Flutter website early last year. I spent a while building a few CSS-inspired effects for Web using Flutter. What I love the most is the creative freedom it gives you. It's been fun. >> So, I've built a couple of apps for clients. I have built a couple of user interfaces and shared them on GitHub. You have the freedom to arrange code the way you like. That is really important to me, and it fascinates me. >> You can basically sit side by side with a designer and change themes, colors, designs, and preview it as you're doing it, and I've worked on five different real life applications using Flutter. >> Flutter gives me complete control over my interface. There are no limits to what we can do with Flutter. >> I got a couple of my inspirations from my own designs, designs from other people, and looking at existing Native applications I can say, okay, what if I tried to do this in Flutter? >> I love design, and it's always exciting to bring designs to life. I love how I'm able to build consistent UIs across platforms, and I love how my apps run very fast. >> So, Flutter's opened doors for me. >> I have gotten a couple of jobs from Flutter. >> I get the opportunity to earn a living for myself doing something I really enjoy. >> It has enabled me to work with companies in India, in the UK, and in the U.S. this is my Flutter story. >> That's my story. βͺ >> Tim Sneath: So, we've got lots of other great content for you today. There are four breakout sessions. There are some community sessions, there's a Leadership Roundtable AMA with representatives from Flutter and Firebase, and new code labs and demos to explore. We hope you'll join us for some of these, but before we're done, one last video of a new Flutter app that we think you'll love. The first Wallace & Gromit feature-length story in over a decade is coming out, and it's delivered through an app built using Flutter. Let's see what the team has created. >> The Big Fix Up needs your help. We're using the latest technology to invite everyone to come and help us. >> Hi, I'm Beth, Product Manager at Fictioneers, and I'm here with my colleague Rex to talk about a brand-new project we've been working on for the last 18 months. It's a new storytelling experience featuring the loveable Wallace & Gromit, and it's called "Wallace & Gromit: The Big Fix Up." Our goal with The Big Fix Up was to create an innovative app that delivered meaningful content to your Smartphone, spanning a variety of different types of media in real time. For us, harnessing Flutter was an obvious choice. It was a great fit for the breadth of media we wanted to share, as well as for the realtime storytelling components. Firstly, Flutter and its plug-in community enabled us to quickly navigate a complex Native integration. I'm now going to hand it over to my colleague, Rex Rafael, our Senior Software Engineer. Rex developed an open-source unitu integration specifically for our project, which is available for developers now. >> In just one week, we were able to ensure compatibility of our tech stacks such as foundation and libraries, and we were quickly able to evaluate and establish the value of presenting the casual game play in media in Flutter using less resources while having rich but shorter AI interactions provided by Unity. Moving forward, Flutter plug-in API made it easy to maintain interaction, easier to understand, and allowed us to make bidirectional communications between Flutter And Unity while retaining that beautiful and high-performance Flutter rendering agent that just makes our app look and feel great. >> Thanks to Flutter's Animation Support, we were able to quickly create a unique look and feel for our Wallace & Gromit app through animations and user interface. In particular, the pre-designed behavior made it easier for us to achieve our goals. From that, we then customized the effects to suit our Wallace & Gromit style. We were also able to implement drawing-based animations using Adobe After Effects, Bodymovin and Lottie. Something that really helped in terms of efficiency was that we were able to validate our approach to the UI through Wireframing. Thanks to the existing material component library, we were able to quickly bring together components that built the backbone of our application. Iterating on our Wireframe app to bring in custom, higher fidelity design components was helped greatly by the component-based architecture. Overall, Flutter helped us to achieve our ambitious vision of storytelling, and we're really excited to see where we can take it in the future. If you want to check out how we've used Flutter and play The Big Fix Up yourself, you can download the app now for free on the App Store or Google Pay. [ Outro music ] βͺ >> Andrew Brogdon: Hey, everybody. I'm Andrew Brogdon, and welcome to the Ask Flutter Lead Roundtable live at Flutter Engage. How live are we, you might ask, let's just say there's a decent chance my daughter might wander in here at some point, so if you see a 4-foot-tall version of me wander into the shot, don't worry. It's all part of the fun. Speaking of guests, though, we have a bunch of leaders from Firebase and Flutter that have sat down to answer your questions. First up, how about Eric Seidel, Flutter's Director of Engineering. >> Eric Seidel: Good morning, end Andrew. Nice to see you. Nice to be here. >> Andrew Brogdon: You started with Flutter from the beginning. You started with Flutter back before it was called Flutter, right? >> Eric Seidel: Yeah, we started this project 6 1/2 years ago now, Ian, myself and a couple of other folks. It has been a wild ride. >> Andrew Brogdon: Awesome. Thanks for being with us here today. Speaking of Ian, Flutter's Tech Lead, Andrew Hickson. >> Ian Hickson: How are you doing? >> Andrew Brogdon: You were telling me you got started on the project when somebody passed you in a hallway, is that right? >> Ian Hickson: THAhat's right He asked me to write some documentation for us, write some specs for what the project was called at the time, Sky I believe. I started writing code and never looked back. >> Andrew Brogdon: That sounds like my story. I started coding and didn't want to do anything else after that. Also with us is Mariam Hasnany. >> Mariam Hasnany: Hi, everyone, how are you doing? >> Andrew Brogdon: You're responsible for defining how Flutter works on the web? >> Mariam Hasnany: Yeah, we've been had art-- hard at work. >> Andrew Brogdon: Last but not least, frank van Puffelen, better known at Puff. >> Frank van Fuffelen: Hey, Andrew, and thanks to the developers. I'm so happy to answer the questions. I brought help. Sparky is going to answer the questions. >> Andrew Brogdon: Awesome. We have questions that have come in on Twitter already and YouTube comments. Back a week or so ago. But we are taking live questions behind the scenes Andrew fits beginen from the DevRel team is mon terrifying the YouTube chat and Twitter. Type it into the chat. He'll be pulling those and we'll get to as many as we can. That said, let's get going. First question up, looks like we have a fun one to start off with. What is the coolest Dashatar you've created or seen? Eric, do you want to start off with this? >> Eric Seidel: Sure. So, full disclosure, my Dashatar was the wizard with a very pointy hat, maybe to match my pointy hair as a manager these days, but I think the coolest one I've seen is the knight with, like, the helmet and the sword. I didn't get that one, but I really like it. >> Andrew Brogdon: Ian, how about you? >> Ian Hickson: I got the -- I got a Dash who is holding a tablet with computer code on it. When I look very closely at the tablet, I noticed it was JavaScript not Dart, so I suspect she's been moonlighting on our Flutter Web Team there you go. Speaking of web, MAaria, did you get the same Dashatar? >> Mariam Hasnany: No, I didn't. I think I got the superhero one. The coolest one I've seen on Twitter is the one that looks like Tim, Tim Sneath. >> Andrew Brogdon: Mm-hmm. Frank, what about you? >> Frank van Fuffelen: Yeah, I did not see that one. I've been trying to create a mash-up of Dash and Sparky. I've been mashing them together quite a bit, didn't get it fully right. The Flutter team came to the rescue. If you check Firebase on Twitter, we have an awesome Dashatar for us right now. >> Andrew Brogdon: That's the pull you have with our team right there. All right. Awesome. Let go into another question. This one came in on Twitter. When will Flutter Web be ready for production? Eagerly waiting for it. Mariam, you're the PM for Flutter on the web. What do you think? >> Mariam Hasnany: So, great news, as of today, Flutter's Web Support is now available on the stable channel. So now you should be able to use web as a target device for your Flutter apps without having to enable any flags, which means for those of you who already have existing Flutter Web apps, you can now build your app in the stable channel, and if you're new to building Flutter web apps, check out -- >> Andrew Brogdon: We just updated our user guides. A lot of good resources there. We have a follow-on question, also on Twitter for you, Mariam. What San ideal use case for Flutter Web? >> Mariam Hasnany: Thanks. That's a really good question. So, with the signature release, we really focused on building a foundation for rich, interactive web applications. So think of things like if you have an existing Flutter mobile app, you can use the same code to build a web version, and then expand your user base so that now you are reaching web users as well. I think we're also additionally a good fit for building Progressive Web Apps or PWAs or single page applications. Those applications usually have a lot of dynamic content, a lot of interactive UI, and so the reason we really believe those three are the best fit is that we still have some work to do around really supporting those document-centric-type pages that you see on, like, traditional HTML with a lot of rich text static content. And so I think right now we're really, really good for web applications. >> Andrew Brogdon: Yeah. That is sort of Flutter's bread and butter, right? Application UI, right? >> Mariam Hasnany: Yep. >> Andrew Brogdon: Mm-hmm. Awesome. Well, thank you. Chimon1984, that's a great question. Moving on, this one's from YouTube. I'm sad I did not get this person's YouTube came. This comes to us from thepoignancy. Which is an awesome name for an account. Will Flutter fire ever become an official Firebase STK? And if so, when? Puff, I think this is your apartment. >> Frank van Fuffelen: I think so, too. It's a great question. So, thank you to poignancy. We at Firebase love Flutter. There might be a few Flutter developers out there. It allows your Flutter application code to talk directly to our functionality. So with Firebase, you can add sign-in by just writing Flutter code instead of having to spin up your own. Or directly talking to a database, right, without having to set up your own REST API. Our team loves Flutter, right, because we love being cross-platform, but we're a cross-platform development platform. Yeah, Flutter is also cross-platform, so they go together like peanut butter and jelly or like Sparky and Dash. It's a bit of a long answer. I think I have three Postm Postmasters . Parts for you. One of them is the STKs. Firebase has a lot of applications we support, but our primaries are Firebase and web. What we've done to make those available to your Flutter app is that we sort of take the official application -- STK, sorry, and we wrap that in some Flutter code for you. So those wrappers we call Flutter fire, but as soon as you're using Firebase in your Flutter applications, you're already using the official STKs because they are right under there. Now, that leaves the Flutter fire library itself, and that library is, indeed, has been going through some changes. As Flutter has been adding functionality platforms mostly, that we also had to update that, so we've been seeing some breaking changes there. So, those have taken some iterations to get through, but I think we're now slowly stabilizing those, so we see more stable API releases coming there. If you find any issues, by the way or you see something that doesn't work the way you expect it to work, always report it on the open-source repo and GitHub. We might not know if you don't tell us. That's one. Second one is documentation. We have a getting started guide for Flutter and Firebase in the Firebase documentation on Firebase.Google.com, but after that, the best documentation lives at -- and I need to always check because I have this tab open all the time. It lives on Firebase.Flutter.Dev. I never have to type that one. That's where you find really great documentation tailored to Flutter usage. Highly recommend checking that out. One of the great things about that documentation is that it's also open source. If you find a mistake or think we could explain something better, that's great. We're looking for an issue report or a pull request. Third one is other things, other materials that we create like video content. And last year you might have seen that we've been doing from the Firebase side more Firebase Flutter content. We've done a few code labs. I've done a live coding talk at the Firebase summit. And then let's see. One of our developer advocates. He's about to teach a series on Flutter application. I realized that might not be announced yet, so let's just keep it a secret between us, right? But, yeah, so clearly, right, we are working hard to support more of Flutter. Many Firebase team members love Flutter. Probably as much as many developers out there. We're great fans and we can't wait to bring more of Firebase to more of Flutter >> Andrew Brogdon: Awesome. Well, thank you, Puff. Much like Flutter is open source pretty much completely, same is true for a lot of Firebase stuff. Like these plug-ins for Flutter Fire, people can get involved in they want to, right? >> Frank van Fuffelen: Exactly, yeah. Most STKs are developed in the open, so we're always looking for people to either contribute there or just tell us if something doesn't work. We test a lot, but we might not catch all bugs that you encounter. >> Andrew Brogdon: A great bug report can make a world of change. Awesome. Well, thank you. And thank you again to poignancy, hopefully that was a poignant answer. Next question comes from Netlinx. This looks like it might be one from Ian. With more than 8,200 open issues on GitHub, Flutter seems a bit understaffed. Are there any plans to improve the situation or what are your priorities? Ian, as Tech Lead, you're in charge of our processes. Do you want to talk about issues and how they're managed? >> Ian Hickson: Yeah, sure, so we have, as Netlinx says, we have 8,000 or so open issues, but the important thing is that we are resolving issues about as fast as we're getting them. So, for example, last year, we had about 15,000 issues filed in our GitHub Rrepo and closed about 15,000 issues. We're happy with the rate we're fixing bugs and solving bugs. The number of issues is more a marker of how many users we have. Because the more users we have, the more bugs get filed. And the number of issues we're resolving is more a marker of how many people are contributing, and we have quite a few contributors. We have over 200 people who are officially part of the Flutter hackers group on GitHub. More than half of though are part of the Google team. Most people contributed to Google are not, in fact, part of the Google Flutter team but the open-source project, they might be from Microsoft or Canonical or volunteers working on their own time. Different people have different amounts of time they're spending, contributing to the project, but hopefully we'll be able to get more issues resolved to make Netlinx happier. >> Andrew Brogdon: Well, there you go. All right. Again, thank you for that question, Netlinx. Looks like we have one for Mariam coming up. This came out on Twitter as well. When will Flutter Web drop the hash in the URL and why does it exist? That pound sign you see at the end of the URLs. >> Mariam Hasnany: That is an excellent question. Okay. So let's start with the why does it exist. So, today, we use something called the hash URL strategy, and that is something we initialized when we are initializing the web engine. So what that means is that when you have Flutter named routes, we're basically initializing those as part of the hash that's attached to the URL. But now, today, with the stable release, we have a way for you to customize that URL and drop the hash from the URL, that way you can make your URL any way that you want, configure it with any other sub-URLs you need to be able to deep link or share the URL with friends and family. And users. But then also, we have a plug-in that somebody in the community has created, so thank you. It's called URL Strategy and it basically does what the instructions we also have in our documentation do, but just in a very easier way. You just put in your pub.dev and you're able to configure your URL and drop the hash. >> Andrew Brogdon: Awesome. Thank you, Mariam. Yeah, I know we've gotten some questions on that before, so I'm glad it came up today. Let's see what else we've got. This one comes in from @Silvioplas. Flutter is still having lots of compatibility issues with the new Macs M1 architecture. Are you working on some solution or should I buy an old Intel Mac? Eric, maybe this is a good one for you. >> Eric Seidel: I guess I would start by maybe saying you don't need to buy a new computer. So I would encourage you to try again today. There's been a whole lot of improvements to the M1 support as part of the Flutter 2 release. And also I'd start by saying that advancements to platforms like M1 on the Apple side or things that come down from Android or other vendors are things we address immediately. We learn about the M1 the same time you did. We ordered an M1 dev box the same day they were available and have been working on them since. We broke it down into three buckets. Which is do apps run well, do the tools run well on the M1, and the third bucket being, you know, can we develop our own tools on the M1? And the first two buckets, as far as I know, everything should pretty much work. Certainly with the Flutter 2 that came out today, certainly if you are hitting issues with the M1 or otherwise, we want to hear about. As Ian alluded to, we get a lot of issues every day, we triage them, and we want to address them as soon as possible. So, yeah, try again with Flutter 2, but I also would expect it to work well, and it's going to continue to get better as we make more, you know, code changes. >> Ian Hickson: What was interesting with the M1 is it was almost a whole new platform for us because we'd never done ARM as a host before. We announced today Web and desktop, but, really, Apple Silicon was its own platform that we had to support, which is harder to get big banner messages for, you know, we now have support for the current macOS release, but it is still a significant amount of work. >> Andrew Brogdon: Yeah, you sort of have to build that up from the ground level up, right? Make sure the Dart and the VM and all of that's working and then the embedder's working and go up through the layers of Flutter from there, right? >> Ian Hickson: Exactly. >> Andrew Brogdon: Very much like you would end up doing for a new platform. Thanks, Silvio, hope that gives you confidence about the M1 architecture. Thanks for the question. All right. Next up. Do the Flutter Dart teams ever plan to add official guidance for app architecture? Similar to Jetpack in Android. Ian, you might want to talk about this, and also sort of how we -- where we decide to offer guidance and where we don't. That's an interesting question, too. >> Ian Hickson: I'm laughing because you're throwing this to me as if you don't know the answer, but you and I have been talking about this for several weeks. Yeah, we have, in fact, just I think either today or very soon we'll be land a new template into the Flutter master branch. And that template with be basically an answer to this question. It's, you know, how do you create an app with all the best practices, you know, State restoration, how do you have your app State and so on? It's not the only answer to the question. The whole point of programming is there are many answers to these questions and different apps have different need, but we hope this particular template will really help here, and we might create other templates in the future for different types of architectures. Maybe you'd rather use redux instead of what we have in this template. This didn't land today for Flutter 2, but hopefully will be in the next stable release in the next few months. >> Andrew Brogdon: Awesome. These concerns show up for developer Relations, my team, all the time. Where are we really being useful by saying to people this is the well-lit path and we recommend it, and where would we be cutting off people from their own ideas that might, in fact, be better in the long run, right? We took a long time before we ever sort of anointed a State management approach as a good one for beginners. We settled on Provider which is a great package from Remi. We didn't want to solve that problem in a way that would stop others from solving it in ways that might be better. Awesome. Okay. Let's see what we've got coming in on the chat. This is from Khalid. Well Null Safety break existing apps? Is there some stuff that needs to be migrated? Who might want to take that one? Eric, do you want to take a stab at it and you certainly know a lot about Null Safety. >> Eric Seidel: The issue is you should be able to migrate. There is even a tool that you can use. I believe it's called Dart Fix and you can run it on your code base and it will help you go through changing your mode to make it Null aware. Ian might have more to say. >> Ian Hickson: Dart Migrate I believe is the tool. It will run. It will give you suggestions. If you look earlier in the Keynote, we have a whole section about how it works. The idea is it should not be breaking. You really would like your dependencies to be migrated first. Your life will be hard if you migrate before your dependencies migrate. It's possible, but it will be less effective. So, you know, if you have a package that you're using that isn't migrated yet, go ask the developer of that package to migrate. But otherwise you should be good to go, and, yeah, it should not be particularly break. As was mentioned in the Keynote, this is why we're not calling this release Dart 3. It's backward compatible with Null Safe Dart s like any other language, you decide which language version you want to roll with, Dart 2.0 or higher, you're in. We went through this in the Flutter samples repo, as Ian was describing. We looked at our samples and how many had a dozen dependencies and how many had zero dependencies? We sorted them in the spreadsheet by that and started at the top and went down from there. So we're actually literally right now landing those in the Flutter sample repo now that the release has gone out. >> Ian Hickson: The other good thing about the way we deployed Null Safety, is you can literally compile an app with non-null safe code and safe code simultaneously, and the compiler will use Null Safety optimizations and the ability to know what the types are when it's compiling the null-safe code. When it has a boundary to non-null safe code, it will add Null checks for you. We call this non-sound Null Safety, if I remember correctly. And so you can -- you can run your app in mixed mode, essentially, with both types of code in there, and that should work fine. >> Andrew Brogdon: Awesome. Yeah, I know the Dart team is very specific about the sound Null Safety is the particular type that Dart offers. Which has some advantages. Once you have that for your code, there are a lot of checks you don't have to make anymore and can make your code faster and tighter. I imagine there will be much more detail in Leaf's talk later today. Those interested in Null Safety or going to want to stay on the line for that. Thanks. We've got another question. Is Flutter good for 3D rendering? That's an interesting question. Puff looks like he's interested in. I don't know, Eric or Mariam or Ian, who would be interested in that one? >> Eric Seidel: I can take it. We've built Flutter as a 2D system. That said, lots of people have done 3D with it. The APIs we provide are for drawing 2D objects on a screen for a typical mobile app. The transfers do support 3D. People have done 2 1/2D or 3D setups. Also, Flutter -- the Flutter content itself can embed other textures, other open GL textures. Embed into the rest of your phone app. We've seen folks do that. In fact, in the Keynote, I think there was this mention of the Wallace & Gromit app at the end. It has 2D and 3D in it. Mashing the two together is possible, but, again, the bulk of Flutter is designed to run a 2D experience. >> Andrew Brogdon: I believe Grant Skinner who everybody saw in the Keynote doing wonderful things with flutter folio did some vignettes. Some of them had 3D elements, just spicing up and adding interesting design aspects to what otherwise would be 2D app UI. I believe you can find those on gskinner's site. Awesome. Let's try another live question. What about Flutter for Desktop? Ian, maybe, do you want to talk about where we are on Desktop. >> Ian Hickson: Yeah, Flutter for Desktop is available now in the stable channel, although we don't consider it to be fully stable yet. We support macOS, we support Windows and we support Linux currently. What more is there to say? We don't support necessarily all the features you might want. For example, we don't yet have support for multi-window, although that is come. We have some efforts coming there. Support for your basic one-window app is pretty solid. There is an app I wrote for solving Sodukus that I run regularly on my Mac and it works great. >> Eric Seidel: Yeah, I would say a little more. One of the things I love about Flutter Desktop and it being available in the stable channel, it's just so nice for development. You just turn it on and Flutter run and, boom, it's right there. And it's great for that sort of workflow. So, yeah, try it, check it out, and send some feedback. Oh, I guess one other thing I'd say, it's been amazing to me the overlap between Flutter Web and Flutter Desktop. We think about the Desktop work splitting it into two camps. How teach Flutter what a mouse and a keyboard are. But then there is also the other part, like, how do you teach the Flutter engine to run a really big phone that is plugged into the wall? And, you know, that comes in Mac, Linux and Windows flavors. And that sort of engine-level work is sort of what Ian was alluding to. Like, we have an engine for Mac. We have an engine compiled to Linux. That's maybe less far along than the, like, can you use a mouse and keyboard with Flutter, which you can, because we've put it on the web now. >> Mariam Hasnany: Yeah, I would add to Eric exactly what you said. A lot of what we needed to do to make web stable was to have those Desktop form factors supported. Be able to use your track pad, your scroll wheel, your keyboard to interact with your web app on Desktop browsers, but I'd also look at gskinner flutter folio, and you can see how you can build mobile, web and Desktop apps across the board and how those features go across those three different platforms and where to use each of them. >> Ian Hickson: It's actually interesting to look at why we haven't yet labelled Desktop as stable, and two of the big reasons are we don't have good testing on our own side to make sure that we don't regress Desktop when we add new features. And that might not matter so much to someone writing a Desktop app, but it matters to us because we want to make sure when we write new code for Desktop we don't break things that already working. The other big thing we don't have support yet is accessiblity. We are working on that. We have code for that it wasn't available today, so that's why we don't see it as a stable product. It's still a beta-level product. But, again, if you have an app that you don't need accessibility support for, maybe running it on some sort of kiosk or something like that, that may be less important to you, but we consider those two features in particular to be really critical before we're willing to put the label "stable" on anything. >> Andrew Brogdon: It's a lot of responsibility to make sure you're not breaking six platforms as opposed to not breaking three platforms, right? >> Ian Hickson: Yep. >> Andrew Brogdon: One thing I wanted to make sure folks are clear on. You mentioned that the Desktop Support, the beta snapshot of Desktop is currently available in the Flutter 2 stable channel release, is that right? >> Ian Hickson: I believe that is accurate. >> Andrew Brogdon: Okay. And so that's so people can just have an easier time trying out Desktop Support as it exists now right from the same version of the STK they currently have installed, right? >> Ian Hickson: Right. >> Andrew Brogdon: Awesome. >> Mariam Hasnany: Yeah, so if you want the latest of Desktop, it's better to use it on beta, because that's where the updates will be, but you're just going to get a snapshot of what it is today on stable. >> Andrew Brogdon: So if you have an existing app or just kind of want to see what it looks like on Desktop, sounds like you can do that right from the stable channel, but the latest and greatest would either be on Dev or on beta. >> Eric Seidel: There is something really magical having written an app for, say, Android and running it on your Mac and it just works, and it's a very weird experience to have done that. I haven't experienced that before. You know, with the web, you kind of have that when you write your web app and works in one browser and works on a different browser in your laptop and on your phone. It's really kind of a magical experience to have that with a Native app. >> Andrew Brogdon: Absolutely. Awesome. Thanks. Well, hopefully that was a lot of detail for you about Flutter on Desktop. Let's take another live question. What is the best way to learn State management packages like river pod? This is sort of an interesting question about how to approach -- maybe that's a Dev -- would anyone be offended if I took that one, even though I'm the host? I'm not really supposed to answer questions. Is that okay. >> Eric Seidel: Please, I was hoping you would take this one. >> Andrew Brogdon: Fire away. This is my jam. One of the -- I would say the best way to learn anything with Flutter is to just start coding. That's how I've done most of my learning with Flutter. One of the nice things about Flutter being entirely open source is when you do run into a crash or something like that, you can go really far down into open-source code before anything would stop you. This is how I learned most of the Flutter STK, and river pod, which is made by Remy, also very good about documenting his code. If you ever run into any issues while you're playing around with it or just having some fun, you can go straight into the source and see his Dart.comments and see how everything works. Also, one of the wonderful things about Flutter is we have a global developer community who are fun and energetic and welcoming. Not only are they happy to answer questions generally on sites like Stack overflow and things like that, but a lot of them are on YouTube putting out video, putting out blog posts and stuff like that. River pod has attracted a bunch of users. You can find a bunch of resources from people who are a few steps further down the road on their learning journey with that particular package than you are, and they've turned around and offered help to you along your way. So, you know, the best way to do a search on YouTube, do a search on a vlogging platform of your choice and odds are you're going to find some folks who have already tried whatever it is you're interested in learning and have left some bread crumbs for you on your own journey. Yeah. All right. Let's see. I think we got -- let's go back to some of the questions we got earlier on Twitter and YouTube. This is one -- this is clearly a Mariam question. What about SEO in Flutter Web? Is it supported? If yes, let us know. Thanks. What do you think, Mariam? >> Mariam Hasnany: I had a feeling this question was coming. So, Flutter started as a fork of Chrome, and so indexability has, like, always been on our mind. It's just with this release specifically, we really optimized for web applications and focused on customers our early adopters that were already building applications with the web. That being said, although indexability is something we're looking into, it is a lot of work to get supported, and so if you are looking for building very document-centric, very text heavy and just websites that need that SEO support, Flutter might not be the right choice for you currently. We do have ways that you can access the browser in DOM because we do use the web platform, and that is what Flutter Web is built on. So there might be ways that you can find to embed those APIs in the meta tags that you might need for SEO using things like platform views, but as of now, we are looking into it, and we would love to understand what exactly your use cases are, how you use SEO today. So file issues on GitHub so we can learn more. But it is -- it is on our roadmap. It is something we'll look into. But as of today, we're best for web applications. >> Andrew Brogdon: Awesome. Thank you, Mariam. And just to echo what you said there at the end. Filing issues, uploading issues and adding comments and context to issues, that's one of the best ways for developers to sort of steer the STK and provide their input. Do I have that right? >> Mariam Hasnany: Exactly. A lot of -- oh, sorry, Ian. >> Ian Hickson: Oh, go ahead. >> Mariam Hasnany: I mean, a lot of what we built for Flutter Web is from hearing what our customers needed at the time that they were building the beta and the tech preview. So the best way to shape our future stable releases is to tell us what we can work on. >> Andrew Brogdon: Awesome. Ian, did you have anything to add there or does Mariam pretty much got it? >> Ian Hickson: No, that was pretty much is. We very much use the issues as a way to prioritize. We look specifically around thumbs up on issues because GitHub makes it really easy to sort by thumbs up on the first comment and issue. So, yeah, definitely thumb up issues that you like, file issues if you can't find one. That is the best way to help us. >> Andrew Brogdon: Awesome. >> Eric Seidel: I don't know that it's -- I was just going to say, I don't know that it's commonly understood how open Flutter is because I just don't -- not all projects are run this way. All our design docs are public. All of our issues are public. Basically when we do anything, we do it in the public. Yes, there may be a lot of issues to look through and, you know, to find the issue that you want, but it's all done in the public, and so, you know, you can watch us do it or you can contribute and, you know, join forces and help us make it better. >> Ian Hickson: Yeah, I come from a long history of open source and open standards, so I've been trying really hard to push that culture in the Flutter project, and I think pretty successfully. We have an open Discord where all our conversations happen. An open GitHub where all our issues happen. Our project planning happens in GitHub Projects. Design docs are in public Google Docs. So, yeah, we are very much an open project, and if you're interested in contributing, we have a contributing guide on GitHub. Check it out. Follow the links. >> Andrew Brogdon: Awesome. Thank you. So, hopefully that gets a good answer for search engine optimization there and a little bit on contributing. Let's take another one from YouTube. When will the problem of janky animations on the first opening of an app be resolved? Eric, on GitHub issues, I think I've seen you doing some stuff on this. Do you want to take this one? >> Eric Seidel: This has been a popular topic, particularly the past few weeks. I wrote a long post on Reddit. I'm working on a longer blog post. I would open by saying performance is something like a grounding principle of Flutter. When we first talked about the project five-plus years ago, you heard us talk first about performance. When you hear us talk about the pillars we're trying to accomplish, performance is, you know, the number one. That's not just, you know, that's not just words, like, we back that up by, you know, every commit that's ever checked in is compared against all sorts of performance tests across the board, across all the platforms. Performance is something that we strive for. We drive towards every day. Specifically regarding to Jank and first-run animations, that's an issue that we have been aware of for a while, and particularly on iOS, it did get worse in some scenarios within the last year. With the migration from OpenGL to Metal where we're no longer able to Cache the programs you have to run on the GPU to produce the pixels. We're no longer able to Cache the shaders between runs like we were before. So the short and the long of it is that we are aware there are issues here, and we're hard at work on it. Lots of people working on this problem. Ian's working on this problem. By this problem, I mean the general problem of performance and how do we make it better all the time? We think we're doing pretty well, and we can always do better. >> Ian Hickson: Yeah, around what I've been calling the early onset Jank issues, it's very much something I'm focused on right now. You look at GitHub project 188, I remember the number by heart because I open it up so often. That's where I've been tracking all the bugs about this. The best thing you can do, to echo what we just said in the last question, the best thing you can do to help us here if you are seeing Jank at the start of your application, please file a bug with code that reproduces the problem, include a video showing the Jank and include a timeline trace showing what your app is actually doing during that video. That is by far the most helpful thing you can do because we can study that particular case of Jank. They're not all caused by the same problem. Even if they're caused by shaders they're not necessarily caused by the same shaders. We have examples of early onset Jank caused by one particularly pathological shader case. We haven't specified the shader based on the rounded radius, so every frame during animation, we have to compile a new shader. So those different bugs will be solved with different problems. One of them presumably by not specializing the shaded base and the other one might be solved by fixing the code we're writing for that particular shader. But we won't know what your specific Jank problem is unless you file a bug that we can look at >> Andrew Brogdon: Yeah, I mean, performance is sort of -- I would say it's a multi-variable equation, but that's not giving it justice, right? There are so many variables that go into that and so many special cases so, again, this is absolutely an area where we can use some great help from our community. Awesome. Let's see. I think we have another question relating to Flutter Web. How does Google plan to use Flutter Web internally? Eric, you speak to the team a lot internally, talk to other groups. Do you want to take this one? >> Eric Seidel: So I can't, you know, speak to other teams' plans, per se, but I can say there are a number of teams that are experimenting with Flutter Web today. Flutter Web just came to the stable channel today, and similarly, we've been giving similar guidance to internal teams that, you know, we're still working on things. So, there's nothing to announce today, but I do expect to see more usage of Flutter Web. I mean, Google engineers have similar constraints to any engineers listening. We have to write to lots of screens. I'm working on this project because I believe it's a better way to develop when we write our code once and then we get to deploy it lots of places. And so I suspect that we have seen -- we have seen a lot of Google teams adopt that strategy already with Flutter, and I suspect we will see even more as Flutter continues to go to more places. >> Ian Hickson: We've also seen for Flutter for Web being used for internal tools. Where there isn't necessarily a big team behind the tool and they need to create something that is useful and productive quickly. And so, for example, just on the Flutter team, for example, we use Flutter Web for some of our internal tools for migrating the public Flutter code into our internal repository for teams like G Pay and other teams to use. The tool that does that itself is written in Flutter. >> Mariam Hasnany: We also -- to add to Ian, we also use Dart DevTools is built in Flutter Web. We hope to showcase using Google technology both internally and externally, because that same tool is available internally as well. >> Andrew Brogdon: I actually used Flutter for Web to build an internal tool myself. Now that I'm a manager, I was -- I made a little tool to help people get GitHub searchs to see what pull requests they've done over the course of six months or so. And Puff, this may be interesting to you, I actually deployed it to Firebase Hosting and the new thing y'all have that puts, like, automatic GitHub actions into your project. Took, like, five minutes for me to get, like, from my laptop up online at web.appdomain. So I don't know who works on that, but give them two thumbs up. It was awesome. >> Frank van Fuffelen: Definitely one of the popular features we released last year, right? You can form a GitHub action, automatically create a URL in Firebase Hosting, a preview URL or a live URL. That's really awesome. We see lots of that, yeah. It merges really well with Flutter Web, of course. >> Andrew Brogdon: Mm-hmm. Awesome. Okay. Let's take another question. This is from FluDev. Can we do mediation with AdMob in Flutter? If yes, then how will it be implemented? I think I just talked myself into answering a question again. Does anybody else want to answer this? I'm the weird oddball former ads person on the call. Maybe. Yeah, sure. A little bit of personal history, I came from Mobile Ads DevRel. How I ended up on the Flutter team. I work on the AdMob plug-in for Flutter. That's how I got hooked on it. As you saw, we had a wonderful announcement about the Google Ads plug-in today. Mediation is not listed as one of its features. I want to be clear about that. Because the plug-in uses the same Native STKs under the hood as you would on any other Flutter or Android or iOS app, mediation, it is in there, and you could in theory set up an ad unit and try to take advantage of it by bundling in the right Native STK and adapter. I should mention, by the way, for those of you unfamiliar with mediation, it's a feature that Google Mobile Ads STK can load and display ads from the Audience Network or Mopub or another one. It's not officially supported. The reason it's not officially supported has to do with testing. One of the reasons that the -- we're being -- taking so much care in putting out the Google Mobile Ads plug-in, if you're going to put out something in regards to monetization, it has to be right, tested and 100% you're completely confident it's right. It's really somebody's livelihood, right? If I have a bug in one of my apps, it crashes, somebody's sad for a minute. If you have a bug in your ads STK, it could mean that somebody's business is threatened or somebody can't keep the lights on in their office. That's a very big responsibility, and that's why so much testing and so much cooperation with the ads team has gone into the current release of the mobile ads plug-in, and that's the -- they're going to do with mediation before saying that it, too, is fully supported and ready for production. So it is on the roadmap, but I wouldn't try it just yet. That's my answer there. All right. Let's take another one. This one -- when will Dart support WebAssembly? Ian, I'm thinking this could be a good one for you. >> Ian Hickson: This could mean a number of things. We actually use WebAssembly today as part of Flutter for Web. Maybe Mariam can talk more about this in a minute. Basically, we have two other parts of WebAssembly that could be relevant for Dart. One of them is whether you could compile Dart itself to WebAssembly and the other one is if you can take code already compiled to WebAssembly and link to it from Dart. So for the second one, linking to WebAssembly code from Dart, I believe there is a package that already exists to load up a WASM Runway -- runtime and therefore let you connect to WASM code. It's not the most convenient way of doing it, but it works. The other way of using WebAssembly with Dart is compile it. That's not possible today. That's going to require features in WebAssembly that aren't mature yet, WebAssembly garbage collection, threading and so forth. These are things we're very interested in. I think WebAssembly has the potential to become really a uniform large interop technology in a few years, so I'm really hoping we can adopt that in Dart as well, but we're not there yet. And until will take some time, I think, to gather. Mariam, do you want to add something how we do WebAssembly with CanvasKit? >> Mariam Hasnany: Yeah, so we have two renderers for Flutter Web. We have our default, what used to be our default, HTML renderers. HTML and DOM back end in our web engine to render your application on the web. But we have been experimenting with CanvasKit, and today we have stabilized it so that you can use CanvasKit, which uses WebAssembly and WebGL to render your app as a Skia in the browser. And so with those two different renderers, we also have something called auto, and that's what we've set your -- all Flutter web apps to run by default. And auto basically means that we use CanvasKit on Desktop browsers, and we use HTML Renderer on mobile browsers, just to optimize for the benefits and the strengths of both. >> Andrew Brogdon: Awesome. Well, thank you, Mariam. Let's see. Let's take some live questions. We have about 15 minutes left, I think, in our block. We are still taking live questions from the chat and on Twitter using the #askFlutter. If we don't get to your question here, hopefully we'll have time to answer it after the fact. Let's take a live question. One word about Flutter Web in comparison to React and Angular. Let's see, Mariam or Ian, what do you think about that? What are some of the differences between those three things? >> Mariam Hasnany: Okay. Ian, did you want to take it or Eric? I feel like Eric has something to say. >> Eric Seidel: I think the first thing that comes to my mind, like, Flutter Web, we just draw it in canvas. We treat it like we have access to the GPU or CPU, which is I think different than how I see Angular and React working. That's the first thing that jumps out to me. >> Mariam Hasnany: I would agree with you. >> Ian Hickson: Sorry, go ahead. >> Mariam Hasnany: No, go ahead. You got it. >> Ian Hickson: I always feel reluctant to compare Flutter to other technologies because we all have valid use cases. Other technologies have valid use cases. I don't want to speak for React and say, oh, React is good at this but not good at that. That's really up to React. We are very happy to co-exist with these other technologies, and we hope that the community as a whole can write guides that say, you know, here is when Flutter is good. Here is when Flutter For Web is good, here is when React is good and so on. >> Mariam Hasnany: Yeah, I was going to answer the same way as you, Ian. I don't know if anyone caught Dion at the Keynote, but I think he put it really well, the web platform has opened it up to so many frameworks, and Flutter is just another one is taking advantage of all the web has to offer, and so we just want to see what you build with it, and we're going to try to suit it best for the things that you want to build with it. >> Andrew Brogdon: Mm-hmm. Awesome. Well, thank you, Ian and Mariam. Let's go to another live question. This -- I am on the beta channel right now. Should I go to stable channel? I think the gag here is that the beta channel just became the stable channel earlier this morning. Do I have that correct? >> Ian Hickson: That is right. It's really hard for me to answer that question because I usually spend most of my time on tip of tree on the projects I use. Which, of course, means half the time I'm broken, and the other half I use the absolute latest features. I'm really the wrong person to answer this. Eric, do you have opinions about what channel people should use? >> Frank van Fuffelen: I think it really comes down to your interest in update frequency and sort of how much testing is received. So say stable only updates about once a quarter, and many, many apps and many, many tests have run before that code is ever pushed to stable. Beta is updated about once a month. Also has a lot of testing. You know, both in terms of apps and tests. But less than stable. In part because as Ian says, right, we promote the best beta of the last while to be the stable. And similarly Dev, Dev is updated I want to say anywhere between about every day to at least once a week. And there, again, we go through a promotion process of, you know, picking the best recent Dev and making that the beta. So I think it's a trade-off, but I think most individuals probably want to be on stable or maybe beta. >> Eric Seidel: The big difference between -- >> Ian Hickson: The other big difference between stage and the -- stable and the other big channels, we'll cherry pick fixes if there is something egregiously bad. Ooh, we didn't catch that. We should have caught that. We will go and cherry pick a fix on to that stable release. So you'll see over the quarter the stable release gets updates, very minor updates, but updates for issues that we think are serious enough that they warrant an out of hand fix. That will not happen on Dev. We just don't -- we don't check on Dev. If something is broken on Dev, it will be fixed on the trunk and we'll do another Dev in a few days' time. And obviously that can't happen on the main line because that's where we're developing. So there's always a risk. The more recent the code, the higher the risk that something is wrong that we haven't caught. But, of course, there is always going to be new fixes there, so it's a trade-off. >> Andrew Brogdon: Mm-hmm. >> Mariam Hasnany: I've seen previously people were using the beta channel because Web was not available. So that could be a reason that you could switch to stable now because we do have Web and Desktop that you could run your app with. >> Andrew Brogdon: Yeah. >> Frank van Fuffelen: That very much applies to me, Mariam, indeed. I'm switching back to stable. >> Andrew Brogdon: In our samples repo, we had a whole bunch of samples for the Web we don't have to put a special notice on. By the way, if you're going to run this, you have to switch channels, because they're running in stable. Awesome. Thank you. Let's go to another live question here. When will you add data classes to Dart? Check issue 314 of Dart lag, which has a lot of thumbs up. This makes me wish Bob were here, but Ian or Eric, you might have a take on this. Mariam as well. >> Ian Hickson: So Bob really covered it in the Keynote. We are actively trying to find a good way to do this. We want to be really careful in how we do this. We don't want to add a syntax that works today but doesn't work in six months' time, doesn't work in two years, and we don't want to keep adding new syntaxes every few months or every few years just to end up with a lot of kind of obsolete language features that aren't used by anyone. So we're looking at meta programming. We're looking at ways that we can really handle a large number of use cases that exist today, and hopefully in an extensionable fact. We have no idea when this will be done. It really depends on what ideas we manage to come up with and how they work. We'll be doing a lot of testing for this. I'm sure if you follow the bugs, for example, the one that is listed here, which I'm sure I'll go and check out after this talk, I'm sure you'll see our progress there. >> Andrew Brogdon: This is -- this is another area where the fact that the Dart language team hasn't yet found the right way to step in and implement something, has also allowed other people to explore their own ideas, right? Like value, for example, can create -- a lot of classes like immutable and serialization. There are options out there for folks right now. Even though the Dart language team hasn't settled on what they feel the correct approach is for what they're going to implement. >> Ian Hickson: Yeah, and we have a relatively mature code generation mechanism in Flutter, but it's code generation, so it has all the downsides of generation, which is why we don't think that's the final solution to this problem. >> Andrew Brogdon: All right. Thank you for that. Let's see. Another one. What would be the best way to develop a Flutter app that needs to work online and completely offline? I'm guessing that's about data, accessing network data and maybe storing it locally and dealing with connection status. Puff, do you want to talk about this? This is kind of up your alley. >> Frank van Fuffelen: I think I saw it coming in. It's a great question. It's a bit more. Gathering data in an offline scenario. When you don't have a network connection and synchronize between the database when you're back online. There are many ways to do this. Some of them involve in Firebase, but also some that don't involve Firebase. I'll focus on the Firebase ones, but the same type of model works for many approaches. What's key here is that essentially when you use one of our Firebase databases, we have the so-called cloud fire store, they work in a very similar way. They keep a local Cache of any data that you've recently read from the database into your application. Keep in mind, these are cloud-hosted databases, right? Any data you've read from the distatabass kept in a local Cache. We can access the data if you restart while you're offline. That's one thing both of them do. That's what you want, right? You want that local Cache. You get to dealing with local right operations. Gathering local data and want to write into the database. In both cases, what both databases do is they keep a queue of pending writes. We essentially keep track of what have you written that we haven't synchronized to the server yet? And this doesn't affect your application. You still see the data as if it's been modified already on the server, but we then in the background actually check, hey, do we a network connection? Once we have a network connection, we start synchronizing all the changes to the server. That could lead to, for example, the server rejecting a change if the user is trying to write something they don't have permission to. We locally reconcile those rejections also. We fire events that you like and reflect the database state. That's actually one of my favorite things I always notice about using something like Firebase with a Flutter application, right, is the redactive -- reactive nature of this. I always love when you are connecting to a database. If I then make a change to the database, it also, snap, updates on the Flutter application. I really love that dealing with a database in a reactive way. So, great question. Thank you. >> Andrew Brogdon: I imagine your favorite widget is Stream Builder, right, Puff? >> Frank van Fuffelen: Very much between Stream Builder and Fu FutureBuilder. >> Andrew Brogdon: What is the difference between legacy version and Null Safety version while collaborating Flutterfire plug-in with Flutter? The existing version and the new safety versions, do you want to talk about the migration of those plug-ins maybe and where we are with that? >> Frank van Fuffelen: I'll completely admit I haven't check yet what's in the latest version. I know the team has been working on safety for sure. I don't know what you need to do yet. This is one I might have to come back to it on Twitter. I'm not sure. Ian, I saw that you also commented on this, so I'm not sure if you have any more information, or if not, I will get back on Twitter, for sure. >> Ian Hickson: I believe the Flutterfire plug-ins are -- I'm not 100% sure. We've been tracking all the different plug-ins we release and make sure they're all updated. There's a lot. I've lost track which ones we've migrated and which ones we haven't. >> Frank van Fuffelen: I saw a lot of releases, I just didn't have time to check as a developer what you need to do for them. I think those also went out today. >> Ian Hickson: If they're not out today, they'll be out very soon. >> Andrew Brogdon: Cool. Well, there you go. Let's do one more live question. What is a good IDE for Flutter? That's going to have about as many answers as there are people on this stream, I think. This could be -- this could be fun. I use IntelliJ Idea. That is my preferred one. Eric, what do you use? >> Eric Seidel: Mostly I use VS code. I've used Android Studio some, too. But the coding I tend to do tends to be more VS Code Eric, you have a favorite, I presume. >> Eric Seidel: I Use Emax and you'll pull it out of my cold, dead hands. >> Andrew Brogdon: Mariam, what about you? >> Mariam Hasnany: Okay. So, as a PM, I use all possible just to make sure things work. But I did, when I joined the Flutter team, I did start with Android Studio. A lot of tutorials set you up that way. Then I moved on to VS Code because that's what I'm used to. Recently I've been testing out IntelliJ making sure our core new Inspector widgets and stuff like that work with it. >> Andrew Brogdon: Awesome. And Puff, any preferences in the Firebase team? >> Frank van Fuffelen: I mostly use Studio Code, but I have a soft spot for DartPad also. Tinkering widgets without having to open any IDE, it's one of my favorite things. >> Ian Hickson: A more serious answer to this question is we really try to make sure that all of the IDEs can work with Flutter. We have an open kind of API that you can talk to if you're an IDE, and that's how all of our plug-ins talk to the Flutter tool. So there is very little be sspoke code in the ID about running Flutter and so forth. This means if you have an IDE that doesn't yet have a plug-in, it's possible you can write a plug-in for that IDE using the Flutter tool. It also means that if you have an IDE that you want to use that doesn't really have strong Flutter Support, you can use it from the command line. All the same things the IDEs use are possible from the command line. Fixes and refactorings. But even, for example, our analyzer tool has a mode in which it operates at the command line live, so it's just running the analyzer continually in the background. That's actually what I use with Emax for example. >> Andrew Brogdon: I know there are some dedicated users. I first learned that talking to Hans on our Design Framework team. I referred to it as VI. He very quickly corrected me. In a nice way. Hans is a nice guy. Not a -- it was a learning moment for me. And speaking of learning moments, we have had one over the past hour. And now it's the end of our time. So, first, let me say thank you to our four panelists here. Thank you so much for being with us here today. >> Eric Seidel: Pleasure, Andrew. >> Andrew Brogdon: I want to say thank you to all of our stream viewers here. Hopefully you enjoyed what you just saw. We have a lot more coming for you. This is the end of our Q&A. If you stay on the stream, we have four tech talks from the Flutter team coming to you. These will provide more technical detail on some of the exciting features and announcements you saw during our Keynote, and then after those, we have 11 more talks from Flutter's global developer community. These are Flutter coders who have put together tech talks going into all sorts of things from navigation to animations, deep dives into all sort of Flutter tech. Those will be up on the website as well. There will be a content drop for those. So, but first up, we'll be having Mariam Hasnany back with us again along with John Ryan to present from mobile app to Progressive Web App. They're going to go through the process of taking a Flutter app that works on mobile and deploying it to the web. So stay right here. We have a lot more Flutter to show you. [ Upbeat music ] βͺ >> John Ryan: Hi, I'm John, a Developer Relations Engineer on Flutter team, and joining me today is someone who also works on Flutter, Mariam. Hi, Mariam. >> Mariam Hasnany: Hi, John. Hi, everyone. I'm Mariam, a Product Manager for Flutter. >> John Ryan: So, Mariam, you're actually the Product Manager for Flutter on the Web, which is what we're going to talk about today. >> Mariam Hasnany: Yeah, I'm so excited to be here and work with you, John, to get a Flutter app running in a web browser and deploy as a Progressive Web App. >> John Ryan: Me too. Actually, before we dive in, Mariam, can you explain why we added Web Support to Flutter? >> Mariam Hasnany: Sure. As some of you may know, Flutter started as a UI framework for building beautiful iOS and Android mobile apps, like the ones you see here, but our vision is to provide a portable framework that helps developers build beautiful, Natively compiled applications for any platform. And since the web already runs on any device, targeting the web felt like a natural next step for Flutter to achieve our goal, enabling you to build high-quality, high-performance experiences across multiple platforms. So, with today's release of Flutter 2.0, we now have production-quality support for the web on the Stable channel, which means you can build apps for iOS, Android, and the browser with the same code base. >> John Ryan: That's super excited. So now I can run Flutter apps Natively on my phone and now in a browser? >> Mariam Hasnany: Yes, and emphasis on apps. While you can do a lot on the web, Flutter's initial stable release is best fit for building web applications, not static content websites. >> John Ryan: Okay. So maybe I should keep my landing page for my site in HTML for I want that to play nicely with search engines, for example? >> Mariam Hasnany: Exactly. We see Flutter being a great fit for apps that can be installable Progressive Web Apps, a rich, interactive single page app or even an existing Flutter Mobile app. So, John, what web app should we build today? >> John Ryan: I've been updating the DashCast app, which is a podcast app. So, first, let's walk through some of the features on the iPhone. So this page loads podcasts using HTTP and JSON. It also uses this custom font here using the Google Fonts package. As you can see, it uses material design components like ink splashes right here, animations, and if I go to a podcast, say this one, you can see I'm using the URL launcher plug-in to open links using plug-ins which operate on the host platform, either Android or iOS. >> Mariam Hasnany: That's pretty cool. And I'm not just saying that because I like the name of it. It would be awesome if I could use that on my laptop. I think having it run in the browser would actually let me use it on any device. >> John Ryan: Yeah, that sounds great. So what do I need to do? >> Mariam Hasnany: So, with the stable release, the web is just another device target now for Flutter, so like you see iPhone or Android listed as devices in our IDE, you should also now see Chrome or Edge if you're on Windows, so all you have to do is run Flutter Create, and that's going to generate the web directory, then select Chrome as the device and then hit run. >> John Ryan: Okay. So let's see if we can do that. So I'll open my terminal here, and I'll run Flutter Create and I'll pass at the current directory to recreate this project, and once that's done, I should see a web directory with an index HTML file, and I can see that right here. So, now I'll select the Chrome device and hit run. >> Mariam Hasnany: All right. So running the app for the first time takes a while to load because Flutter is launching the application using the Dev Compiler Dart Dev C to run in debug mode. The first compilation takes the longest because it needs to compile the entire app. >> John Ryan: Cool. So on the web, Dart uses different compilers, right? >> Mariam Hasnany: Yeah, for our mobile apps, we have a GIT compiler and an AOT compiler that converts your app into machine code or ARM. Similarly, on the web, Dart uses the Dart Dev C and dart2js compilers which convert your app into JavaScript. So having separate compilers for development and deployment will give you a fast dev cycle and also make sure your production app runs as fast as possible. >> John Ryan: So since the Flutter framework is written in Dart, the entire framework can be compiled into JavaScript, right? >> Mariam Hasnany: Yeah, just like you said, the Flutter framework is built using Dart, and so your app that sits on top of the framework. So all we had to do to add Web Support was replace the low-level C++ rendering engine that's used by mobile apps, and instead map to browser APIs DOM or WebAssembly to render your web app either using HTML or CanvasKit. >> John Ryan: So, the only really different between Flutter mobile apps and web apps is that underlying engine that they use? >> Mariam Hasnany: Yeah, our motto for the web is not two separate frameworks that look the same and use the same language, but actually a shared framework across platforms, mobile, web, Desktop, et cetera. So when we improve features on the Flutter framework, all platforms get the benefits. >> John Ryan: Okay. So that's why I don't have to change any of my apps' code. The framework APIs are the same. So I've got the app running now. Are we done? >> Mariam Hasnany: Well, there are a few things I like to consider when building a Flutter web app. So, first, especially when you're bringing an existing Flutter app to the web, you want to check if the plug-ins are supported for the web. Flutter plug-ins allow you to talk to Native libraries for the platform you're running on. So when you're running your Flutter app on the web, you can get access to existing JavaScript libraries through these plug-ins. >> John Ryan: Okay. So I'm using URL Launcher, so let's check if URL Launcher is supported. I'll go to pub.dev and I'll just search for the plug-in or package I'm interested in. And I can see here this label at the bottom. It's got the different platforms that are supported. So it's got Android, iOS, and it is supported on the web, but what do I do if my plug-in isn't supported yet? >> Mariam Hasnany: So, you'll actually want to add Web Support for that plug-in, and you can find instructions for upgrading your plug-in to include Web Support on our blog site. >> John Ryan: Great. So since URL Launcher already has Web Support and I already have it in my pub spec for my mobile app, I don't actually have to change anything? >> Mariam Hasnany: That's right. For most Google plug-ins, we do all the work behind the scenes, such as wiring up To JavaScript libraries so the plug-in works as you'd expect on both mobile and web. >> John Ryan: Right. And sometimes a plug-in will require some JavaScript to work. If I open up Index HTML here, you can see that I imported some JavaScript to make it work. So I have all the plug-ins working for both mobile and on the web. What's next? >> Mariam Hasnany: So, now I like to think about layout. Web apps can run on many different form factors and it's important for our app to adjust the UI accordingly. >> John Ryan: So I need to think about layout for different screen sizes? Cool. So, the homepage needs some work. Let's change the bottom section to use a twoColumn layout here. For this, I'm going to use a layout builder, and I'm going to check the constraints, so I'm going to go to this podcast column here, and I'm going to change this PodcastList to a LayoutBuilder. So I'm going to type in LayoutBuilder, and that takes a Builder parameter, which is a call back, and that call back takes two parameters. One of the parameters is the build context, and interestingly we get the constraints here, and the constraints are the incoming constraints that the layout system passes to this portion of the widget tree. So I can actually check the constraints. I've already kind of set up the twoColumn layout with my podcast list, so what I'm going to do is I'm going to just add this back in, return this PodcastList and I'm going to use the constraints to set this twoColumn parameter here. So I'm going to set it to a twoColumn layout if the constraints maxWidth is greater than 700. So I'm going to reformat, and now that I've made that change, how do I restart the app and see the change? >> Mariam Hasnany: Great question. So you can trigger a hot restart for web apps, which basically means that you don't have to restart your app and wait for it to recompile everything and load again. It's just a fast way for you to see changes. So if you make a small change, the Dev Compiler is smart and only recompiles the JavaScript that was affected and then pushes only the deltas to the browser. So, this works similarly to the hot reload feature for mobile development. The only difference is that hot reload remembers your State and hot restart does not. >> John Ryan: Cool. So if I restart my app here and open up the browser, I can see that the changes show right away, and I can resize the window here manually or I can open up the Chrome DevTools and click on this toggle device tool bar button, and what that allows me to do is demo this app on different device types. In this case, it's A Pixel 2. >> Mariam Hasnany: Wow, that looks so much better on every screen. By the way, there is more info on building responsive UI on flutter.dev/docs. So, John, the next thing to think about is navigation. >> John Ryan: Sure. I've actually set up deep linking in my app using Navigator 2, so on the web, if I navigate to a specific page, the URL and the URL bar updates. I can also navigate to specific pages by updating the path and the URL, or if I were to click on a link, it would update the page. This would also work if I were using named routes, but I'm using Navigator 2 here, and if I click the back button, it takes me back to the previous page that I visited. So I changed the podcast from 1 to 2 here. If I click the back button, it's going to take me back to the first podcast. If I click the back button again, it takes me back to the home screen, and if I were to click on a podcast like this, click the back button in the app, and then click the back button in the browser, it takes me back to the previous page I visited. So this looks better already. What other things can I do to make my app feel right in a browser? >> Mariam Hasnany: Well, since our app can run on Desktop browsers as well as mobile browsers, we should also consider adding scroll bars and mouse or keyboard interactions for the Desktop. >> John Ryan: Sure. Let's add a scroll bar to our list view in this page, for example. So if I go to the widget for that page, the episode list, and I wrap this ListView in a Scrollbar by typing wrap with widget, Scrollbar, and hot restart the app, I should be able to see this page reload, and now I get this nice Desktop-style scroll bar on the right-hand side. And you can also see that my curser changes from a normal pointer to this clickable pointer, this click pointer, and that's a piece of the framework that uses the mouse curser widget. So if you want to do this yourself, you can use the mouse region widget and provide the mouse curser that you want to display when you hover over that widget. So, to add keyboard shortcuts, I also used the shortcuts widget here. So I can actually play and pause this podcast using the space bar. >> Mariam Hasnany: All right. That's looking good. So, finally, you'll need to think about what rendering mode will be best for your app. Unlike Flutter mobile apps that just use Skia to render, there is actually two renderers for web. There is one HTML which uses DOM Canvas APIs, and another one, CanvasKit, which uses WebAssembly and WebGL to render Skia paint commands. >> John Ryan: So how do I know which one of those two renderers I should use? >> Mariam Hasnany: Well, by default, the render mode is set to auto, so this means that your app runs with the HTML renderer on mobile browsers and CanvasKit on Desktop browsers. This is our recommended combination to optimize for the characteristics of each platform. >> John Ryan: That's really cool. So what if I set the renderer mode to either HTML or CanvasKit. How do I know what the difference is between those two? >> Mariam Hasnany: So, HTML allows you to optimize for download size and uses less bandwidth. That's why we think it's better for mobile browsers. On the other hand, CanvasKit is faster. So if you have larger screens with a higher number of widgets showing per frame, that's what it's better for. >> John Ryan: Gotcha. So I think it makes sense to use auto in this case, since I'm rendering quite a few widgets on Desktop screens, and on mobile browsers, if I were to load this in iOS Safari, I would want it to load fast. So if I'm debugging, how do I know which one of these is running? >> Mariam Hasnany: So, if you inspect the body tag in Chrome inspect source code, you'll see a class, FLT-renderer, that's going to either show you CanvasKit or HTML, and then let you know if it was set automatically or not. >> John Ryan: It looks like something is wrong with my app here. One of the dates is not showing up. It's showing Null. Can I set breakpoints while my app is running in the browser? >> Mariam Hasnany: Yeah, you can. We connect to Chrome's JavaScript debugger which allows you to set breakpoints, evaluate expressions and also use Chrome DevTools. >> John Ryan: Cool. Let's set a breakpoint after we load this JSON. So I'm going to make sure I'm running in debug mode here, and I can see I've got my debugger open, and I'm going to set a breakpoint after I load the details for this podcast, and I'm going to reload this page by just navigating back and opening it again. And you can see that once I'm stopped at a breakpoint, I can do all the normal things like evaluate expressions. For example, I can just type response.body and see the response body. So it looks like I'm parsing the JSON correctly. If I scroll through this, I just want to check that the episode URL here, publish date here is the value I would expect, and I can see that it's Null, so I can see the that the value is coming from the server as Null, but let's verify that by opening up the Chrome DevTools. So if I go back to my app here, continue, and pop open the Chrome DevTools, I can see network requests here, just like any other web app. So if I navigate back to this page, I'm still stopped at this breakpoint, but I can see the network request here and I can also verify that the value is Null if I wanted to. So, let's work around this issue for now by fixing this widget so it doesn't display the word "Null." I can open up the Inspector here, disable this breakpoint and enter select widget mode. I'm just going to select this widget. Once I have that selected, I can navigate directly to that widget by double clicking on it in the Flutter Inspector, and I can see that I'm just putting the raw value of toString into the next -- text widget. So if timeAgoDate Null, it's going to put the string Null into that widget. So I can just fix this quickly by doing a quick Null check. So if the episode timeAgoDate equals Null, I'm just going to give it a null widget here, otherwise I'll give it the text widget that I was giving it before. And I can perform a hot restart and go back to my app. And you can see that the null widget is gone now >> Mariam Hasnany: Fun fact, just like Flutter DevTools, the Inspector is also built using Flutter. All right. I think the app feels ready to me. Let's ship it. >> John Ryan: Let's ship it. So in addition to the Flutter Build iOS and Flutter Build Android commands, there is now a Flutter Build Web command. So if I go to my terminal and I run this command, flutter build web, that's going to do a release build of my app, and it's going to put the output assets in this build/web directory, and I've already run a build here, so I've already got the build web directory filled out with my index HTML and my Dart.JS file. >> Mariam Hasnany: Yeah, and, John, when you use that build command, you can choose which renderer to use, just like you did earlier with the run command, but since you didn't specify one, it's just going to use the auto option. >> John Ryan: Cool. That makes sense. So it looks like it's done now. Now that the release bundle is ready to go, what are my options to host this app? >> Mariam Hasnany: Well, there's a lot of options. There is Firebase hosting, Google Cloud, GitHub Pages or other similar hosting services. >> John Ryan: Okay. So I'm familiar with Firebase, so let's go with that. I've actually already installed the Firebase CLI, so I'll just run from my project directory Firebase init hosting, and that's going to ask me a few questions here. So it's going to ask me what to use as my public directory, and we'll use build/web, since that's where the output assets go, and I'm going to configure it as a single-page app since Flutter apps are single page, and I'm not going to overwrite the HTML file. And once that's done, it writes a Firebase configuration file, and I can run firebase deploy --only hosting for my current project, which will upload the assets, and it should just take a second here. And once that's done, I can actually click on this link to load the final version of the app running in release mode. >> Mariam Hasnany: Wow, that was really fast. It looks just like we expected. >> John Ryan: Yeah, it does. So now that it's hosted, how do I turn it into a PWA? I want my users to be able to install it when they visit the page. >> Mariam Hasnany: So it's already a PWA. If you look at that icon in the URL bar, it's a plus icon. If you click on it, you'll get an option to install it as a Progressive Web App. So when you build your Flutter web apps, we create a web manifest file for you so that by default your app can use PWA features like installation, offline support or notifications. >> John Ryan: Great. And now that it's installed, I can access it without opening my browser. So are we done? >> Mariam Hasnany: Yeah, yeah we're done. Let's recap all the steps we took. >> John Ryan: Sure. So we started with our mobile app. We ran it in the browser and we changed some things to keep the web platform in mind. So we looked at plug-in support for our app, we tweaked some things for responsive design for Desktop screens, we looked at navigation and how that works on the browser, and we looked at Desktop idioms like scroll bars, mouse cursers and keyboard shortcuts, and we also looked at the different web renderers like auto and CanvasKit and HTML. >> Mariam Hasnany: Yep. And we also used hot restart to iterate quickly and debug the code using breakpoints, evaluation expression, Inspector and Chrome DevTools. Then we deployed it using Firebase and installed it as a PWA. >> John Ryan: Yeah, it's all available now in the Stable channel. So thanks again for joining me today, Mariam. >> Mariam Hasnany: Yeah, thank you for having me. I had so much fun, and I encourage everyone trying to build their own Flutter web apps on the Stable channel now. >> John Ryan: Thank you all for watching and check out flutter.dev/web to learn more. [ Birds chirping ] [ Upbeat music ] >> Leaf Petersen: So here's an interesting question. Does this switch need to have a case to handle Null? Well, if theme mode can return Null, then it does and the switch is broken. Can it? Wouldn't it be nice if the compiler could just tell me whether I need to worry about theme mode being null or not? Well, the new Null Safety feature that we are releasing as part of Flutter 2.0 is designed to solve just this kind of problem for our developers. Null Safety lets the tooling keep track of what things can be null for you, making development in Flutter easier, faster, and more reliable. So today I'm going to show you what it's like to migrate an app to Null Safety. This isn't an intro to Null Safety, so if you're not familiar with the feature, some things will be new to you, but don't worry, you'll get the basic idea. So the app I'm going to migrate is the Rally app from the Flutter Gallery demo app. It's a pretty full-featured app. We can take a look in here. We can click around. We see it has a bunch of animations, it has a bunch of charts, so, you know, nontrivial app. There's about 9,000 lines of code in this as I have it currently running. The thing I want to point out here is this little message down in the terminal window that says that we are running with unsound Null Safety. So what's that about? Well, basically this app is running a version of the Flutter framework that has been ported over to Null Safety, but the app itself is not yet Null Safe, so we're running a mix of Null Safe and non-Null Safe code. That's fine. We built technology into Dart to make this work, but it means the app doesn't get the full benefits of Null Safety, and the framework can't rely on the app not to pass Null where it's not allowed to. That's what we mean by unsound Null Safety, we can't quite trust it. So what we need to do today is to get this app running with full sound Null Safety. And to do this, we're going to use a migration tool that the Dart team has built to make this easier. So let's give it a try. So if we go over here to our terminal window, we can run the migration tool directly from our terminal. So if we run Dart Migrate, it's going to give us a little printout here which tells us some helpful documentation, which is very useful to read. It will tell you lots of powerful ways to use the tool and tell you more about how to use Null Safety as well. The tool is going on and it is looking at your code and it is analyzing it to figure out a bunch of things that it needs to know about it in order to migrate it to Null Safety. So it's looking at the code. Oh, and it's giving us an error. So something went wrong. What did we do here? Okay. So we're getting a bad state. We're getting an error that says that the package has un-migtated dependencies. So what's going on with that? Well, this is the first thing that the migration tool is going to do for you. We really encourage our developers not to migrate their code before all of their dependencies have been migrated. Waiting for your deps to be migrated makes your migration experience much more reliable and helps you have a good experience with it. The migration tool is trying to keep you on the rails by checking this for you. So, we need to fix this before we get started. So how do we fix this? Well, we need to update all of our dependencies. We need to change the packages that we depend on to be Null Safe versions, and the tool that we use for this is the tool that understands packages, which is pub, okay? So we have built into pub a new mode for the pub outdated command. So if we run flutter pub outdated with --mode=null-safety, we will get a bunch of information that is very useful for knowing whether or not we are ready to migrant to Null Safety, okay? So, we're running pub outdated, and we get some information that tells us a whole bunch of stuff about the status of our dependencies of the packages. So what are we looking at here? Well, on the left side, we have a column that says the name of all of the packages that we are currently using for which the current version is not Null Safe, and you can tell that because if you look under "current," that column shows us the current version that we are using, and there's a little "X" next to the version that means that it is not yet Null Safe, it has not been migrated, that package has not been migrated, and you shouldn't be migrating your app unless all of the packages you depend on are Null safe. Well, maybe there's a new version of the package that is Null Safe because the Dart team has been out migrating lots of stuff to get it ready. And, in fact, if we looked at this, if we looked under the resolvable column, we see that both of these packages have a version listed with a checkmark next to it, and that little checkmark is telling us that this version that is listed here is Null Safe. The resolvable column is telling us the latest versions that we can get that are mutually compatible that we will actually be able to get a pub solve for. There may be a more recent version listed under "latest," but for some reason, it is not compatible with something else that we have in there, okay? So, resolvable's what we're going to focus on. And if we want to migrate, because we are apparently able to migrate, what we need to do is we need to copy over these latest resolvable versions into our pub spec and update the dependencies on the packages, okay? So we're starting here with shrine images, and we're going to go to shrine images and update it to point to this latest Null Safe version. And we will do the same for URL Launcher here. It has -nullsafety in its name because it's a Null Safety prerelease. It hasn't been published in stable yet, but it is available as a pre-release, okay? So I've updated my pub spec here, and now if I run flutter pub get, that will go off and it will get me these new versions of these packages, download them, and it will -- and it will get it ready to run again. And if we run our outdated command again just to check, what we should see is that there is nothing listed anymore among the packages that are not yet available. So we can see here that all of our dependencies, both direct dependencies and dev dependencies, all of them support Null Safety. So that tells us that we are now ready to migrate. So now we can go back and try it again. Okay. So this is going off and doing some analysis. So what is it going to do? So the first thing I'm going to tell you that it's going to do or not going to do is it's not going to change the code that we have on our disk. So the migration tool is designed to make essentially its own virtual copy of your code, pretend to migrate it, and then it's going to give us a preview of what it will do once we choose to apply the migration. So this allows us to look at the choices that it's making and possibly reconsider if we want to accept those choices directly or do something to change what choices it's making. We'll get into that in a little more detail in a minute, okay? So we've made it a little further here. We're not getting our error anymore about seeing missing migrated dependencies. It's generating a bunch of suggestions. It's generating the modified code and then it's spinning up a little web server and giving us locally on our disk here on our own machine, and then it's giving us an address that we can hit to actually get a preview of the code the way it will look once we migrate it, okay? So this is the migration tool. So, let's take a little look around the migration tool. If we look over on the left, what we see here is a skeleton view of our code layout of our app. This is the app code over here. And there are little check boxes showing which files we're choosing to migrate now. By default, you're going to migrate everything, but if for whatever reason you want to only migrate part of your app, so, for example, you want to split part of it off so you can send it off in bite-sized chunks to your reviewers and be nice to your reviewers, you can choose to deselect certain parts and select other parts. Again, as with packages, we recommend that you choose to migrate the sort of roots of your package first and then move in a waterfall fashion through the dependencies, even with your app, if you don't migrate it all at once, but the migration tool, the preview pane here allows you to choose which things you're going to migrate, okay? And if you click on any one of these files, in the middle here, in this middle pane, we will see a preview of what the code will look like after we run the migration, and then there is a little bit more information over on the right that I'm going to get to in a minute. So the first time through this tool -- I'm going to do a couple of things with this, but the first time through, I want to see what happens if we just accept the changes as the migration tool proposes them with no modifications. And so to do that -- or at any point if I want to accept the code in its current state, I can push the "apply migration" button, okay? Applying a migration is actually going to edit the code that is on my disk. The tool is going to go off. If I click that, it's going to say "do you really want to do this?" And if you say okay, then you will see down here in your terminal window that it has applied the migrations. It has migrated 48 files. And if we do a quick git diff, we'll see now that there's a whole bunch of changes that have been made to our code. And if we go over to our IDE, we can actually see, if we go up and we click on one of these files here, we might see some changes. So, for example, some app required things became required and so on. We actually also see, though, that we have a static error. Okay. So this is the first thing I want to point out about this. The migration tool is not perfect. It's not putting us out of business yet. It does a lot of the mechanical work for you, but it will sometimes get things wrong or it will sometimes make choices that are not exactly what you would have made if you were migrating the code by hand. The real strength of the tool is doing sort of the mechanical data flow work for you where you have something which is nullable assigned to something else which is nullable and chasing that down. And here it's gone a little off the rails. So let's see. We only have one error, so let's see how much work is left for us to do if we were running the migration this way. If we go in here, we can see that what it's complaining about is that we have a variable match, and the inferred type of match is string question, and it's being assigned to the parameter of this demo page constructer. And we can see that this demo page constructer, it's a field formal, it has been migrated to be non-nullable, and yet we are passing a string question is a nullable string. We're passing a nullable value and that's not allowed, okay? So this is somewhere where the tool went a little bit off the rails. Basically, this was already marked as at required, and usually the tool assumes things which are required are not nullable, because that's what they usually are. If we change our mind and make this nullable, that's fine. This is good so far. That fixes the original error that we had, but it introduces a new error because there are other places that this thing is assigned, and now we have to chase through and mark all of the places that this data flows through as also being nullable. And this is the work that the migration tool would otherwise be doing for you, right? It would be doing the work of chasing through all of these places that that nullable value reaches and marking them nullable for you. So that's why using the migration tool in general is going to save you a lot of work, because it does a lot of this mechanical stuff. And we can see now that we have actually -- that we now have no errors. So we can go over to our app here and we can quit out of it and we can restart it. That's going to take a minute to start up, so let me just point out here a couple more things around here. We have a bunch of informationals now that weren't there before. So what's going on with that? Well, one thing we can see is that there are a whole bunch of assertions which are now not necessary, right? These were assertions that were previously asserting that things that should not be null, that are not allowed to be null, were not actually passed a null value. Well, now that we've migrated this to Null Safety, the static analysis, the tooling is sufficient to prevent this from happening. So the system is telling us that these assertions are essentially dead. When we were running in unsound mode, we might have wanted to keep these assertions around because un-migtated code could violate the guarantees of Null Safety and still flow Null through here, but now that we've migrated this fully to Null Safety, we don't need these assertions anymore. Another cool thing if we look in here, if you remember when I started out, I asked the question of whether this case, this switch statement here needed to handle Null. And we can see actually now that the migration tool has figured out for us that we do. In fact, theme mode can be nullable. It has been migrated to be nullable, and I looked through this code and I actually found that, yes, Null can flow to this location. It turns out that won't crash the app because there is some default logic here, but it's a latent bug in this code that was found with Null Safety. If I was editing with this code, I would have been told that right up front, so that's one of the really nice things Null Safe code that I hope you find valuable. Okay. So, we're loading up the app here. It's taking a little bit of time. We have to do a full rebuild, but if we give it a minute -- okay, and we are up and running. So the first thing I want to point out is that we are, in fact, running with full sound Null Safety. We've got this little message to tell us here. It says that we have been successful. And now all of the code in our app is soundly Null Safe and the compiler and ourselves can trust that no Null values flow to places where they shouldn't, okay? And if we click around in the app here, we actually can see it's running quite fine. That's not always the case. It's possible that you will get new run time errors. Maybe you added a Null assertion operator in a place that it wasn't supposed to or any of a various number of small things, but in this case, we seem to have ended up in a pretty good spot and the code is running just fine. So, that's pretty cool, right? We basically just -- we basically just took a nap, and with one push of a button plus three small edits, we got this entire 9,000 lines of Dart code up and migrated and up and running with full Null Safety. And it took us, you know, maybe 10, 15 minutes here. And I'm not cheating, by the way. I didn't pull this app down and do a whole bunch of work beforehand to make this easy. I cut out some of the other pieces of the app that I didn't want to work on to get it down to 9,000 lines, but other than that, I just ran this and we're running. So this is really a legitimate example of what it can be like to migrate your code. But we also saw that it didn't necessarily do everything right, and I also will say that the tool is going to be more conservative than you might choose to be. It is trying to get things up and running and it is trying to minimize the number of things that it makes nullable, but where it has to make a choice, it will sometimes make a choice to make something nullable that you because you know a little bit more about your app would be able to make non-nullable. So if you want to do a careful migration of your code up front, right, you might want to audit the changes that the tool is going to make and guide it to a better result. Fortunately, the tool supports an interactive workflow for doing this, which allows you to tune the output, and this is one of the -- I think the more powerful ways of using the tool. So we're going to go back and try this again using that interactive -- interactive workflow, okay? So let's give it a try. Okay. So if we go back over here to our terminal, we can reset ourselves back to clean state so we can try this again using the interactive workflow. We tried it once just sort of accepting everything that the migration tool suggested to us and then fixing up anything. Now we want to walk through it again, taking a careful look at the choices that it's going to make. So what I'm going to do is I'm going to go ahead and run that tool again, okay? And if you recall, again, this tool is not going to directly change the code that we have on the disk. It's going to go off and develop its own little view of the world and propose it to us in a preview package. When we use an interactive workflow, we're going to spend time using the tool in our IDE to understand the choices that it's making and to guide the choices that it's making. So how do we guide the choices? Well, there's two ways we can do that. One is we can actually refactor our code so that it's more compatible with Null Safety, and the other is that we can add explicit hints, in a way that I'll show you in a minute, to the code to guide the tool to a better result. And that's the one I'm gonna focus on here, okay? Using hints to guide the output of the tool to get it to produce exactly what we want. So let's take a look at that, okay? So we're -- it's getting its stuff spun up here, and if we take, again, remember, it's got a little web server and we take our -- take the URL it gives us. Just open it up in our browser. And we're once again back into this preview tool and we can look -- we can -- we can start poking around in here. So this time I want to focus a little more on using the tool and all of the powerful things that the tool provides for us. So I talked about how in the center here, we have our preview pane. And this preview pane is, again, showing us the way the code is going to look after its migrated. On the disk is the code that currently exists un-migtated, and in this preview pane is the code as it will exist once we migrate. You can see that because actually it's highlighted here the changes that it's proposing to make in the preview pane. So if we look at each of these, it's adding questions to these type, meaning this is becoming a nullable type. This is a field that it thinks is potentially going to be -- is going to be nullable. And it's also listing over here in this upper right-hand corner, it's listing by category each of the changes it's gonna make. So we can see in this file here it's making quite a few changes. It's proposing to add a lot of non-Null assertion operators. We can click on them over here and it will take us there. These non-Null assertion operators are places where we have a nullable thing that we know by invariant is now not null and we want to extract out the non-Null value with a non-Null assertion operator, a Null check operator. So there's a whole bunch of those in there. I don't want for focus on them right now. So what I suggest when you're using the interactive workflow is that you focus on the types that have been made nullable. So down here there's a list of just four types, four places where it has taken a type and made it nullable. The reason I recommend focusing on this is that the choice of nullability in the types is what drives all of the other changes that it makes. All of those Null check operators that it's adding, it's adding because of the choices it made about nullability. So once you've figured out what the right nullability is for the types, all of those Null check operators, you know, you might want to check them, but they basically are mechanically added, they're mechanical. And this is, you know, the power of the tool is that it will do that mechanical work for you. So let's take a look at it. So if we look here, we've got these four fields. It is proposing to make them nullable. So, is that the right choice? Maybe I know a lot about this code so I can just say right off the hand yes or no. That's great. In this case, I'm actually not that familiar with this code. I just pulled this down off of GitHub, so I'm using the tool and using my IDE to explore this. And the tool gives us some very powerful tools. It gives us some very powerful techniques for figuring out why it is making the choices that it's making. So if we click on one of these, we can see down in this right-hand pane down in the bottom-right a stack of the reasoning that led the tool to make the decision that it made. It's essentially telling you what flow of control and data through the program led it to decide that this should be a nullable variable. And if we walk back through that flow, we can reconstruct very quickly and without having to do a lot of exploring in the code or debugging why it's made it nullable and whether we agree with its reasoning. So let's do that. If we go over here to this little pane here and we start clicking on the points in the file, well, the top of it is just pointing to the actual field, and then the second thing is saying, well, this field is set in the constructer as a field formal parameter. And this is the constructer that it is set in. Then if we walk back one level, we get to the call to the constructer that is causing it to believe that this should be nullable, okay? So it's looking here and it's saying "open controller is set by being a parameter to the animations constructer here in this other file," and if we walk back one step, we can see that it has decided that in this other state file, open controller is going to be a nullable parameter. Okay. That seems very reasonable, except if we look in this init -- this is part of the initState. It's an initState sub-method. Once we get here to this point, the assertions tell us that these four fields will always be non-null. So, in fact, the animations constructer, even though it looks like it is accepting a nullable value will never get null. So here is a place where we would like to change the output of the tool by overriding its behavior. We'd like to come in mere and say, no, we don't want you to make this nullable, we want you to make this non-nullable, okay? And the way we can do that, one of the simplest ways, is we can actually use these two buttons that the tool gives to us to add a question mark hint, which means make it nullable. Well, we don't need that one because this is already nullable. Or the exclamation point hint which means, no, make this non-nullable, which is what we want because we want to change it, we want to override it. So we hit that button, and what we see is we see a little comment with a bang in it showing up here on the code. Key point here. This is the one point up until the point that we apply the migration that the tool is actually editing the code on the disk. So if we go over to our IDE, we can see that this IDE, which is looking at the code on the disk, is showing us that this comment has actually been added into the code. And, in fact, if we want to, we can add the comments out here. I want all four of these to be non-nullable, so I can just go ahead and edit it directly in my IDE, and if I wanted to, I could check this code into GitHub. I could spread out this migration over the -- over a long time period by just adding annotations and incrementally working on it, and all of these have know effect on the existing have no effect on the existing code, but they guide the migration tool to a better result, okay? So if we go back to the tool now, we can re-run the tool. There is this re-run with changes button we're going to hit, and when we hit that, it's going to look at the comments that have been added, look at any changes to the code, any refactoring you did, and it's going to recompute the set of suggested changes that it's going to make to your code. So it is doing exactly the same work, and our hope here by adding these non-nullability assertions is that we're going to make the rest of this code cleaner, right? Okay. So, this is the outcome. If you recall, when we first came into this file, there were a whole bunch of Null check operators proposed to be out of this, and those were all driven by the fact that these four fields were nullable. Now that we've made them nullable, now that we've overridden the choices of the tool, it is not suggesting to add those because they're not needed anymore. So by auditing this and making a few small changes to its choices of non-nullability, we've ended up in a point where the final emitted code is much cleaner. That's what I mean by interactive work with the tool. We work with the tool to help get it to a better point. It does all the mechanical work of figuring out what flows from these decisions that we make about what things are nullable, okay? One more example here I want to show of a different kind of tool we can use. So if we go to featurediscovery.dart here, we go into a little bit, we'll see another example of a code pattern which is very common in Flutter. Which is a State. This accompanies a Stateful widget, and it's a State class. There is a very common pattern here where State classes tend to have fields which are not set in the constructers, but they are set in the initState method. Often but not always, those fields are never actually intended to be used as null. They just happen to be set a little bit late. Well, Dart Null Safety has a new feature called Late Fields, which is exactly intended to support this kind of pattern where you set something later -- you don't set it initially to a non-null value, but once you set it, you never reset it to Null. So, often we want to look at our State classes to see, is this a good place to use a late variable, okay? So how do we figure that out? Well, I'm going to look at these animations and these overlay fields here, both of which the tool is choosing to mark as nullable. If we look at the reasoning stack here, it's actually not that helpful this time. Because basically it's just telling us this field is not initialized, so I don't know what to do with it. Sometimes that means we may want to refactor the code to initialize the code in the constructer, but in this case, in the State pattern, we don't get to do that. But what we can do is we can go over here to our IDE and we can actually start looking around a little bit to figure out whether it is necessary to make these things nullable. There is nothing wrong with making them nullable, but let's see. So if we look at overlay first and we look at all the uses of overlay, okay? So we use our IDE here to see all the uses. We can see here that actually overlay is almost certainly going to be -- should be nullable. It is set to null in a place. It uses Null aware operators on it. It's checked for Null. So something about the logic of this program is requiring overlay to be nullable. So we're not going to change anything about that. Animations, though, if we look at the uses of animations, we can see in one place it is set to a non-null value. The result of the constructer is definite of the constructer is definitely non-null, and all of the other places that it's used, it's passing it into places that have required parameters that are definitely non-null. So that's a good sign to this -- for us, that this field is never actually really intended to be null, and therefore it's a great candidate to make late, okay? So how do we make it late? Well, again, we use hints, and here we can just add it directly. We don't have a button in the tool for this, but this is one of these sort of power user hints that you can actually add directly in your code to, again, continue guiding the tool. I'd add a late hint that's going to come back here and tell the tool that when we rerun this code, it should treat animations as a late non-nullable variable and propagate all of the changes that follow through from that. So we'll get rid of a few more of these none-null assertion operators. So that's the basic workflow that we're talking about here. When we talk about using the tool in an interactive mode. We look at the changes that the tool is proposing, we think about either using the preview pane, which gives us information about the reasoning that the tool is made or we look in our IDE to try and understand whether it's making the choices we want it to make, and we override any choices that we don't like and then we rerun it until we finally get something that we like. And then if we want to, we can take all or, again, some of the code and apply the migration to it. So let's go ahead and do that. We can say, well, we just ported this feature discovery directory. We haven't looked at any of this other code yet. I want to send this out for review, so I'll uncheck everything else, okay? And then I can go ahead and apply the migration. It's going to ask me if I really want to do this. I say yes. It's going to go ahead and rewrite just the code that we just audited here on disk. So we can see here it said it migrated a few files, it updated our pub spec to say that the whole project has opted in, and then it has marked a whole bunch of files as explicitly opted out because we haven't migrated them yet. If we start the tool up again it will tell us, hey, these are the files that aren't migrated, these are the files that are migrated, what do you want to do with these, okay? So, Okay. So, that's the workflow. If I wanted to, I could now send feature discovery off for review. I could start in the next part. I could the whole thing in one go. With a bit of help from the migration tool, we could have this app up and running just without a lot of fuss. It might take us an hour or two to get something really tuned and fine. Okay. So, a few things that I'd like you to take away from this. First, remember that you should only migrate when all of your dependencies are ready. We really strongly encourage this, and pub outdated -- mode=null-safety will help you figure out if you're ready or not. When pub says you're ready, go for it. If not, you need to wait. Maybe you can help migrate some of those other packages you depend on while you're waiting and get familiar with Null Safety. Second, when you are ready to migrate, I hope I've convinced you that the migration tool is a great option for speeding up the process. You can try using it in a one-off fashion the way I did at the start, but we think you'll probably get a better outcome if you work with it interactively the way we did here at the end. Finally, whether you choose to use the tool or not, I hope it's clear that migrating to Null Safety isn't a terrifying ordeal. Our experience is that most code is pretty straightforward to migrate, whether you're using the migration tool or just using the IDE, and we've been really quite happy with the result. So, thanks for listening. Thanks for being part of the Dart and Flutter community and happy coding. [ Birds chirping ] [ Upbeat music ] >> Filip Hracek: When you close a door of a modern car, [ Car door shuts ] Chances are that the sound you hear is engineered. The latch mechanism is made in a way that makes it sound a little bit more deeper and more vault-like and satisfying. Old cars didn't have that. [ Car door shuts ] In this talk, I want to show you how you can make your Flutter apps more satisfying to use. [ Car door shuts ] If you want to expand your expertise with some design shops, this talk might be for you. There's an important concept called perceived value. This is the value of something as it is perceived by the user. A car, for example, is inherently valuable because it can take you from point A to point B in relative comfort. But that's not the whole story, is it? Two cars can both take you from point A to point B in relative comfort, but they don't have the same perceived value. All it takes is something like the sound that a car makes when you close the door. You'll find that the perceived value of a car is often as important as the functional one. Similarly, your app can be functionally amazing, but it could still be -- if it feels too bland or flimsy, then people will just not use it as much. The perceived value will be low. Some people will still use it, of course, but others will be put off. On the other hand, just to be clear, if your app or if any app is not valuable at all, if it doesn't have any functional value, then no amount of additional perceived design polish is going to save it. So, in this talk, we are assuming that the app has some functional actual value, it's useful. It just needs a little bit of polish. You may be thinking, well, I'm not a designer. How is this relevant? I'm a developer. Like, I don't do this kind of thing. And you're right, you can have a perfectly valuable, good career in software engineering without ever really thinking too much about design. You can just implement whatever the designer tells you to implement and that's fine, and there's nothing wrong about that. This talk is for people who would like to meet the designer halfway or people who would like to even bridge the gap between development and design. Or maybe people who want to become the mythical designer-developer. Some people call these developers unicorn developers because they are rare and valuable. Okay. So what are some of the things that you can do in Flutter to make your app more polished? This app, for example, is not polished. It shows the agenda of my talk, starting with car doors and ending with animations, and it even, like, tracks my progress and shows a little congrats card at the end. So let's pretend it's valuable, but its perceived value is pretty low. Let's try to fix that. We'll start with white space. White space is the blank space around elements of your app that make those elements stand out. White space is something that's perceived by product makers as wasted. It's like, oh, all these precious fix pixels used just for background? What? But white space is actually really important and it communicates meaning, hierarchy and relatedness between elements of your app. So, do we have a widget in Flutter for white space? Yes. It's called Padding. That's right. Sometimes just playing around with Padding in your app will make a big difference in the perceived value of your app. And this is something that you can do very early on, even if you're just playing with a prototype. It's easy to play with using hot reload, so you can see immediately what the fact is. And, again, hot reload will just make it happen. You don't need to do anything more. A related simple thing to white space is alignment, right? This is nothing more than making sure that elements on your screen are lining up nicely. For example, these paragraphs might look nicer if they line up with the title. Again, this is just padding most of the time, and sometimes using the align widget. For example, if you want to line up to the right. Aligned elements aren't just nice to look at, the alignment also communicates some meaning. The paragraphs belong to the title because visually they're in the same group. Next up, typography. In most apps, text is a big part of the screen. Some apps are basically a vehicle for a lot of text, right? So it's important. So how do we improve typography in our apps? How do we improve the way text looks like? You're looking for consistency and delight. Consistency means that you have only one text theme and then you're using that one text theme throughout the app. You try to keep the fonts, the styles, the sizes to the absolute minimum that still communicates meaning. If you find yourself overwriting the text style too often, then that's a good indication that you might not be consistent enough. Just extract the styles into text theme and then use that instead. [ Upbeat futuristic music ] βͺ How do you delight with text, though? Well, that depends on the kind of audience that your app is for. Some apps can delight by being minimalist. Others might go for absolute mayhem, just crazy things. Still others, and I think the majority of them, might delight with just the more classical approach of having a good display font for the headlines and then something subtle but interesting for the body text. Don't forget about letter spacing and other typographical measurements. They are there for you to play with, right? For example, the letter spacing of bigger headlines can be much tighter because the increased size of the letters makes up for the decreased readability of the squeezed characters, and the squeezed characters may look much nicer. Line heights, similarly, can be pretty tight in titles, but for body text they need to be more spaced out so that it's easier to read. Again, hot reload is your friend. You won't get to the right combination on your first try. Trust me. At least I can't. This stuff needs iteration. Next, let's look at colors. Once again, there's a lot you can achieve just by being consistent. So find a palette and stick to it. Finding a good color palette is actually pretty hard. Again, especially for me, it's super hard, but there are online resources, there are actually online tools that can help you, and there are tutorials and articles. You can also get inspired by art and fashion and architecture and what have you. When you have a palette, just use it in your material themes ThemeData and then use it around your app. So you can specify each color in that material theme themes data, or you can just specify some of the basic colors and let material theme guess the good complimentary colors from that. I recommend using material color swatch, which is just a fancy way of saying it's a color and nine of its other shades. From a primary color, material theme then can guess some of the other little things. Like, for example, the color of text selection in your app. But, of course, you can always override to your heart's content and you can make the text selection whatever color you want. Material theme has also the concept of accent color. This is the kind of color that you want to use sparingly, but that adds a lot more life to your design. If you don't have that, then the app could look a little too bland, but, again, use it sparingly. Like with red roses in a room, that looks great, but if you have a room that is completely red, that may not be such a good idea. If you have a brand or visual to work with, then of course use that. That's the best. Anyway, there is a lot to be learned about color, of course, but you'll get a long way by just being consistent. Next, iconography. A nice well-placed image makes a huge difference in the perceived value of your app. These can be photographs, illustrations, splats of color, what have you. Don't underestimate the power of adding a single image to your app and placing it prominently on the screen. [ Upbeat music ] βͺ Also, don't forget to make the image match the rest of the design or vice versa, match the rest of the design to the image. Like here, I noticed that there is a subtle gradient on the image, and so I copied it to the background of my app, so, first of all, there is no discontinuity and it also just looks nicer. So, so far we looked at white space, typography, color, and iconography. So basically Padding, text, color and image, right? Even with just these very basic, simple elements, you can make your app look much nicer. But let's not stop there. One of the coolest things you can do with an app is make it move. Let's talk about animations. Well, actually, first, let's talk about the basics of motion. You want a car to fly from the top to the center of the screen. What do you do? Well, you use something like slide transition or animated position and you're done, right? Wrong. You see, by default in Flutter, these kinds of widgets that move around things default to Curves.linear. This is an obvious default because Flutter can't know what you want, but it's also a pretty bad default to keep as is because you almost never want Curves.linear to move things around. Once again, you should use hot reload and experimentation to find out what's best for you, but most of the time, a good subtle ease out or ease in curve will work. In our case, you can see how Curves.easeoutcubic made a huge difference. And you can now see how the linear curve looks really weird and unnatural. People when they see movement like that in apps, they can't put their finger on what exactly is wrong, they just know it's wrong. Well, what's wrong in this case is that we're using the linear curve. There is no acceleration. It just starts moving in constant speed and then stops immediately, and nothing in the real world moves like that so it feels unnatural. Okay. So now we have this animation that where the card comes from the top and it's not linearly animated, which is great. Can we make it a little cooler? A little more satisfying? So, just sliding is fine, but we can also animate in the other stuff. Like, for example, we can make the confetti icon show up and then we can trick out the text below. If we try that and animate everything at once, the result is actually terrible, I think. Instead of making the animation look cooler, it's just all muddled and confusing. There's a concept called staggered introduction. When you're introducing new elements to the UI, you don't want to show everything at once. You stagger their animations. You space them out. So, how do you do this in Flutter? Well, there's a great article on flutter.dev called "Staggered Animations," and you should just go check it out. It's really good and it has code in it that you can immediately use. In short, this is done using Interval. Interval is a class that you can use in combination with animation controller, and so for the whole introduction, using all these elements, like, for example, our sliding card and the icon and the text, you use a single animation controller that runs for the whole duration. And then for each of the sub-animations, you use Interval. For example, an Interval like this will do nothing for the first 50% of the whole animation controller's duration, and then between the 50% mark and the 60% mark, it will do the whole thing and then it will be at rest for the rest of the animation. You can combine this with another sub-animation and another part of the thing will use a different interval that can be overlapping with the first one, and in this way, you can orchestrate this ballet of animations. In the end, you will have this app that comes to life, like, pow, pow, pow. Like, things are starting to come up to life. So, is this great design? Probably not. I don't think so. I'm not a designer. But it's better than this, right? And I spent about three hours doing this. Including lunch. Instead of days of back and forth with designer. Now I can ask an actual designer about ways to improve what I already have, and I have the vocabulary to talk to them about these things. By the way, I want to say that the code for this app both before and after will be available on GitHub, and I'll make sure it's accessible so you can play around with it and ideally make it even nicer, because I would really like that. In conclusion, here's what you learned today. Even without being a full-blown designer, you can still make your apps more [ Car door shuts ] Satisfying to use. This will increase the perceived value of your app. More people will be installing it, more people will be keeping using it, and research shows people will even think it's more user friendly just by looking at it. As I said before, if your app doesn't have any actual value, then no amount of design polish will save it. But on the other hand, don't let a perfectly functional, valuable app be overlooked by the users just because it doesn't have that [ Car door shuts ] You know, satisfying element. This additional perceived value of your app will, in turn, make you more valuable. If you're able to build apps that people value more, then that's going to be good for your career. So, learn about the basics of design, color theory, typography, psychology, sociology, and use all that in your Flutter development. Think of yourself as a maker, not just a coder. A designer-developer. Thanks for watching. [ Birds chirping ] [ Upbeat music ] βͺ >> Zoey Fan: Hello, everyone, my name is Zoey. I am a Product Manager on the Flutter team. >> Andrew Brogdon: And I'm Andrew from Flutter's Developer Relations team. >> Zoey Fan: Thank you for joining our breakout session. We're here today to show you how you can monetize your Flutter apps. If you watch the Keynote earlier, you probably already knew that we announced open beta for the Google Mobile Ads STK for Flutter, and that's what we're going to focus on today, but I just wanted to quickly mention that in addition to ads, there are two other ways to monetize your mobile apps. For example, you can always charge for your app in the App Store. Another option will be in-app purchase. You can allow your user to buy extra content or features such as game currency through in-app purchase. We also have a plug-in for that on pub.dev. Today, we're going to be focusing on ads because we have this new ad integration that we're excited to tell you about. During the Keynote today, we announced the Google Mobile Ads SDK for Flutter is now open for beta, and this brand-new plug-in will now support a wide variety of ad formats. For example, an overlay banner, which is usually a rectangle ad at the top and bottom of the device screen. Second, an inline banner. Actually, it's just another variation of the banner ads, but the main difference here is that the overlay banner is floating on top of a Flutter view, but the inline banner allows you to integrate it into the widget tree so the ads can appear in line with ad content. Next is interstitial. These are full-screen adds that cover the whole screen of your app. These ads work great when you place them at natural breaks and transitions in your app. For example, you can place them after the user completes a level in a game. We also support rewarded video. These are ads that reward users for watching short videos. Last but not least, we're also supporting Native ads. Native ads are highly customizable, so you can design them to match the look and feel of your ad content. This allows you to provide a seamless ad experience with minimal interruptions to the app. Moreover, another highlight of this new plug-in is that we're now unifying support for both Ad Manager and AdMob. For those of you who are not familiar, AdMob and Ad Manager are two different ad services. Generally speaking, small to medium-sized publishers prefer AdMob because it's an easy to use solution. Google Ad Manager is an ad management platform for large publishers who have significant direct sales and need more advanced features. That being said, no matter what size publisher you are, our new plug-in is able to tailor to your scenarios. When it comes to mobile code, AdMob and Ad Manager are very similar in terms of implementation. So for today's demo, we will use an AdMob ad as an example. Before we get started, here's some ad terminology I would like to clarify. First, ad unit. Ad unit represents a single place in your app where you want to show an ad. If you have an app with three screens and you want to show a banner on each screen, then you need to create three ad units so you can control them independently. Next, ad format. We already talked about it earlier. You can choose between a banner ad, an interstitial, rewarded video or a Native ad. Ad request. When your app loads an ad, it sends an ad request to the server. You can use this object to provide additional information that can be used when selected. Last but not least, test ad. Once you implement an ad, you definitely want to test it, but it's important to enable test ads during development so you can click on them as much as you want without the clicks actually being recorded. Because if you click on too many ads without being in test mode, there is a risk your account might be flagged for invalid activity, and you don't want that to happen. The good thing is that Google does provide test ad units. These ad units are not associated with your account at all, so there's no risk of your account generating invalid traffic when using them. Okay, now you have enough of ads terminology, we can get started. For today's demo, Andrew and I are going to show you an app we created in our spare time. Let me tell you more about it. Both Andrew and I are parents, so we created this app called The Big List of Parenting Jokes. It was so much fun that we wanted to share it with the entire world, but we soon realized that we have to pay for the maintenance cost, the servers, et cetera, so we'd like to monetize the app via ads. That way the app can be free to download. In order to load an ad in your app, the first step is to create an ad unit. Actually, in order to do so, you will first need to create an AdMob account. You can follow the link below to create an AdMob account. To save some time, I have already created an AdMob account. After you log in, you will navigate to the left and click apps in the sidebar. Here, we want to create a brand-new app, so you will now click "add app." Let's first create an Android version of our app. Select Android as the platform. Select "no" because we haven't published it yet. Let's fill in a name. The Big List of Parenting Jokes. Select "add app." Okay, now you see there are two tasks for you to complete. The first one is to set up an app-ads.txt for the app. That's a mechanism that lets you leverage your business website for some extra security. It's a good thing to use, but since we're focused on mobile app right now, I'm going to skip past it. Now let's move on to create an ad unit. For the ad format, I'm going to pick banner because banner is probably the easiest one to start with. Later Andrew can show you how to display an overlay banner versus an inline banner in the code. Now let's enter a name for this ad unit. Let's call it a demo ad. Well, you know what? The name is kind of boring. I'm just going to call it "a fun ad." Here we go. Click "create ad unit." Hooray, now you have your first ad unit. But don't forget, you only created an Android version at this point. Let's repeat the same step to create an iOS one. Let's hit "done." Go to apps in the sidebar, "add app," select iOS this time, click "no," hit "continue," put the app name there, click "add app," create an ad unit, select a banner again, give it a name, click "create ad unit." Cool. Now we have two ad units. One for each platform. Now, Andrew is going to show us how we can load them in our Flutter app. Over to you, Andrew. >> Andrew Brogdon: Thanks, Zoey. All right. So here I am with my running app. It displays a list of jokes that I like to tell my daughter. As you can see, my design skills aren't that sophisticated, but my comedy's pure gold, right? So, that's why Filip did the talk on design touches, and I'm doing this one. Let's take a quick look at the code. I have a hard coded list of joke data here in a file called data.dart. In main.dart, I have a StatelessWidget that represents my app and another and another widget for the screen itself, which uses a scaffold and ListView to display a row for each joke in the list. So, I've got my app. Zoey and I made the decision that these jokes need to be brought to the whole world, so I'm going to use ad-based monetization from AdMob to make that possible. The first step is to get the ads STK integrated into my project. I can do that by adding a line to my pub spec from the Google Mobile Ads plug-in. This plug-in has support for iOS and Android. While I'm in here, I'm also going to throw in a line for provider, which is a package you may already know. It makes distributing data down the tree inherited widgets a little cleaner and easier. Now, I just need to do a pub get and a full rebuild of my app, and I'll have those packages and the Native code that comes with the plug-in. Now, once that Native code is initialized, some of it's going to look around for an AdMob application ID. >> Zoey Fan: I just registered two of those. >> Andrew Brogdon: Yep. And I need to add them to my underlying Android and iOS projects. First, let me open the manifest for my Android project. I just need to add a little XML element within the application tag to hold that ID as metadata. You'll see there's a particular name for the metadata, and don't worry about memorizing that because it's included in the plug-in instructions. Okay, so that's Android. Now for iOS. I need to update the info.plist file that's part of my app's iOS runner subproject. The Flutter plug-in for IntelliJ has this handy shortcut for opening XCode, which I will now use. Then I add a new row to the plist file called GAD Application Identifier. And, again, don't memorize that because it's in the instructions. And then I give it a string value and I paste in my iOS application ID. Cool. So now no matter which platform I'm building for, Android or iOS, the SDK will know right where to find the correct ID. Speaking of SDKs, now's a good moment to point out that the Google Mobile Ads plug-in references the same Native mobile ads SDKs that you use for any other iOS or Android app, so the two places you just saw me adding ID values are the same as you would use for any other iOS or Android app, whether it's built with Flutter or not. Okay. So now I need to update my app's Dart code to take advantage of these new capabilities. Let's start right up here in main. Before I do anything ads related, I need to initialize the mobile ads SDK. For simplicity's sake, I'd like to do that right when my app starts running. Because that initialization involves Dart talking to Native code, I need to make sure Flutter's method channel service is running, and the way to do that is by calling WidgetsFlutterBinding.ensure Initialized. Now, you may be looking at that line and thinking, I've used plug-ins before, and never in my life had I had to do anything with whatever the heck that method is, and you'd be right. Run app will actually call this for you when it executes, but because I want to use a plug-in before calling run app, I need to do it myself to avoid a runtime error. Okay, so here's the initialization call, which returns a future. It's important to wait for that future to complete before doing anything that involves ads. Sitting and waiting before calling run app isn't a great idea, though, so, instead, I'll create a little class to hold data about my ads integration and use Provider to make it available to the widgets further down the tree. So, I'll make a new file called AdState.dart, and inside I'll create a little model class. First thing it will need is a property for the future, and I can take that in via the constructer. Also, I can stick my ad unit IDs in this class. >> Zoey Fan: I registered two of those as well. >> Andrew Brogdon: Right. As we saw earlier, Zoey created one banner ad unit for an destroyed -- Android and one for iOS. right now, though, and you should always, always, always use test ads when you're working on your app, I'm going to use the dedicated test ad units for banners on iOS and Android. There is actually a page in the AdMob documentation that lists these ad units for each platform and format, and they always serve test ads, which makes them great when you're coding. So, I'll add a little Platform check here, and return the right ad unit for each one. Now, back in my main method, I can create one of these little objects and give it the future from the mobile ads plug-in, then wrap my application widget with a provider and use the value constructer to make my AdState object available to any widget that needs it. All right. Now, if I do a rebuild of my application, you will see that I have changed absolutely nothing that's visually discernible, but that's okay. It's up and running with the SDK, and now I can load and display an ad. There are lots of ways to make room in an apps UI to display a banner. However, I am but a humble dad joke author, so I'm going to start with one of the simplest, just a single banner at the bottom of the screen. First, I'll wrap my ListView in a column. Then I can add a sized box at the bottom. I'll give it a height of 50. There are a bunch of standard sizes for banner ads, but 320 by 50 is definitely the most common. Now, I just need to add an Expanded widget around the ListView to make sure it fills all the remaining space in the column. And now I can hot reload again, and you see there's now a little space below my ListView for a banner, and the ListView still scrolls nicely within its view port. All right. Let's load an ad. In order to track the state of an ad as it loads, I need a Stateful widget, so I'll convert JokeListScreen to be Stateful, and the plug-in helps me here. And now I can add a field for a banner ad. This object represents a single banner ad placement within the application. The remaining work for me is about load an ad into this placement and using the aptly named ad widget to integrate it into the widget tree so my users can use it. Okay, first up is loading an ad. I need to make sure initialization is complete before I do that, so I'll override didChangeDependencies in the State object. This method is called any time one of the inherited widgets on which a State object depends gets changed. It's also run just after initState the first time a State object is created, but before Build, so it's a good spot for any nontrivial work You need to do that requires a Build context. First, I need to call the superclass method. Next, I'll grab the adState using Provider, then I can use then to add a function to be executed when that feature completes. Inside, I'll call setState, and instantiate a BannerAd object. It needs a adUnitId, which I can also get from adState. And a size. I'll use adSize.banner, which is 320 by 50. Next up is an AdRequest, and I'll just need a plain one, but this object allows you to set flags and parameters that are used when the server selects an ad. If I were using Google Ad Manager here rather than AdMob, I might want to set keywords to help the server select from several different ad campaigns that I'd set up beforehand. The last parameter I need is an ad listener object. This is a class that exposes a bunch of call backs that the ads plug-in will call in response to events. I could define one here, but a better place would be back in adState. I can create a getter for a listener right here, and for the actual instance, you know how we've all seen those cooking shows on YouTube where someone starts a recipe for Like a giant roast turkey? This is going to take about three hours to cook, but I just so happen to have one here that I started three hours ago. Well, consider the following pasted-in code to be my giant roast turkey because it's large and easy to understand. Actually, it's only 15 lines, so maybe a roast chicken, but it is good code. This is a simple ad listener that just logs all the events that can take place. There is one for ad loading, for instance, and one that's called when someone taps on an ad and leaves the app for a browser. You could use that one to stop background work if you happen to be running some. Anyway, I provide that listener from my adState object right here, and that's it. Now I just need to call load, which I'll do using the cascade operator. This is a neat little Dart trick. It calls the method, but instead of returning the result, it returns the object on which the method was called. Cool. So now I've got this closure here that will execute once ads are initialized, and it's going to create a banner ad and call set State. All that's left now is to display that ad. So let me go back to my build method and change the bit at the bottom to use an if then. Ever since Dart 2.5, we've been able to use if else statements and for loops inside lists, so I can put a null check on banner ad here and return the sized box if the ad hasn't been created. Or put in a Container with the same height if it is. Then inside the Container, I'm going to use an ad widget to display my banner ad. Okay. Let me go ahead and hot restart, and there's my test ad. I can tap on it and opener a browser with the destination URL, come back, and you can see in my log that the listener is receiving and printing out ad events properly. >> Zoey Fan: Awesome. So I guess we're done now. Thanks, everyone. I hope you've enjoyed this talk. >> Andrew Brogdon: Wait, we haven't gotten to the cool part yet. >> Zoey Fan: Okay, just kidding. Please go ahead and be cool. >> Andrew Brogdon: Thanks. And I wish people would say that to me more. As some of you may know, there's been an AdMob plug-in for Flutter for a while. I actually worked on it a bit when I was on the ads team. That's how I got hooked on Flutter in the first place. What's new about this version is that at ads are integrated into the widget tree. Previously, they were displayed with Native views that floated on top of what whatever Flutter rendered. They were two completely different systems, so you couldn't put a banner in a column like I just did, and you definitely couldn't put them in a scrolling list of widgets. Now, though, you can, and I'm going to show you how and turn my dad joke business up a notch. First up, I'll need more than one banner. So what I'm going to do is remove the BannerAd property, and instead keep track of a list of items, one for each row in the list, and they'll be either a joke or a banner. Then in initState, I'll start with a copy of the list of jokes. So now I've got a new list, and inside didChangeDependencies, instead of creating one BannerAd, I'll loop through the list back to front and drop in banner ads every so often. Let's say to start a few from the end, make sure I stop at 1 so there's no chance to have an ad first in the list, and I'll put in one banner every ten items. Now, I just use insert at that index, and I create the same banner at constructer and load method from before. So, instead of loading one BannerAd, I'm loading a few at once and keeping track of where they should be displayed in the list. Cool. So now in my build method, I can remove the column and expand it in the FLs and go back to something much simpler. First, I need to change item count to use that new list, and then I change the item builder to check the type of the item. And return a JokeRow, if it's a joke, or a Container and AdWidget if it's a BannerAd. Okay. I made a been of changes to the State object, so let's do a hot restart instead of a hot reload, and there we go. I've got an ad on the screen and it scrolls right along with the rest of my list. There's some other ads below, and you can see they disappear under the app bar just like any other widgets, but I can still tap on a banner Ad, and just like before, go to the browser, come back, no problem. This, to me, is the best feature in this new version of the plug-in. Being able to monetize with ads in a way that feels more natural and less obtrusive goes a long way to maintaining a good user experience. Also, let me pull up an Android emulator and build my app again. This is a Flutter event, which means I'm talking to a multi-platform audience, and I know you're curious. So here you can see the same app running on Android with no code changes required. I'm monetized on both platforms. >> Zoey Fan: Thank you, Andrew. In this breakout session, we have shown you how you can implement banner ads in your app, but there are a lot of features we didn't get to cover in this short session, and we strongly encourage you to take a look. The Google Mobile Ads SDK for Flutter is available on pub.dev for you to download and try today. Please follow the link below for detailed documentation. By the way, we also designed a code lab. Please give it a try. We hope this new plug-in will help you unlock more revenue growth for your Flutter apps. Thank you for joining us today. Bye-bye now. >> Andrew Brogdon: Thanks, everybody. [ Upbeat outro music ] [ Birds chirping ]
Well, all platforms on stable sure is unexpected.
What's your bet guys on 'exciting announcements'?
You can already upgrade to Flutter 2.0.0 (at least on the beta channel). Just ran `flutter upgrade`: https://i.imgur.com/u1EXWXN.png
My tent is pitched rn haha. What a great stream so far. Will be trying to migrate my apps to desktop and looking forward to it.
I wonder if they are going to mention the Google Pay app jank issues on iOS. I think it ended up with a worse customer experience.
sadly flavours for macOS and windows still not supported