After the WindVane miniapp container is integrated into a Flutter app, you can use WindVane in the Flutter app to load a miniapp.
Procedure
If you want to integrate the WindVane miniapp container into a Flutter app, you must integrate the WindVane SDK into a native app, and use MethodChannel to call methods provided by the WindVane SDK in the native app to open a miniapp. Perform the following operations:
Integrate the WindVane SDK into a native Android or iOS app.
Create a
MethodChannel
instance in Flutter to enable the communication between Flutter and the native app, and then define the methods that you want to call.Implement the methods that are defined by
MethodChannel
in the Android or iOS app.Use the created
MethodChannel
instance in Flutter to call the methods defined in the native app.
Step 1: Integrate WindVane into a native app
For more information about how to integrate WindVane into a native app, see the following topics:
Step 2: Create a MethodChannel instance in Flutter
Create a MethodChannel
instance in Flutter to enable the communication between Flutter and the native app. Sample code:
class WindVaneMiniAppManager {
static const MethodChannel channel = const MethodChannel("windvane_miniapp");
}
You can set MethodChannel
to a channel name based on your business requirements. windvane_miniapp
in the preceding code is provided for reference only.
Step 3: Implement MethodChannel in the native app
Android
Inherit
FlutterActivity
.Implement the
configureFlutterEngine
method to create aMethodChannel
instance.ImportantThe channel name that you specify for MethodChannel in the native app must be the same as the channel name that you specified for MethodChannel in Flutter in Step 2: Create a MethodChannel instance in Flutter.
In the following sample code, three methods are defined:
loadMiniApp: opens a miniapp.
initWindVaneMiniApp: initializes WindVane.
getMiniApps: queries miniapps.
@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); }}); }
You can use
MethodCall.method
to query the name of a method.You can use
MethodCall.argument("${key}")
to query the parameter of a method.You can check the result of a method by using
MethodChannel.Result.success
orMethodChannel.Result.error
that is returned after the method is called.
iOS
Inherit
FlutterViewController
.Create a
MethodChannel
instance.@interface EMASMainViewController : FlutterViewController @end @interface EMASMainViewController () @property (nonatomic, strong) FlutterMethodChannel* messageChannel; @end @implementation EMASMainViewController - (void)viewDidLoad { [super viewDidLoad]; [self configMessageChannel]; } -(void) configMessageChannel{ // Query the current 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
Step 4: Call MethodChannel
Use the created MethodChannel instance in Flutter to call the methods defined in the native app. Sample code:
WindVaneMiniAppManager.channel.invokeMethod(
"openMiniapp", {'appId': appId}).then((value) => {});
invokeMethod
returns a Future object.
iOS supports flutter projects to open WindVane miniapps in window mode
Solution Overview
When the window passed in from outside is not set as the key window, calling the miniapp launch method will not take effect. Therefore, customer must provide a loading page as a transitional page before launching the miniapp (this loading page must be the rootViewController)
When users click the close/back button or a miniapp triggers the close action via JSAPI, AliCloud container SDK will not automatically close the current miniapp page. Instead, it will first send a "close" callback message to customer (the callback method is registered during container initialization). The customer must then destroy the current window.
When users attempt to close the mini-program via a swipe gesture(interactivePopGestureRecognizer), this action directly triggers the closure of the miniapp page, which would expose the previously provided loading page again and degrade user experience. To address this, AliCloud container SDK must disable the swipe-to-close functionality.
For scenarios where Miniapp A rediret to another Miniapp B, the JSAPI for miniapp navigation (wv.navigateToMiniApp) must be implemented by customer. When closing a miniapp, The customer must determine whether to close the current miniapp or destroy the current window within the close callback method.
When a miniapp opens another native pages (e.g., photo gallery or camera), AliCloud container SDK must present these pages using the window provided by the customer.
Note
The window passed in needs to be keyWindowAndVisiable, and the rootViewController has been set
The swipe gesture function will be disabled for WindVane type miniapps, and customer need to implement the closing logic and js api (miniapp to open miniapp)
Not applicable to uniapp containers
Step 1:Param window
class EMASMiniAppOpenConfiguration has propertieswindvaneWindow,When calling the methodopenMiniApp:openConfiguration:completionBlock:
to open the miniapp, pass in the parameter window
Step 2:Re-implement the miniapp closing method
EMASMiniAppService adds a method closeMiniApp:
, which needs to be registered when the container is initialized
[miniAppService closeMiniApp:^(NSString * _Nonnull appId) {
//TODO:close the applet's processing logic
}];
Close miniapp logic sample code:
if ([currentVC.navigationController respondsToSelector:@selector(popViewControllerAnimated:)]) {
if (currentVC.navigationController.viewControllers.count > 1) {
[currentVC.navigationController popViewControllerAnimated:YES];
} else {
[currentVC dismissViewControllerAnimated:YES completion:nil];
//TODO:destroy window
}
}
Step 3:Re-implement the miniapp to open miniapp JS API
Refer to Custom JSAPI and use the alias method to rewrite the original wv.navigateToMiniapp method of the container
Add a method of class WVMiniNavigatorApp callednavigateToMiniApp:(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"];
//get the window to show windvane miniapp
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) {
//path
config.path = path;
}
if (extraData){
//extended Parameters
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];
}
}
Use the alias method to rewrite the miniapp to open miniapp method
NSDictionary *dic = @{
@"WVMiniApp.navigateToMiniApp":@"WVMiniNavigatorApp.navigateToMiniApp"
};
WMBridgeRegisterAlias(dic);