Flutter PlatformView: How to host native android and iOS view in Flutter
Flutter does a great job when it comes to building beautiful UI by leveraging all these widgets that are available in flutter SDK, But sometime we might want to show the same native UI in your flutter application.
This is where Flutter Platform View comes to the rescue.
Hello guys, This is CodingWithTashi and in this shitty post, we are going to learn how to host native Android and iOS views in your Flutter app with Platform Views.
This post is inspired from How to create Widgets from Native Views by Felix (Author or flutter_bloc). Feel free to check out his article as well.
Flutter offer PlatformView
which allows us to embed Android or iOS Views in the flutter widget hierarchy without doing much work.
As Felix mentioned in his post This opens the door to many possibilities like fully integrated maps and web views in your flutter applications.
At the time of writing this post, Flutter support only mobile platform
- Android
- iOS
Desktop support is not available yet, You can refer to this open issue for more updates.
Also, Flutter provides very good documentation on Hosting Platform View for android and iOS, Feel free to check out their official documentation link attached below.
Before we start here are some quick things to note are:
- As of now, supported platforms are Android and iOS only
Android:
- They are two ways to host PatformView on android
- Virtual displays
Virtual displays render the
android.view.View
instance to a texture, so it’s not embedded within the Android Activity’s view hierarchy. Certain platform interactions such as keyboard handling and accessibility features might not work.
- minSdkVersion should be 20 for Virtual display
2. Hybrid composition
Hybrid composition appends the native
android.view.View
to the view hierarchy. Therefore, keyboard handling and accessibility work out of the box. Prior to Android 10, this mode might significantly reduce the frame throughput (FPS) of the Flutter UI. See performance for more info
- minSdkVersion should be 19 if you are using Hybrid composition.
iOS:
- There is only one way to host PatformView on iOS
iOS only uses Hybrid composition, which means that the native
UIView
is appended to the view hierarchy.
Alright with that said In this post we are going learn how to host platform view in android and iOS by creating a simple WebViewPlugin
where we will expose a native android and iOS WebView
as a Flutter Widget.
These are the topic that we will cover.
- How to communicate dart to native?
- How to create a WebView plugin from scratch?
- How to host a native WebView in the flutter widget?
Here is an overview of how our map_plugin works.
Great, now that we know what and how we are hosting our Platforms let’s try to understand by building a simple WebViewPlugin
.
Let’s get our hands dirty 😊.
The first thing we’re going to need to do is to create a new flutter plugin:
We will write all android code in an android folder and iOS logic in an ios folder accordingly.
example folder is used to test our plugin and the lib folder is where we write our dart logic to communicate with android and iOS.
After the Flutter Plugin has been created successfully, we can start by creating our WebView
class in ./lib/web_view.dart
In this code, we are returning AndroidView
andUiKitView
base on the platform.
For the full AndroidView
and UiKitView
documentation check out https://docs.flutter.io/flutter/widgets/AndroidView-class.html.
https://api.flutter.dev/flutter/widgets/UiKitView-class.html
An important thing to note here is that when we create AndroidView or UiKitView on lines no 15 and 20 we need to provide a viewType
which we will use at a later point in time.
You might get a red error in the test folder and example folder. Since we are not going to do any test cases for this plugin, You can delete the test folder and fix the example folder by removing the error code within the main.dart
file. (We will fix it later)
Additionally, we have provided onPlatformCompleted
method so that we can provide the WebView widget with a WebViewController
which we can then use to update its URL using setUrl
method.
Next, we need to work on the Android implementation of our WebViewPlugin
.
Android Implementation
To make our life easier let's open android/src/main/kotlin/{organization_name}/WebViewPlugin.kt
-> Select Open for Editing in Android Studio.
Then Android project in the new window and sync the gradle
first. Once done replace your WebViewPlugin.kt
content with the following
All we are doing here is adding the extending WebViewPlugin
with FlutterPlugin
and then override
two methods.
In onAttAchedToEngine
method, we registerViewFactory
by providing the viewType
which we defined earlier in webview.dart
as well as providing a WebViewFactory
which will be creating our native WebView
as a PlatformView
.
You will get an error for WebViewFactory.
Next, we fix this issue by creating WebViewFactory.kt
at android/src/main/kotlin/{organization_name}/
and extend PlatformViewFactory
.
Our WebViewFactory
implements the create
the method which returns a PlatformView
(in our case it will return a FlutterWebView
). Now you can go back to WebViewPlugin.kt
and fix the earlier error by importing WebViewFactory.kt
at this point, you will get an error for FlutterWebView since this class doesn't exist. We will fix it by creating FlutterWebView.kt
at android/src/main/kotlin/{organization_name}/
and implement PlatformView
as well as MethodCallHandler
so that we can have our native view painted as a flutter widget and be able to receive data from dart via a MethodChannel
.
FlutterWebView
creates a new WebView
and sets up a MethodChannel
so that the WebView
can receive data from dart code and make updates (in this case update the URL).
In order to implement PlatformView
, we need to override getView
and return our webView
as well as override dispose
(which in this case destroys WebView when PlatformView is destroyed).
In order to implement MethodCallHandler
, we need to override onMethodCall
and, depending on the method, either call our internal setUrl
method (to update the WebView URL) or return result.notImplemented
since we currently don’t support any other methods.
Now it’s time to test our new WebView
widget!
Open flutter project, Go to ./example/lib/main.dart
and replace it with the following code:
This should look familiar. We are running a MaterialApp
that renders a Scaffold
. We have our Column
that contains TextFormField
to enter url
,Elevated
to load the url
in the WebView.
We also have our implementation for onWebViewCreated
where we call the setUrl
method.
We can also set the url
manually with the help of TextEditingController
and WebViewController
.
With that said our Android Implementation is done, Quite work huh? You have learned a lot as well.
It’s time to run our example flutter app and take a look at what we’ve built.
Great! We’ve proven that you can now create any native Android view as a flutter widget which is pretty powerful and interesting.
You should also be able to run iOS applications though WebView
will not work since we have not implemented iOS logic yet.
Let’s see how we can achieve the same thing in iOS as well, don’t worry we have done most of the work already. Let's straight go to the iOS implementation.
iOS Implementation
Open ios/Classes/SwiftWebViewPlugin.swift
. You can either continue using Android Studio or open the same project in Xcode. I would encourage you to use Xcode since you can take advantage of IntelliSense.
Important: To open your project in Xcode, head over to example -> ios -> Runner -> Select tool on top option menu -> Flutter -> Open ios Module in Xcode
Screenshot attached below
You can also run the application one more time in the simulator to see if all work fine.
Okay, now that is done, let's replace SwiftWebViewPlugin.swift
it with the following content.
All we are doing here is extending SwiftWebViewPlugin
with FlutterPlugin
and then added register
method.
In register
method, Similar to android, we register registerViewFactory
by providing WebViewFactory
which will be creating our native WebView
as a PlatformView
and the withId
which we already defined earlier in webview.dart
You will again get an error for WebViewFactory.
Next, we fix this issue by creating WebViewFactory.swift
in the same path.
Create swift file WebViewFactory.swift
under ios/Classes/
and extend PlatformViewFactory
.
Our WebViewFactory
implements the create
the method which returns a PlatformView
(in our case it will return a FlutterWebView
).
at this point, you will get an error for FlutterWebView since this class doesn’t exist. We will fix it by creating FlutterWebView.swift
at the same location.
Create swift file FlutterWebView.swift
underios/Classes/
and implement FutterPlatformView
so that we can have our native view painted as a flutter.
FlutterWebView
creates a new WebView
and sets up a MethodChannel
so that the WebView
can receive data from dart code and make updates (in this case update the URL).
In order to implement PlatformView
, we need to override view
and return our webView
.
We have also added onMethodCall
and, depending on the method, either call our internal setUrl
method (to update the WebView URL) or return result(FlutterMethodNotImplmented)
since we currently don’t support any other methods.
With that said our iOS Implementation is also done, Yay!! If you are still reading this, You have done a great job learning how to build your own plugin with platform view.
It’s time to run our crappy example app and take a last look and see what we’ve built.
Seems working fine. We have not cover any test cases for this plugin since this is not a production plugin. so we’ll cover this at some other time. You can check out the complete source code at https://github.com/codingwithtashi/flutter_web_view.
Thanks, guys, That’s all for now, Make sure to give a clap 👏 and leave some engagement. If there is any correction or feedback feel free to leave a comment as well.
If any of my shitty posts help you in any way, you can consider buying me a cup of coffee. I will personally thank you 🙏.
Check out similar posts from CodingWithTashi. Connect me on Twitter or Linkedin
Follow Flutter Community on Twitter: https://www.twitter.com/FlutterComm