LEIGHA JARRETT: Hi there. I'm Leigha, a product
manager for Flutter. Whether you're an experienced
iOS developer or just getting started, this video
will provide you with a comprehensive overview
on how Flutter works on iOS and how it can help you
build beautiful apps. From Flutter's
unique architecture to its integration with
the Apple ecosystem, we'll cover everything
you need to know. So without further
ado, let's get started. [MUSIC PLAYING] Flutter is a framework for
building beautiful, responsive user interfaces that can
run on multiple platforms with a single code base. That means that you
can use this same code to create apps for iOS,
Android, the web, and even desktop platforms like
Mac, Windows, and Linux. But before we get into
the details of Flutter, let's review the anatomy
of an iOS app built with Apple's frameworks. At the top, you have
your UI app code. And this is likely written using
the UIkit or SwiftUI frameworks in either Objective-C or Swift. Here, you can define the
structure and appearance of your app's UI
using a set of views. OK, so now we have our views. But we need another step
to actually translate our high level UI code into
the shapes and colors that are displayed on the screen. This is where the rendering
pipeline comes into play. Frameworks like SwiftUI
and UIkit use graphics APIs to render views. Most Apple devices use
the metal framework, which provides direct
access to the GPU. So the UI framework generates a
metal-based rendering pipeline when it comes time to
displaying graphics. This is a great approach
for iOS app development. But one downside is if you want
to deploy to Android or to web, you'll need to rewrite
your app in a new language and framework. And in many cases, you're
working within the confines of the iOS design language. With a cross-platform framework,
the first bit isn't an issue. You can deploy to
multiple platforms from the same code base. But the problem is, a
lot of these frameworks act as an abstraction
over those native views that we mentioned before. Not only do you introduce
this extra layer, which may pose some
performance problems. But you also are still working
within those same design confines. Flutter, on the
other hand, takes a bit of a different approach. With Flutter, you still
have a unified code base, but with a native architecture. You first write your app code
using the Flutter framework. Then, Flutter's engine
converts your code into instructions for
the graphics hardware, just like native frameworks. When your app is compiled, two
iOS frameworks are produced, the App,framework, which
contains your Dart code, and the Flutter.framework,
which contains all the libraries needed to run the Dart code. These frameworks
are then embedded into a Native iOS app
that's created and compiled using Xcode. So when you build
a Flutter iOS app, you're really embedding
your compiled Dart code into a Native iOS app. This structure provides
flexibility, including the ability to
easily add Flutter UI components to an
existing iOS app, or add Native app extensions
like home screen widgets that are written with SwiftUI. Let's dig a little bit
deeper on how all of this works under the hood. When building a Flutter app,
you use the Flutter framework to define your UI. Flutter code is written in
the Dart programming language. Instead of views, UI
components are called widgets. The Flutter framework is
declarative, just like SwiftUI. So the code often
looks pretty similar. Things might be
named differently. Like, an HStack in SwiftUI
is called a Row in Flutter. But overall, if you're
comfortable with SwiftUI, Flutter should feel familiar. One notable difference
is that Flutter uses aggressive
composition where possible. In SwiftUI, you might use a
modifier to modify your view. But in Flutter,
that modification is actually its own widget. Modifications are
represented as widgets which contain other widgets. It's like a Russian
doll of widgets. To learn more about
Flutter syntax and how it compares
to SwiftUI, check out our guide linked below. Anyways, back to
our architecture. Just like SwiftUI and
UIkit, the Flutter framework needs to make some calls
to create render pipelines. This is where the Flutter
engine comes into play. It takes the framework
code and translates it into rendering commands that can
be understood by the graphics hardware on the device. In the case of iOS,
the Flutter engine renders frames using metal,
just like a Native iOS app. OK, so why does this matter? Well, like we mentioned
earlier, getting rid of that extra abstraction
can help with performance. But what's really cool is that
since Flutter talks directly to the iOS graphics
API, you control every pixel on the screen. This means you can create
custom visuals in your app, like the Wonderous app
that I showed before. This flexibility is great. But you may be worried that more
flexibility means more work. To make things easier, there are
sets of pre-configured widgets that match the mobile OS
design, material widgets for Google's design system and
Cupertino widgets for Apple's. My favorite part
of these widgets is that everything
is open source, meaning you can fork and
customize them or propose changes directly
to the framework. See that the padding
looks a bit off? Go ahead and submit an issue. Or if you've got a fix
yourself, submit a pull request with your adjustments. Continuing on with
our discussion on Flutter's
architecture, so far, we've talked about the
framework and the engine. But there's something else,
the platform embedder. This is basically the glue
between Flutter and the host operating system,
in this case, iOS. When you start a Flutter
app, the embedder does a bunch of
things, like providing the entry point for the app
and initializing the Flutter engine. Let's take a closer look. When you create a
new Flutter app, the tool auto-generates folders
for platform-specific files. So for iOS, that's
the iOS Directory. And we can open this
generated workspace in Xcode. Over in Xcode, there's
a target called Runner. Now, a target represents
a single product, in this case, an iOS app. Essentially, the Flutter tool
auto-generates a Native iOS app. And this Native app is the
root of our Flutter iOS app. Let's take a look at these
auto-generated components. So here, we'll open up
this app delegate file. And if you're familiar
with UIkit development, you may have used an app
delegate class before. It serves as the entry
point for an application. It's responsible for setting
up the app's initial state and responding to
system level events. Flutter iOS apps
use an app delegate that inherits from the Flutter
app delegate class, which is responsible for
initializing the Flutter engine and connecting it to
the Native iOS platform. More specifically, it creates
a FlutterEngine object, which is responsible for
running the Dart code and rendering graphics
like we discussed before. The AppDelegate also creates
the FlutterViewController, which passes input
events into Flutter and displays the frames rendered
by the engine using metal. Remember that everything
that we've just talked about is all auto-generated for you. So unless you're doing
something custom, you don't need to
worry about editing it. Now, you might be
wondering, where are these iOS classes coming from? When the AppDelegate
file imports Flutter, it's importing the
Flutter framework. The iOS Flutter framework
contains the engine and related libraries needed
to execute Dart code and render UI on iOS devices. So how does this
framework get embedded? And where does your app
code come into play? Well, remember how we previously
mentioned the Runner target that's automatically created? It has a default
scheme that can be run from Xcode by
pressing the Run button, just like a Native iOS app. When you press the Run button,
Xcode compiles and creates the app. The generated Xcode project
executes a build script. And this script compiles
the app start code into a framework called
App.framework and then copies the Flutter framework
into your build directory. Finally, these frameworks
are embedded into your app and codesigned. OK, so we've been walking
through a Flutter iOS app's architecture in Xcode. But in reality, you would
use Flutter's own tooling to run your app. You can use the Flutter
CLI command, Flutter Run, or the Run button
in your Flutter IDE if you're using VS Code
with the Flutter plugin. Using these tools, you can also
take advantage of hot reload. Hot reload is a
Flutter feature that lets you make changes
to your app's code and see those changes
immediately reflected on your test device, the
iPhone, iPad, or simulator. It maintains your app state. So say you're testing
a screen that requires a few clicks to get there. You don't need to click
through to that screen every time you make a change. Besides hot reload, the process
for compiling a Flutter app is the same under the hood. When you use the
command flutter run to run your app in
debug mode, Flutter is actually just
calling Xcode build to get you an iOS app, which
is the same command that's used when you build your
apps directly from Xcode, like we showed before. OK, so we've covered a lot of
ground, Flutter's framework, engine, and platform embedder. Now, let's talk about
leveraging Swift or Objective-C APIs in your Flutter app. There are a lot of reasons
why you may want to do this. Maybe you want to use
Apple's APIs or frameworks in your Flutter app, like
connecting to the Photos library or kicking off some
on-device machine learning workflow. Most Commonly used APIs have
corresponding Flutter plugins. And a plugin wraps the
Native APIs and exposes a Dart interface that you
can use in your Flutter code. This means that if you
want to write the code to open the photo library,
you can write it once in your Flutter app. Behind the scenes, the plugin
makes the necessary API calls, depending on which platform
your app is running on. And you can find all kinds
of plugins on pup.dev. For quick overviews of some
of our favorite packages, check out our Package
of the Week video series here on YouTube. However, Apple is always coming
out with a new, exciting APIs that us developers
want to try out. And maybe you don't want to
wait for a plugin to be created. Fear not. Most plugins themselves
use something called method channels
that let you communicate with a Native platform. And you can use them right
in your own Flutter app. Remember that AppDelegate
file we showed before? We won't go into
too much detail. But at a high level,
you'll create a new method in that file. And then you can call
it from your Dart code. Alternatively, you can leverage
Dart's interoperability with platform languages. For example, ffigen
is a tool that can be used to
automatically generate bindings, which act as the glue
between Dart and Objective-C or Swift. You tell ffigen what
classes you want to use. And then you can leverage
the generated Dart wrappers directly in your Flutter
app, no Native code needed. OK, one last bit
before we wrap up. An important aspect of
integrating Native SDKs with your Flutter app is
dependency management. Luckily, Flutter
provides a solution for this using Cocoapods. Cocoapods is a dependency
manager for iOS projects that allows you to easily
include external libraries and frameworks in
your Xcode project. Don't worry if you've
never used Cocoapods before because Flutter
takes care of it for you. When you add a dependency
to your Flutter project that requires Cocoapods,
Flutter will automatically generate and configure
the necessary files and configurations for you. This makes it easier
to integrate Native iOS SDKs with your Flutter
app without having to manually manage dependencies
or worry about compatibility issues. And that's Flutter for iOS. Now that you know how Flutter
works under the hood for iOS development, give it a
try for your next app, or consider building your next
feature for your existing iOS app with Flutter. We've curated some great
resources on Flutter for iOS and included them in the
video description below. This includes a reference
guide for Swift and SwiftUI developers, a
beautiful reference app to test out for yourself,
and some additional iOS-focused videos. And if there's
something that you find is difficult or
missing, let us know. Go ahead and file an
issue or add a thumbs up to an existing one on GitHub. Each quarter, we have a survey
that goes out to get feedback from developers like you. So be sure to fill
that out there as well. Our team really appreciates it. And that's it for
Flutter on iOS. I'm Leigha. Thanks for following along. And we can't wait to
see what you build. [MUSIC PLAYING]