kotlin 当上下文是MutableContextWrapper并且需要添加到View类时,如何在Flutter应用中将Android Fragment作为原生视图托管

ryevplcw  于 2023-04-07  发布在  Kotlin
关注(0)|答案(1)|浏览(183)

我需要在我的Flutter应用程序中托管一个嵌入式原生视图,
我有一个Android Fragment,我试图将其添加到在FlutterEngine中注册的View
但需要添加片段:

(context as FragmentActivity).supportFragmentManager

由于现有的上下文是MutableContextWrapper,因此该方法不起作用
有什么需要帮忙的吗?

主活动:

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() { ... }

日志:

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

添加此Android原生片段到Flutter应用程序

kokeuurv

kokeuurv1#

要将Android Fragment添加到Flutter应用中,您需要遵循以下几个步骤:
在Flutter和Android之间创建一个平台通道,以便相互通信。
在Android项目中,创建一个扩展PlatformView并实现OnCreate和OnDestroy方法的新类。
在OnCreate方法中,创建Fragment的示例并将其添加到ViewGroup。
在Flutter小部件的构建方法中,使用AndroidView小部件添加平台视图。
下面是一些示例代码来帮助您开始:
在Android项目中,创建一个扩展PlatformView的新类:

public class MyPlatformView implements PlatformView, OnCreateListener, OnDestroyListener {
  private final FrameLayout layout;
  private final FragmentActivity activity;

  public MyPlatformView(Context context, int id, Map<String, Object> creationParams) {
    activity = (FragmentActivity) context;
    layout = new FrameLayout(context);
    activity.getSupportFragmentManager()
        .beginTransaction()
        .add(id, MyFragment.newInstance(), "MyFragment")
        .commit();
  }

  @Override
  public View getView() {
    return layout;
  }

  @Override
  public void onCreate() {
  }

  @Override
  public void onDestroy() {
  }
}

在Flutter小部件中,使用AndroidView小部件添加平台视图:

class MyFlutterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AndroidView(
          viewType: 'myViewType',
          creationParams: {'myParam': 'myValue'},
          creationParamsCodec: const StandardMessageCodec(),
        ),
      ),
    );
  }
}

请注意,在AndroidView小部件中,viewType必须与您在FlutterEngine中注册MyPlatformView类时使用的名称匹配,您可以通过调用FlutterEngine.getPlugins().add(new MyPlugin())来注册MyPlatformView类;其中MyPlugin是实现registerWith的FlutterPlugin。

相关问题