Flutter在Android端注册插件流程源码解析

1,694 阅读7分钟

先发一段Flutter在Android注册插件的代码流程,这里就拿我之前写的Flutter与Android的混合开发(2)Activity如何跳转到Flutter页面,如何传值里的PageFlutterActivity.kt类来举例

PageFlutterActivity.kt

package com.liuhc.myapplication

import android.os.Bundle
import android.util.Log
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodChannel
import io.flutter.view.FlutterMain
import org.json.JSONObject

/**
 * 描述:
 * 作者:liuhc
 * 创建日期:2019-09-04 on 23:30
 */
class PageFlutterActivity : FlutterActivity() {

    private lateinit var methodChannel: MethodChannel

    override fun onCreate(savedInstanceState: Bundle?) {
        //强烈建议放到Application里初始化,初始化一次即可,放这里只是举个例子
        FlutterMain.startInitialization(this)
        //intent的参数设置必须在super.onCreate之前,因为super.onCreate里会取这些参数
        intent.action = "android.intent.action.RUN"
        val channelName = "channelName_PageFlutterActivity"
        val androidMethod = "methodName_PageFlutterActivity"
        val jsonObject = JSONObject()
        jsonObject.put("path", "InvokeMethodPage")
        jsonObject.put("title", "PageFlutterActivity")
        jsonObject.put("channelName", channelName)
        jsonObject.put("androidMethod", androidMethod)
        intent.putExtra("route", jsonObject.toString())
        super.onCreate(savedInstanceState)
        //调用super.onCreate(savedInstanceState)之后flutterView才有值,
        //所以如果需要注册插件,则应该放到super.onCreate(savedInstanceState)代码之后才可以
        flutterView.enableTransparentBackground()
        //如果不需要平台交互的话,只需要上面的代码并在最后加上super.onCreate就可以了
        //这里this.registrarFor方法实际调用的是FlutterFragmentActivity里的delegate的registrarFor方法,
        //而delegate的registrarFor方法实际调用的是FlutterActivityDelegate里的flutterView.getPluginRegistry().registrarFor方法,
        //而FlutterActivityDelegate里的flutterView在调用了这里的super.onCreate(savedInstanceState)才有值,
        //所以如果需要注册插件,则应该放到super.onCreate(savedInstanceState)代码之后才可以
        val key = "PageFlutterActivity"
        if (this.hasPlugin(key)) return
        val registrar = this.registrarFor(key)
        methodChannel = MethodChannel(
            registrar.messenger(),
            channelName
        )
        methodChannel.setMethodCallHandler { methodCall, result ->
            if (methodCall.method == androidMethod) {
                Log.e("Android", "接收到了Flutter传递的参数:${methodCall.arguments}")
                result.success("$androidMethod ok")
                Log.e("Android", "主动调用Flutter的methodInvokeMethodPageState方法")
                methodChannel.invokeMethod("methodInvokeMethodPageState", "Android发送给Flutter的参数")
            }
        }
    }

}

看其中的这段代码

methodChannel = MethodChannel(
    registrar.messenger(),
    channelName
)

MethodChannel这里我们传了2个参数,第二个就是一个String类型,我们主要看第一个registrar.messenger()是什么,这个registrar是我们调用父类的方法registrarFor(key)得到的,所以我们去父类查看registrarFor方法,源码如下:

FlutterActivity

public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
    private static final String TAG = "FlutterActivity";
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }

    public FlutterView getFlutterView() {
        return this.viewProvider.getFlutterView();
    }

    public final boolean hasPlugin(String key) {
        return this.pluginRegistry.hasPlugin(key);
    }

    public final Registrar registrarFor(String pluginKey) {
        return this.pluginRegistry.registrarFor(pluginKey);
    }
    //删掉了这里不需要关心的代码
}

可以看到registrarFor方法调用的是this.pluginRegistry.registrarFor方法,而this.pluginRegistry在构造函数里可看到实际上是FlutterActivityDelegate类的实例,所以我们再去看FlutterActivityDelegate的源码

FlutterActivityDelegate

public final class FlutterActivityDelegate implements FlutterActivityEvents, Provider, PluginRegistry {
    private static final String SPLASH_SCREEN_META_DATA_KEY = "io.flutter.app.android.SplashScreenUntilFirstFrame";
    private static final String TAG = "FlutterActivityDelegate";
    private static final LayoutParams matchParent = new LayoutParams(-1, -1);
    private final Activity activity;
    private final FlutterActivityDelegate.ViewFactory viewFactory;
    private FlutterView flutterView;
    private View launchView;

    public FlutterActivityDelegate(Activity activity, FlutterActivityDelegate.ViewFactory viewFactory) {
        this.activity = (Activity)Preconditions.checkNotNull(activity);
        this.viewFactory = (FlutterActivityDelegate.ViewFactory)Preconditions.checkNotNull(viewFactory);
    }

    public FlutterView getFlutterView() {
        return this.flutterView;
    }

    public boolean hasPlugin(String key) {
        return this.flutterView.getPluginRegistry().hasPlugin(key);
    }

    public Registrar registrarFor(String pluginKey) {
        return this.flutterView.getPluginRegistry().registrarFor(pluginKey);
    }

    public void onCreate(Bundle savedInstanceState) {
        if (VERSION.SDK_INT >= 21) {
            Window window = this.activity.getWindow();
            window.addFlags(-2147483648);
            window.setStatusBarColor(1073741824);
            window.getDecorView().setSystemUiVisibility(1280);
        }

        String[] args = getArgsFromIntent(this.activity.getIntent());
        FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
        this.flutterView = this.viewFactory.createFlutterView(this.activity);
        if (this.flutterView == null) {
            FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
            this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
            this.flutterView.setLayoutParams(matchParent);
            this.activity.setContentView(this.flutterView);
            this.launchView = this.createLaunchView();
            if (this.launchView != null) {
                this.addLaunchView();
            }
        }

        if (!this.loadIntent(this.activity.getIntent())) {
            String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
            if (appBundlePath != null) {
                this.runBundle(appBundlePath);
            }

        }
    }

    private boolean loadIntent(Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.RUN".equals(action)) {
            String route = intent.getStringExtra("route");
            String appBundlePath = intent.getDataString();
            if (appBundlePath == null) {
                appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
            }

            if (route != null) {
                this.flutterView.setInitialRoute(route);
            }

            this.runBundle(appBundlePath);
            return true;
        } else {
            return false;
        }
    }

    private void runBundle(String appBundlePath) {
        if (!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
            FlutterRunArguments args = new FlutterRunArguments();
            ArrayList<String> bundlePaths = new ArrayList();
            bundlePaths.add(appBundlePath);
            args.bundlePaths = (String[])bundlePaths.toArray(new String[0]);
            args.entrypoint = "main";
            this.flutterView.runFromBundle(args);
        }

    }

    public interface ViewFactory {
        FlutterView createFlutterView(Context var1);

        FlutterNativeView createFlutterNativeView();

        boolean retainFlutterNativeView();
    }
    //删掉了这里不需要关心的代码
}

找到其中的registrarFor方法

public Registrar registrarFor(String pluginKey) {
    return this.flutterView.getPluginRegistry().registrarFor(pluginKey);
}

发现调用的是this.flutterView.getPluginRegistry().registrarFor(pluginKey),我们再去看FlutterView的源码

FlutterView

public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry {
    private FlutterNativeView mNativeView;

    public FlutterView(Context context) {
        this(context, (AttributeSet)null);
    }

    public FlutterView(Context context, AttributeSet attrs) {
        this(context, attrs, (FlutterNativeView)null);
    }

    public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
        super(context, attrs);
        this.nextTextureId = new AtomicLong(0L);
        this.mIsSoftwareRenderingEnabled = false;
        this.onAccessibilityChangeListener = new OnAccessibilityChangeListener() {
            public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
                FlutterView.this.resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
            }
        };
        Activity activity = getActivity(this.getContext());
        if (activity == null) {
            throw new IllegalArgumentException("Bad context");
        } else {
            if (nativeView == null) {
                this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
            } else {
                this.mNativeView = nativeView;
            }

            this.dartExecutor = this.mNativeView.getDartExecutor();
            this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
            this.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
            this.mMetrics = new FlutterView.ViewportMetrics();
            this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
            this.setFocusable(true);
            this.setFocusableInTouchMode(true);
            this.mNativeView.attachViewAndActivity(this, activity);
            this.mSurfaceCallback = new Callback() {
                public void surfaceCreated(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
                }

                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
                }

                public void surfaceDestroyed(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
                }
            };
            this.getHolder().addCallback(this.mSurfaceCallback);
            this.mActivityLifecycleListeners = new ArrayList();
            this.mFirstFrameListeners = new ArrayList();
            this.navigationChannel = new NavigationChannel(this.dartExecutor);
            this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
            this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
            this.localizationChannel = new LocalizationChannel(this.dartExecutor);
            this.platformChannel = new PlatformChannel(this.dartExecutor);
            this.systemChannel = new SystemChannel(this.dartExecutor);
            this.settingsChannel = new SettingsChannel(this.dartExecutor);
            PlatformPlugin platformPlugin = new PlatformPlugin(activity, this.platformChannel);
            this.addActivityLifecycleListener(platformPlugin);
            this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method");
            PlatformViewsController platformViewsController = this.mNativeView.getPluginRegistry().getPlatformViewsController();
            this.mTextInputPlugin = new TextInputPlugin(this, this.dartExecutor, platformViewsController);
            this.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel, this.mTextInputPlugin);
            this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterRenderer);
            this.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(this.mTextInputPlugin);
            this.sendLocalesToDart(this.getResources().getConfiguration());
            this.sendUserPlatformSettingsToDart();
        }
    }

    public FlutterNativeView getFlutterNativeView() {
        return this.mNativeView;
    }

    public FlutterPluginRegistry getPluginRegistry() {
        return this.mNativeView.getPluginRegistry();
    }

    public interface Provider {
        FlutterView getFlutterView();
    }
}

找到其中的getPluginRegistry方法

public FlutterPluginRegistry getPluginRegistry() {
    return this.mNativeView.getPluginRegistry();
}

this.mNativeViewFlutterNativeView的实例,我们再去看FlutterNativeView

FlutterNativeView

public class FlutterNativeView implements BinaryMessenger {
    private static final String TAG = "FlutterNativeView";
    private final FlutterPluginRegistry mPluginRegistry;
    private final DartExecutor dartExecutor;
    private FlutterView mFlutterView;
    private final FlutterJNI mFlutterJNI;
    private final Context mContext;
    private boolean applicationIsRunning;

    public FlutterNativeView(@NonNull Context context) {
        this(context, false);
    }

    public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
        this.mContext = context;
        this.mPluginRegistry = new FlutterPluginRegistry(this, context);
        this.mFlutterJNI = new FlutterJNI();
        this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
        this.dartExecutor = new DartExecutor(this.mFlutterJNI);
        this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
        this.attach(this, isBackgroundView);
        this.assertAttached();
    }

    @NonNull
    public FlutterPluginRegistry getPluginRegistry() {
        return this.mPluginRegistry;
    }

    public void runFromBundle(FlutterRunArguments args) {
        boolean hasBundlePaths = args.bundlePaths != null && args.bundlePaths.length != 0;
        if (args.bundlePath == null && !hasBundlePaths) {
            throw new AssertionError("Either bundlePath or bundlePaths must be specified");
        } else if ((args.bundlePath != null || args.defaultPath != null) && hasBundlePaths) {
            throw new AssertionError("Can't specify both bundlePath and bundlePaths");
        } else if (args.entrypoint == null) {
            throw new AssertionError("An entrypoint must be specified");
        } else {
            if (hasBundlePaths) {
                this.runFromBundleInternal(args.bundlePaths, args.entrypoint, args.libraryPath);
            } else {
                this.runFromBundleInternal(new String[]{args.bundlePath, args.defaultPath}, args.entrypoint, args.libraryPath);
            }

        }
    }

    /** @deprecated */
    @Deprecated
    public void runFromBundle(String bundlePath, String defaultPath, String entrypoint, boolean reuseRuntimeController) {
        this.runFromBundleInternal(new String[]{bundlePath, defaultPath}, entrypoint, (String)null);
    }

    private void runFromBundleInternal(String[] bundlePaths, String entrypoint, String libraryPath) {
        this.assertAttached();
        if (this.applicationIsRunning) {
            throw new AssertionError("This Flutter engine instance is already running an application");
        } else {
            this.mFlutterJNI.runBundleAndSnapshotFromLibrary(bundlePaths, entrypoint, libraryPath, this.mContext.getResources().getAssets());
            this.applicationIsRunning = true;
        }
    }

    @UiThread
    public void send(String channel, ByteBuffer message) {
        this.dartExecutor.send(channel, message);
    }

    @UiThread
    public void send(String channel, ByteBuffer message, BinaryReply callback) {
        if (!this.isAttached()) {
            Log.d("FlutterNativeView", "FlutterView.send called on a detached view, channel=" + channel);
        } else {
            this.dartExecutor.send(channel, message, callback);
        }
    }

    @UiThread
    public void setMessageHandler(String channel, BinaryMessageHandler handler) {
        this.dartExecutor.setMessageHandler(channel, handler);
    }

    FlutterJNI getFlutterJNI() {
        return this.mFlutterJNI;
    }
    //删掉了不需要关心的代码
}

找到其中的getPluginRegistry方法

@NonNull
public FlutterPluginRegistry getPluginRegistry() {
    return this.mPluginRegistry;
}

然后再看一下FlutterPluginRegistry的代码

FlutterPluginRegistry

public class FlutterPluginRegistry implements PluginRegistry, RequestPermissionsResultListener, ActivityResultListener, NewIntentListener, UserLeaveHintListener, ViewDestroyListener {
    private static final String TAG = "FlutterPluginRegistry";
    private Activity mActivity;
    private Context mAppContext;
    private FlutterNativeView mNativeView;
    private FlutterView mFlutterView;
    private final PlatformViewsController mPlatformViewsController;
    private final Map<String, Object> mPluginMap = new LinkedHashMap(0);
    private final List<RequestPermissionsResultListener> mRequestPermissionsResultListeners = new ArrayList(0);
    private final List<ActivityResultListener> mActivityResultListeners = new ArrayList(0);
    private final List<NewIntentListener> mNewIntentListeners = new ArrayList(0);
    private final List<UserLeaveHintListener> mUserLeaveHintListeners = new ArrayList(0);
    private final List<ViewDestroyListener> mViewDestroyListeners = new ArrayList(0);

    public FlutterPluginRegistry(FlutterNativeView nativeView, Context context) {
        this.mNativeView = nativeView;
        this.mAppContext = context;
        this.mPlatformViewsController = new PlatformViewsController();
    }

    public FlutterPluginRegistry(FlutterEngine engine, Context context) {
        this.mAppContext = context;
        this.mPlatformViewsController = new PlatformViewsController();
    }

    public boolean hasPlugin(String key) {
        return this.mPluginMap.containsKey(key);
    }

    public Registrar registrarFor(String pluginKey) {
        if (this.mPluginMap.containsKey(pluginKey)) {
            throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
        } else {
            this.mPluginMap.put(pluginKey, (Object)null);
            return new FlutterPluginRegistry.FlutterRegistrar(pluginKey);
        }
    }

    private class FlutterRegistrar implements Registrar {
        private final String pluginKey;

        FlutterRegistrar(String pluginKey) {
            this.pluginKey = pluginKey;
        }

        public BinaryMessenger messenger() {
            return FlutterPluginRegistry.this.mNativeView;
        }

        public PlatformViewRegistry platformViewRegistry() {
            return FlutterPluginRegistry.this.mPlatformViewsController.getRegistry();
        }

        public FlutterView view() {
            return FlutterPluginRegistry.this.mFlutterView;
        }
    }
}

我们看其中的registrarFor方法

public Registrar registrarFor(String pluginKey) {
    if (this.mPluginMap.containsKey(pluginKey)) {
        throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
    } else {
        this.mPluginMap.put(pluginKey, (Object)null);
        return new FlutterPluginRegistry.FlutterRegistrar(pluginKey);
    }
}

可以看到FlutterActivity的子类调用父类的registrarFor时,最终获取到的返回值就是FlutterPluginRegistry.FlutterRegistrar类的实例

到这里我们把整个流程梳理一下

最开始FlutterActivity的子类调用registrarFor方法时,最终调用顺序是FlutterActivity.registrarFor->FlutterActivityDelegate.registrarFor->(FlutterView.getPluginRegistry->FlutterNativeView.getPluginRegistry->返回值FlutterPluginRegistry)->FlutterPluginRegistry.registrarFor,最终返回值为FlutterPluginRegistry.FlutterRegistrar

好了,现在注册器的来历我们弄清楚了,那么最开始的FlutterActivity的子类代码里

methodChannel = MethodChannel(
    registrar.messenger(),
    channelName
)

里面的registrar.messenger()实际是什么呢,因为FlutterActivity里的registrarFor方法最终返回的是FlutterPluginRegistry.FlutterRegistrar,所以registrar.messenger()的返回值就是FlutterPluginRegistry.FlutterRegistrar类里的messenger()方法的返回值,我们看一下FlutterPluginRegistry.FlutterRegistrar类里的messenger()方法

public BinaryMessenger messenger() {
    return FlutterPluginRegistry.this.mNativeView;
}

返回的是FlutterNativeView的实例,这个mNativeView是哪里来的呢?

public FlutterPluginRegistry(FlutterNativeView nativeView, Context context) {
    this.mNativeView = nativeView;
    this.mAppContext = context;
    this.mPlatformViewsController = new PlatformViewsController();
}

这个mNativeView实例就是FlutterNativeView创建FlutterPluginRegistry时将自己作为参数传入并赋值的,而FlutterNativeView是在FlutterActivityDelegateonCreate方法里,由FlutterActivityDelegate的属性viewFactory调用createFlutterNativeView方法(viewFactory是FlutterActivity将自己作为参数传入并赋值)创建并作为参数传入FlutterView并赋值的,或者是由FlutterView自己创建的FlutterNative并赋值的(如果viewFactory.createFlutterNativeView返回值为null)

到这里,我们也就知道了最开始创建通道时的参数registrar.messenger()到底是什么了,实际就是FlutterNativeView,那么我们将registrar.messenger()替换为getFlutterView()可以吗,答案是可以的,因为FlutterView实现了接口BinaryMessenger并且BinaryMessenger的方法实现都委托给了mNativeView实例,所以最开始的代码也可以用如下方式实现

methodChannel = MethodChannel(
    flutterView,
    channelName
)

或者

methodChannel = MethodChannel(
    flutterView.flutterNativeView,
    channelName
)

但是用这种方式的话记得提前调用父类的registrarFor注册方法将自己作为插件注册到系统


欢迎加入Flutter开发群457664582,点击加入,大家一起学习讨论

Flutter开发