Android集成FlutterFragment时Image Picker插件不工作问题求解
Android原生集成Flutter模块Image Picker库运行异常问题解决
问题现象
集成过程中首先抛出插件缺失异常:
Unhandled Exception: MissingPluginException(No implementation found for method pickImage on channel plugins.flutter.io/image_picker_android)
初步定位为GeneratedPluginRegistrant未完成注册,需要重写configureFlutterEngine方法完成插件注册。但业务场景需要在Fragment中打开Flutter模块,无法直接让Activity继承FlutterActivity,该类不支持getSupportFragmentManager调用。
尝试将Activity改为继承FlutterFragmentActivity后,虽然可以重写configureFlutterEngine方法,但又抛出视图找不到的错误:
java.lang.IllegalArgumentException: No view found for id 0x245a3c5c (unknown) for fragment FlutterFragment{647abea (0b17a247-4e8e-42bc-b5f3-6ab0796e458b) id=0x245a3c5c flutter_fragment}
原有问题代码
MainActivity.java
package com.mch.testplugin; import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.android.FlutterFragment; import io.flutter.embedding.android.FlutterFragmentActivity; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngineCache; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends AppCompatActivity { Context mContext; FlutterFragment flutterFragment; private static final String TAG_FLUTTER_FRAGMENT = "flutter_fragment"; FlutterEngine mFlutterEngine; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; setContentView(R.layout.activity_main); Button myButton = findViewById(R.id.myButton); myButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flutterFragment = (FlutterFragment) getSupportFragmentManager() .findFragmentByTag(TAG_FLUTTER_FRAGMENT); // Create and attach a FlutterFragment if one does not exist. if (flutterFragment == null) { flutterFragment = FlutterFragment.createDefault(); flutterFragment = FlutterFragment.withNewEngine() .initialRoute("/") .build(); getSupportFragmentManager() .beginTransaction() .add( R.id.frame_layout, flutterFragment, TAG_FLUTTER_FRAGMENT ) .commit(); } }); } // @Override // public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { //// super.configureFlutterEngine(flutterEngine); // mFlutterEngine = flutterEngine; // GeneratedPluginRegistrant.registerWith(new FlutterEngine(this)); // } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> <FrameLayout android:id="@+id/frame_layout" android:layout_width="match_parent" android:layout_height="200dp" /> </androidx.constraintlayout.widget.ConstraintLayout>
修复方案
问题根源有三点:
- 继承
AppCompatActivity时configureFlutterEngine不会被系统回调,插件注册逻辑根本没有执行;注释里的注册代码还错误地新建了FlutterEngine实例,和FlutterFragment实际绑定的Engine不是同一个,就算执行也不会生效。 - 布局使用ConstraintLayout但没有给子控件添加约束,FrameLayout没有被正确加载到视图树,导致Fragment事务执行时找不到对应id的容器。
- 代码里冗余调用了
FlutterFragment.createDefault(),后续又重新构建了Fragment实例,属于无效代码。
按如下修改即可正常运行:
修改后的MainActivity.java
package com.mch.testplugin; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.annotation.NonNull; import io.flutter.embedding.android.FlutterFragment; import io.flutter.embedding.android.FlutterFragmentActivity; import io.flutter.embedding.engine.FlutterEngine; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterFragmentActivity { private FlutterFragment flutterFragment; private static final String TAG_FLUTTER_FRAGMENT = "flutter_fragment"; private FlutterEngine mFlutterEngine; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button myButton = findViewById(R.id.myButton); myButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flutterFragment = (FlutterFragment) getSupportFragmentManager() .findFragmentByTag(TAG_FLUTTER_FRAGMENT); if (flutterFragment == null) { flutterFragment = FlutterFragment.withNewEngine() .initialRoute("/") .build(); getSupportFragmentManager() .beginTransaction() .add( R.id.frame_layout, flutterFragment, TAG_FLUTTER_FRAGMENT ) .commit(); } } }); } @Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { super.configureFlutterEngine(flutterEngine); mFlutterEngine = flutterEngine; GeneratedPluginRegistrant.registerWith(flutterEngine); } }
修改后的activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/myButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="打开Flutter模块" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="20dp"/> <FrameLayout android:id="@+id/frame_layout" android:layout_width="match_parent" android:layout_height="200dp" app:layout_constraintTop_toBottomOf="@id/myButton" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="20dp"/> </androidx.constraintlayout.widget.ConstraintLayout>
补充说明
FlutterFragmentActivity本身是AppCompatActivity的子类,完全兼容原生Fragment的所有API,不存在无法调用getSupportFragmentManager的问题。- 如果对Flutter模块启动速度有要求,可以提前在Application类中初始化FlutterEngine并缓存,构建FlutterFragment时使用
withCachedEngine()方法传入缓存的Engine ID,能大幅降低页面打开耗时。
内容的提问来源于stack exchange,提问作者Lak
相关产品推荐
相关产品推荐

