iOS原生使用FlutterEngineGroup接入flutter模块

随笔9个月前发布 语诺妈咪
78 0 0

原生项目集成flutter流程这里不做说明
FlutterEngineGroup在推出后,很好的解决了原生跳转多flutter页面的路由问题,可以非常容易的实现native->flutter->native->flutter这种嵌套路由,只需要重新创建一个flutterEngine,并且开销很小

1. 创建FlutterEngineGroup

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.flutterEngineGroup = [[FlutterEngineGroup alloc] initWithName:@"flutterGroupName" project:nil];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

2. 创建FlutterViewController

@interface MyFlutterViewController : FlutterViewController

-(instancetype)initWithFlutterUrl:(NSString *)url;

@end

@implementation MyFlutterViewController

-(instancetype)initWithFlutterUrl:(NSString *)url {
    FlutterEngineGroup *engineGroup = [AppDelegate getFlutterEngineGroup];
    FlutterEngine *engine = [engineGroup makeEngineWithEntrypoint:nil libraryURI:nil initialRoute:url];
    return [self initWithEngine:engine nibName:nil bundle:nil];
}
@end

这样就实现了多engine的路由跳转
但是FlutterEngineGroup一个弊端就是EngineEngine之间数据是隔离的,没有办法直接通信,这里我采用原生平台作为中转站,通过channel先通知原生平台,再由原生平台来通知到其他的flutterEngine
首先要说明的是因为flutterEngine是相互隔离的,所以注册的channel也是隔离的

3. 创建Engine-Channel键值对管理类

把目前还在路由栈中的engine以及对应的channel对应保存起来,这里我使用NSMapTable,原因是NSMapTablekey不需要遵守NSCopying协议,并且可以设置keyValue的引用类型,当设置为weak引用,当engine销毁后,对应的键值对会自动回收
先创建一个flutterManage用来管理Engine-Channel键值对,作为一个单例,提供添加以及遍历通知的方法

@interface FlutterManage : NSObject

+ (instancetype)shared;

- (void)setObject:(FlutterMethodChannel *)anObject forKey:(FlutterEngine *)aKey;

-(void)notifyOtherFlutterEngineWithEngine:(FlutterEngine *)engine info:(id)info;

@end

static FlutterManage *_manage = nil;

@interface FlutterManage ()

@property(nonatomic, strong) NSMapTable<FlutterEngine *,FlutterMethodChannel *> *table;

@end

@implementation FlutterManage

+ (instancetype)shared {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _manage = [[self alloc] init];
        _manage.table = [NSMapTable weakToWeakObjectsMapTable];
    });
    return _manage;
}

-(void)setObject:(FlutterMethodChannel *)anObject forKey:(FlutterEngine *)aKey {
    [_table setObject:anObject forKey:aKey];
}

-(void)notifyOtherFlutterEngineWithEngine:(FlutterEngine *)engine info:(id)info {
    FlutterMethodChannel *channel = [_manage.table objectForKey:engine];
    NSEnumerator *enumerator = [_manage.table objectEnumerator];
    FlutterMethodChannel *target;
    while (target = [enumerator nextObject]) {
        if (target == channel) continue;;
        [target invokeMethod:@"notifyOtherFlutterEngine" arguments:info];
    }
}
@end

4. 在MyFlutterViewController中保存engine-channel键值对,并且在收到通知消息notifyOtherFlutterEngine后调用管理类的通知方法

-(void)initChannel {
    __weak typeof(self) weakSelf = self;
    self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"my_methodChannel" binaryMessenger:self.binaryMessenger];
        [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
            if ([call.method isEqualToString:@"notifyOtherFlutterEngine"]) {
                [[FlutterManage shared] notifyOtherFlutterEngineWithEngine:weakSelf.engine info:call.arguments];
            }
        }];
    [FlutterManage.shared setObject:self.methodChannel forKey:self.engine];
}

到此,实现了多引擎之间的数据传递
我觉得通道有这一个就可以了,后面如果需要细分不同的通知做不一样的逻辑,我们可以再info中扩展参数,这样就不必每次有新的通知类型,都去修改FlutterManage这个类,扩展只限制在业务层

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...