现有Android项目中集成Flutter/Flutter混合开发实战(二):FlutterActivity源码分析

2,375 阅读4分钟

二.集成Flutter

2.通过继承FlutterActivity等组件集成

需要说明的是,我最后在通过route添加不同flutter界面的地方失败了,目前没有找到好的解决办法,如果有人研究过这个,希望可以指出我的错误,帮我解决。

第一篇文章中详细介绍了如何将FlutterView添加到Android原生页面布局中。

(PS:有小伙伴在评论里说,可以设置监听来达到原生控件和FlutterView同时加载的效果,的确是一个可以优化的点,谢谢您的帮助!)

第二种方式是通过继承FlutterActivity、FlutterFragment及FlutterFragmentActivity。

public class FlutterExtendActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

但是目前有个问题没有解决,是这样的:

这样创建的Activity中的Flutter界面是default值,也就是空值返回的界面,但我们不可能永远通过默认的initialRoute来添加FlutterView。

如果在FlutterActivity的onCreate中更改route值呢?

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        FlutterMain.startInitialization(getApplicationContext());
        super.onCreate(savedInstanceState);
        getFlutterView().setInitialRoute("flutter_activity");

失败了。


getFlutterView().pushRoute("flutter_activity");

也失败了。


--------------------------------------------------------------------

↑这两张图其实是同一张...反正都不成功

主要原因是,super.onCreate之后,FlutterActivity已经创建好了布局,而且我们的这个Activity中又没有setContentView()的实现,设置route的操作不能挪到super.onCreate()前面。


我查看了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 FlutterView createFlutterView(Context context) {
        return null;
    }

    public FlutterNativeView createFlutterNativeView() {
        return null;
    }

    public boolean retainFlutterNativeView() {
        return false;
    }
}

可以看出FlutterActivity实际是继承了Activity,实现了FlutterView.Provider、

PluginRegistry、ViewFactory三个接口。

但是FlutterActivity的三个在实例化时候的变量都指向了一个FlutterActivityDelegate对象,也就是说,它代理了FlutterActivity几乎所有的动作。

三个接口大致内容如下:

(1).FlutterView.Provider

public interface Provider {
    FlutterView getFlutterView();
}

FlutterView.Provider是一个接口,提供了getFlutterView()抽象方法

那么FlutterActivity的具体实现呢?

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

但是viewProvider又指向了这个FlutterActivityDelegate;

(2).PluginRegistry

public interface PluginRegistry {
    PluginRegistry.Registrar registrarFor(String var1);

    boolean hasPlugin(String var1);

    <T> T valuePublishedByPlugin(String var1);

    public interface PluginRegistrantCallback {
        void registerWith(PluginRegistry var1);
    }

    public interface ViewDestroyListener {
        boolean onViewDestroy(FlutterNativeView var1);
    }

    public interface UserLeaveHintListener {
        void onUserLeaveHint();
    }

    public interface NewIntentListener {
        boolean onNewIntent(Intent var1);
    }

    public interface ActivityResultListener {
        boolean onActivityResult(int var1, int var2, Intent var3);
    }

    public interface RequestPermissionsResultListener {
        boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3);
    }
}

(3).ViewFactory

public interface ViewFactory {
    FlutterView createFlutterView(Context var1);

    FlutterNativeView createFlutterNativeView();

    boolean retainFlutterNativeView();
}

具体实现:

public FlutterView createFlutterView(Context context) {
    return null;
}
public FlutterNativeView createFlutterNativeView() {
    return null;
}
public boolean retainFlutterNativeView() {
    return false;
}

也就是...这个接口的实现基本没有什么意义.

所以我们还是要看FlutterActivityDelegate这个类和它的实例究竟做了什么.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.eventDelegate.onCreate(savedInstanceState);
}

调用了eventDelegate.onCreate(),我们可以顺藤摸瓜看看它的onCreate()

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);
        }

    }
}

FlutterView是由FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) 这个构造方法new出来的。

实际上,

@NonNull
public static FlutterView createView(@NonNull final Activity activity, @NonNull final Lifecycle lifecycle, final String initialRoute) {
  FlutterMain.startInitialization(activity.getApplicationContext());
  FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null);
  final FlutterNativeView nativeView = new FlutterNativeView(activity);
  //↓这里还是调用了FlutterView的三个参数构造
  final FlutterView flutterView = new FlutterView(activity, null, nativeView) {
    private final BasicMessageChannel<String> lifecycleMessages = new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE);
    @Override
    public void onFirstFrame() {
      super.onFirstFrame();
      setAlpha(1.0f);
    }
}


我们之前使用的Flutter.createView()显然也是调用了这个构造。但是createView()有一个String类型的initialRoute参数,FlutterActivity中调用的构造则没有。我猜想,会不会提供了更改Route的方式呢?

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

        if (route != null) {
            this.flutterView.setInitialRoute(route);
        }
        //如果route值不为空,则将它设置给flutterview

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

FlutterActivityDelegate中有这个方法,从这个Activity跳转过来的Intent中可以获取route,key值为"route",如果route不为空的话,就给这个FlutterView设置一个initialRoute。出于这样的思路,我在跳转本Activity的时候,传递一个在Flutter中定义好页面的route值进去怎么样?

做了一下尝试,

findViewById(R.id.btn_flutter_acty).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        startActivity(new Intent(MainActivity.this, FlutterExtendActivity.class).putExtra("route","flutter1"));
    }
});

结果是失败了,跳转后页面上出现的FlutterView仍然是传default时返回的页面.


额,由于今天没有什么时间了,所以就写这么多。确实人菜话多,而且今天也没有什么进展(MethodChannel实现通信成功了,不过明天再写吧)今天就卡在了这个FlutterActivity上,不知道明天能找到什么解决办法...请大家见谅。