FlutterFlutterBoost

前言

Flutter版本:1.9.1
FlutterBoost版本:1.9.1
测试使用的iamge_picker版本:0.6.2+2
1
2
3

Flutter Boost 目前算是 Flutter 混合开发的一个旗帜了,不过也由于 Flutter 技术本身就较新,Flutter Boost 也才开源一年多时间,里面还是会存在较多 bug。我们公司使用的就是 Flutter Boost 集成的混合开发项目,这几天集成选择相册的功能,本地开发没问题,通过 Flutter Boost 集成到原生后 Android 端第一次跳转后返回接收不到参数,由于接收不到参数,第二次点击就没响应了,报错Unhandled Exception: PlatformException(already_active, Image picker is already active, null),iOS 就根本跳转不了。我也花了点时间 debug,发现了其中的问题。

Android 端解决方案

问题原因

  • 集成 flutter_boost 之后,很多插件会使用栈底的 Activity,也就是 app 启动的时候的 MainActivity()(app 启动的时候会注册插件,插件通过 registrar.activity()获取到的)
  • Android 使用底层 Activity 跳转没问题,但是调用 startActivityForResult 的时候,需要使用在栈顶的 Activity(onResume 状态的 Activity)才会在拉起的界面 finish 的时候拿到回调,这就会导致我们使用的插件中的 Activity 拿不到回调

我的解决方案

  1. 修改插件源码,在插件里面注册 Activity 的生命周期回调,并修改 Activity 指向

android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java中本身就有 Activity 生命周期注册:

70- public void onActivityResumed(Activity activity) {}
70+ public void onActivityResumed(Activity activity) {
71+    delegate.changeActivity(activity);
72+}

1
2
3
4
5

2.在android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java中需要把原来 final 的 activity 改为动态的

80-  private final Activity activity;
80+  private Activity activity;
1
2

然后添加更新函数

public void changeActivity(Activity activity) {
    this.activity=activity;
}

1
2
3
4

ok,这个时候在调用 startActivityForResult 的时候会使用这个改过的 Activity 的实例,在拉起的 Activity finish 的时候,就能顺利拿到回调了。

iOS 端解决方案

问题原因

iOS 其实跟 Android 端的问题大同小异,注册的时候是使用的底层的 controller,所以我们在 FlutterController 中使用这个底层的 controller 无法跳转

我的解决方案

  1. 添加一个能拿到顶层 controller 的方法 ios/Classes/ImagePickerPlugin.m
- (UIViewController *)getCurrentVC
{
    UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    UIViewController *currentVC = [self getCurrentVCFrom:rootViewController];
    return currentVC;
}

- (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
{
    UIViewController *currentVC;
    if ([rootVC presentedViewController]) {
        // 视图是被presented出来的
        rootVC = [rootVC presentedViewController];
    }
    if ([rootVC isKindOfClass:[UITabBarController class]]) {
        // 根视图为UITabBarController
        currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];

    } else if ([rootVC isKindOfClass:[UINavigationController class]]){
        // 根视图为UINavigationController
        currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];
    } else {
        // 根视图为非导航类
        currentVC = rootVC;
    }
    return currentVC;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  1. 在我们点击 image_picker 发送通道消息的时候更改本地已缓存的 controller
57+ UIViewController *rootViewController = [UIApplication  sharedApplication].keyWindow.rootViewController;
58+ _viewController  = [self getCurrentVCFrom:rootViewController];

1
2
3

问题解决

总结

我这里这两种方案不会是最好的解决方案,因为涉及到改插件源码,这样以后插件更新会比较麻烦,但是从目前看来是解决了我开发的问题,如果你们有好的解决方案,或者新版本已经解决了这个问题,请留言告知。

Last Updated: 8/12/2020, 1:34:59 PM