I need to host an embedded native view into my Flutter app,
I have an Android Fragment and me trying to add it to the View
class that registered in FlutterEngine
but Fragments need to be added:
(context as FragmentActivity).supportFragmentManager
And that does not work due to the existing context is MutableContextWrapper
Any help, please?
MainActivity:
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
flutterEngine
.platformViewsController
.registry
.registerViewFactory("EmbeddedNavigationView.kt", EmbeddedNavigationFactory(mapOf("text" to "hello!")))
}
}
EmbeddedNavigationView:
class EmbeddedNavigationView(context: Context, val viewParams: Map<String, Any>) : View(context), PlatformView {
private lateinit var fragmentMap: Fragment
private val fragment: Fragment = FlutterFragment.createDefault()
init {
initObjects()
initSubView()
}
private fun initObjects() {
fragmentMap = MapFragment()
}
private fun initSubView() {
addFragment(fragmentMap)
}
private fun addFragment(fragment: Fragment) {
// thow error due to MutableContextWrapper is not a FragmentActivity
val fragmentManager = (context as FragmentActivity).supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.add(R.id.fragment_map, fragment)
transaction.commit()
}
private fun removeFragment(fragment: Fragment) {
val fragmentManager = (context as FragmentActivity).supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.remove(fragment)
transaction.commit()
}
override fun onDraw(canvas: Canvas) {
// Draw the view's content
super.onDraw(canvas)
}
override fun onDetachedFromWindow() {
// Remove the fragment when the view is detached
fragmentMap?.let {
(context as AppCompatActivity).supportFragmentManager.beginTransaction().remove(it).commit()
}
super.onDetachedFromWindow()
}
class MyFragment : Fragment() {
// Fragment code here
}
override fun getView(): View? {
return this
TODO("Not yet implemented")
}
override fun dispose() {
// impl dispose
TODO("Not yet implemented")
}
}
EmbeddedNavigationFactory:
class EmbeddedNavigationFactory(private val createParams: Map<String, Any>?) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val viewParams = createParams ?: args as? Map<String, Any> ?: mapOf()
return EmbeddedNavigationView(context, viewParams)
}
}
MapFragment:
class MapFragment : androidx.fragment.app.Fragment() { ... }
Logs:
Launching lib/main.dart on 2201117TG in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app-debug.apk...
Debug service listening on ws://127.0.0.1:50805/JtPxjixFiC4=/ws
Syncing files to device 2201117TG...
E/MethodChannel#flutter/platform_views(15059): Failed to handle method call
E/MethodChannel#flutter/platform_views(15059): java.lang.ClassCastException: android.content.MutableContextWrapper cannot be cast to androidx.fragment.app.FragmentActivity
E/MethodChannel#flutter/platform_views(15059): at com.example.mapbox_android_update.EmbeddedNavigationView.addFragment(EmbeddedNavigationView.kt:29)
E/MethodChannel#flutter/platform_views(15059): at com.example.mapbox_android_update.EmbeddedNavigationView.initSubView(EmbeddedNavigationView.kt:26)
E/MethodChannel#flutter/platform_views(15059): at com.example.mapbox_android_update.EmbeddedNavigationView.<init>(EmbeddedNavigationView.kt:20)
E/MethodChannel#flutter/platform_views(15059): at com.example.mapbox_android_update.EmbeddedNavigationFactory.create(EmbeddedNavigationFactory.kt:19)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.plugin.platform.PlatformViewsController$1.createPlatformView(PlatformViewsController.java:503)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.plugin.platform.PlatformViewsController$1.createForTextureLayer(PlatformViewsController.java:191)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.embedding.engine.systemchannels.PlatformViewsChannel$1.create(PlatformViewsChannel.java:128)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.embedding.engine.systemchannels.PlatformViewsChannel$1.onMethodCall(PlatformViewsChannel.java:55)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/MethodChannel#flutter/platform_views(15059): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/MethodChannel#flutter/platform_views(15059): at android.os.Handler.handleCallback(Handler.java:938)
E/MethodChannel#flutter/platform_views(15059): at android.os.Handler.dispatchMessage(Handler.java:99)
E/MethodChannel#flutter/platform_views(15059): at android.os.Looper.loopOnce(Looper.java:210)
E/MethodChannel#flutter/platform_views(15059): at android.os.Looper.loop(Looper.java:299)
E/MethodChannel#flutter/platform_views(15059): at android.app.ActivityThread.main(ActivityThread.java:8309)
E/MethodChannel#flutter/platform_views(15059): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#flutter/platform_views(15059): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
E/MethodChannel#flutter/platform_views(15059): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1038)
E/flutter (15059): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, android.content.MutableContextWrapper cannot be cast to androidx.fragment.app.FragmentActivity, null, java.lang.ClassCastException: android.content.MutableContextWrapper cannot be cast to androidx.fragment.app.FragmentActivity
E/flutter (15059): at com.example.mapbox_android_update.EmbeddedNavigationView.addFragment(EmbeddedNavigationView.kt:29)
E/flutter (15059): at com.example.mapbox_android_update.EmbeddedNavigationView.initSubView(EmbeddedNavigationView.kt:26)
E/flutter (15059): at com.example.mapbox_android_update.EmbeddedNavigationView.<init>(EmbeddedNavigationView.kt:20)
E/flutter (15059): at com.example.mapbox_android_update.EmbeddedNavigationFactory.create(EmbeddedNavigationFactory.kt:19)
E/flutter (15059): at io.flutter.plugin.platform.PlatformViewsController$1.createPlatformView(PlatformViewsController.java:503)
E/flutter (15059): at io.flutter.plugin.platform.PlatformViewsController$1.createForTextureLayer(PlatformViewsController.java:191)
E/flutter (15059): at io.flutter.embedding.engine.systemchannels.PlatformViewsChannel$1.create(PlatformViewsChannel.java:128)
E/flutter (15059): at io.flutter.embedding.engine.systemchannels.PlatformViewsChannel$1.onMethodCall(PlatformViewsChannel.java:55)
E/flutter (15059): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/flutter (15059): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/flutter (15059): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/flutter (15059): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter (15059): at android.os.Handler.handleCallback(Handler.java:938)
E/flutter (15059): at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter (15059): at android.os.Looper.loopOnce(Looper.java:210)
E/flutter (15059): at android.os.Looper.loop(Looper.java:299)
E/flutter (15059): at android.app.ActivityThread.main(ActivityThread.java:8309)
E/flutter (15059): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (15059): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
E/flutter (15059): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1038)
E/flutter (15059): )
E/flutter (15059): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter (15059): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18)
E/flutter (15059): <asynchronous suspension>
E/flutter (15059): #2 TextureAndroidViewController._sendCreateMessage (package:flutter/src/services/platform_views.dart:1141:28)
E/flutter (15059): <asynchronous suspension>
E/flutter (15059): #3 AndroidViewController.create (package:flutter/src/services/platform_views.dart:801:5)
E/flutter (15059): <asynchronous suspension>
E/flutter (15059): #4 AndroidViewController.setSize (package:flutter/src/services/platform_views.dart:828:7)
E/flutter (15059): <asynchronous suspension>
E/flutter (15059): #5 RenderAndroidView._sizePlatformView (package:flutter/src/rendering/platform_view.dart:182:29)
E/flutter (15059): <asynchronous suspension>
E/flutter (15059):
E/_android_updat(15059): open libmigui.so failed! dlopen - dlopen failed: library "libmigui.so" not found
D/DecorView[](15059): onWindowFocusChanged hasWindowFocus true
adding this android native fragment to flutter app
2
Answers
solved you can use the data binding method to access the fragment
To add an Android Fragment into your Flutter app, you need to follow a few steps:
Create a platform channel between Flutter and Android to communicate with each other.
In your Android project, create a new class that extends PlatformView and implements OnCreate and OnDestroy methods.
In the OnCreate method, create an instance of your Fragment and add it to your ViewGroup.
In the build method of your Flutter widget, add your platform view using the AndroidView widget.
Here’s some sample code to help you get started:
In your Android project, create a new class that extends PlatformView:
In your Flutter widget, use the AndroidView widget to add your platform view:
Note that in the AndroidView widget, viewType must match the name you used to register your MyPlatformView class in your FlutterEngine. You can register your MyPlatformView class by calling FlutterEngine.getPlugins().add(new MyPlugin()); where MyPlugin is a FlutterPlugin that implements registerWith.