Flutter App接入WindVane小程序容器后,则可以在Flutter App中使用WindVane小程序容器加载小程序。
接入流程
Flutter App接入WindVane小程序容器,首先需要通过Native端集成小程序容器,再通过MethodChannel调用Native端小程序容器SDK提供的方法打开小程序,详细流程如下:
Android端和iOS端集成小程序容器SDK。
定义Flutter和Native通信的
MethodChannel,以及需要调用的方法。在Android端或iOS端,分别实现
MethodChannel已经定义好的方法。在Flutter侧通过定义好的
MethodChannel调用Native方法。
步骤一、Native端集成小程序容器
集成小程序容器的详细操作请参见:
步骤二、定义MethodChannel
在Flutter中定义和Native侧通信的MethodChannel, 示例代码如下:
class WindVaneMiniAppManager {
static const MethodChannel channel = const MethodChannel("windvane_miniapp");
}MethodChannel的名称可以自定义,上述代码中的windvane_miniapp仅为示例。
步骤三、在Native中实现MethodChannel
Android
继承
FlutterActivity。实现
configureFlutterEngine方法,创建MethodChannel。重要MethodChannel的名称须和步骤二、定义MethodChannel中Flutter定义的MethodChannel名称保持一致。
示例代码如下,其中定义了三个方法:
loadMiniApp:打开小程序。
initWindVaneMiniApp:初始化小程序容器。
getMiniApps:查询小程序列表。
@Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { super.configureFlutterEngine(flutterEngine); GeneratedPluginRegistrant.registerWith(flutterEngine); MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor(), WINDVANE_MINIAPP); channel.setMethodCallHandler((methodCall, result) -> { String method = methodCall.method; if ("initMiniApp".equals(method)) { initMiniApp(result); } else if ("getMiniAppList".equals(method)) { getMiniAppList(result); } else if ("openMiniapp".equals(method)) { openMiniApp(methodCall, result); }}); }方法名通过
MethodCall.method获取。方法的参数通过
MethodCall.argument("${key}")获取方法执行后的结果通过
MethodChannel.Result.success或MethodChannel.Result.error返回。
iOS
继承
FlutterViewController。创建
MethodChannel。@interface EMASMainViewController : FlutterViewController @end @interface EMASMainViewController () @property (nonatomic, strong) FlutterMethodChannel* messageChannel; @end @implementation EMASMainViewController - (void)viewDidLoad { [super viewDidLoad]; [self configMessageChannel]; } -(void) configMessageChannel{ //获取当前的 controller // FlutterViewController* controller = (FlutterViewController*)[UIApplication sharedApplication].delegate.window.rootViewController; self.messageChannel = [FlutterMethodChannel methodChannelWithName:@"windvane_miniapp" binaryMessenger:self.binaryMessenger]; __weak __typeof__(self) weakSelf = self; [self.messageChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { NSLog(@"call method is %@",call.method); __strong typeof(weakSelf) strongSelf = weakSelf; NSString *method = call.method; if ([method isEqualToString:@"initMiniApp"]) { [strongSelf initWindVaneMiniApp:call result:result]; } else if ([method isEqualToString:@"openMiniapp"]) { [strongSelf loadMiniApp:call result:result]; } else if ([method isEqualToString:@"getMiniAppList"]) { [strongSelf getMiniApps:call result:result]; } }]; } @end
步骤四、调用MethodChannel
通过定义好的MethodChannel调用相应方法,示例代码如下:
WindVaneMiniAppManager.channel.invokeMethod(
"openMiniapp", {'appId': appId}).then((value) => {});invokeMethod返回的是Future对象。
iOS 支持flutter工程以window方式打开WindVane小程序
方案概述
当外部传入的window并没有设置为主window时,调用打开小程序方法不起作用,所以需要客户提供loading页作为打开小程序前的过渡页(此过渡页须为rootViewController)
当用户点击关闭按钮/返回按钮或小程序调用jsapi关闭当前小程序时,容器sdk不会自动关闭当前小程序页面而是先发送“关闭”回调消息给客户(回调方法在容器初始化时注册),然后需要客户销毁当前window
当用户侧滑关闭当前小程序时,因为会直接触发小程序页面关闭,导致此前客户提供的loading页面被再次露出影响用户体验,所以需容器sdk禁用侧滑功能
当出现小程序A跳转启动另一个小程序B时,小程序跳转的jsapi(wv.navigateToMiniApp)需客户自行实现。当关闭小程序时,客户需在关闭回调方法中自行判断应关闭当前小程序或销毁当前window
当出现小程序打开相册/拍照等其他页面时,容器sdk需根据用户传入的window来present当前页面
注意事项
传入的 window 需要为 keyWindowAndVisiable, 并且已设置 rootViewController
WindVane类型小程序会禁用侧滑功能,需要客户自己实现关闭逻辑和js api 小程序打开小程序功能
对uniapp容器不适用
第一步:传入window
EMASMiniAppOpenConfiguration类新增属性windvaneWindow,在调用打开小程序方法openMiniApp:openConfiguration:completionBlock:方法时传入window
第二步:重新实现小程序关闭方法
EMASMiniAppService新增方法closeMiniApp:,该方法需要在容器初始化时注册
[miniAppService closeMiniApp:^(NSString * _Nonnull appId) {
//TODO:关闭小程序的处理逻辑
}];关闭小程序逻辑示例代码:
if ([currentVC.navigationController respondsToSelector:@selector(popViewControllerAnimated:)]) {
if (currentVC.navigationController.viewControllers.count > 1) {
[currentVC.navigationController popViewControllerAnimated:YES];
} else {
[currentVC dismissViewControllerAnimated:YES completion:nil];
//TODO:销毁window
}
}第三步:重新实现小程序跳转小程序 JS API
参考自定义JSAPI,并使用别名方式重写容器原有的wv.navigateToMiniapp 方法
示例:
新增一个类WVMiniNavigatorApp的方法navigateToMiniApp:(NSDictionary *)params withBridgeContext:(id<WMBridgeCallbackContext>)context
@implementation WVMiniNavigatorApp
- (void)navigateToMiniApp:(NSDictionary *)params withBridgeContext:(id<WMBridgeCallbackContext>)context {
NSString *appId = [params wvStringValue:@"appId"];
NSString *path = [params wvStringValue:@"path"];
NSDictionary *extraData = [params wvDictionaryValue:@"extraData"];
//获取需要展示的window
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
id<EMASMiniAppService> miniAppService = [[EMASServiceManager sharedInstance] serviceForProtocol:@"EMASMiniAppService"];
if (miniAppService) {
EMASMiniAppOpenConfiguration *config = [[EMASMiniAppOpenConfiguration alloc] init];
config.windvaneWindow = delegate.windVaneWindow;
if (path.length > 0) {
//deeplink 路径
config.path = path;
}
if (extraData){
//扩展参数
config.extraData = extraData;
}
[miniAppService openMiniApp:appId openConfiguration:config completionBlock:^(int resultCode, NSDictionary * _Nonnull resultDict) {
NSLog(@"resultCode = %d, resultDict = %@",resultCode,resultDict);
if (resultCode == 200) {
//打开小程序成功,自动跳转到小程序界面
// 返回结果
[context callbackSuccess:@{@"msg": @"success"}];
}else{
[context callbackSuccess:@{@"resultCode": @(resultCode),@"msg": resultDict}];
}
}];
}else{
NSDictionary *errorResult = @{
@"detailErrorCode": @"12",
@"detailErrorMsg": @"EMASMiniAppService is nil"
};
[context callbackFailure:WMBridgeStatusFailed withResult:errorResult];
}
}使用别名方式重写小程序跳转小程序方法
NSDictionary *dic = @{
@"WVMiniApp.navigateToMiniApp":@"WVMiniNavigatorApp.navigateToMiniApp"
};
WMBridgeRegisterAlias(dic);