Commit 065433bd authored by XinLei's avatar XinLei Committed by GitHub

Merge pull request #1 from alibaba/master

sync latest version
parents 6afd80fb 8a706f68
......@@ -86,16 +86,16 @@ Use FLBFlutterAppDelegate as the superclass of your AppDelegate
Implement FLBPlatform protocol methods for your App.
```objc
@interface DemoRouter : NSObject<FLBPlatform>
@interface PlatformRouterImp : NSObject<FLBPlatform>
@property (nonatomic,strong) UINavigationController *navigationController;
+ (DemoRouter *)sharedRouter;
+ (PlatformRouterImp *)sharedRouter;
@end
@implementation DemoRouter
@implementation PlatformRouterImp
- (void)openPage:(NSString *)name
params:(NSDictionary *)params
......@@ -129,11 +129,12 @@ Implement FLBPlatform protocol methods for your App.
Initialize FlutterBoost with FLBPlatform at the beginning of your App.
Initialize FlutterBoost with FLBPlatform at the beginning of your App, such as AppDelegate.
```objc
PlatformRouterImp *router = [PlatformRouterImp new];
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
onStart:^(id engine) {
onStart:^(FlutterEngine *engine) {
}];
```
......@@ -202,6 +203,23 @@ iOS
[vc setName:name params:params];
[self.navigationController presentViewController:vc animated:animated completion:^{}];
```
However, in this way, you cannot get the page data result after the page finished. We suggest you implement the platform page router like the way mentioned above. And finally open/close the VC as following:
```objc
//push the page
[FlutterBoostPlugin open:@"first" urlParams:@{kPageCallBackId:@"MycallbackId#1"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is opened");
}];
//prsent the page
[FlutterBoostPlugin open:@"second" urlParams:@{@"present":@(YES),kPageCallBackId:@"MycallbackId#2"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is presented");
}];
//close the page
[FlutterBoostPlugin close:yourUniqueId result:yourdata exts:exts completion:nil];
```
Android
......
......@@ -82,16 +82,16 @@ class _MyAppState extends State<MyApp> {
为您的应用程序实现FLBPlatform协议方法。
```objectivec
@interface DemoRouter : NSObject<FLBPlatform>
@interface PlatformRouterImp : NSObject<FLBPlatform>
@property (nonatomic,strong) UINavigationController *navigationController;
+ (DemoRouter *)sharedRouter;
+ (PlatformRouterImp *)sharedRouter;
@end
@implementation DemoRouter
@implementation PlatformRouterImp
- (void)openPage:(NSString *)name
params:(NSDictionary *)params
......@@ -127,9 +127,10 @@ class _MyAppState extends State<MyApp> {
在应用程序开头使用FLBPlatform初始化FlutterBoost。
```的ObjectiveC
```objc
PlatformRouterImp *router = [PlatformRouterImp new];
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatformrouter
onStart:^(id engine){
onStart^FlutterEngine *engine{
}];
```
......@@ -193,6 +194,24 @@ public class MyApplication extends FlutterApplication {
[self.navigationController presentViewController:vc animated:animated completion:^{}];
```
但是,这种方式无法获取页面返回的数据,建议你按上面的example实现类似于PlatformRouterImp这样的路由器,然后通过以下方式来打开/关闭页面
```objc
//push the page
[FlutterBoostPlugin open:@"first" urlParams:@{kPageCallBackId:@"MycallbackId#1"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is opened");
}];
//prsent the page
[FlutterBoostPlugin open:@"second" urlParams:@{@"present":@(YES),kPageCallBackId:@"MycallbackId#2"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is presented");
}];
//close the page
[FlutterBoostPlugin close:yourUniqueId result:yourdata exts:exts completion:nil];
```
Android
```java
......
......@@ -22,7 +22,7 @@ rootProject.allprojects {
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
compileSdkVersion 28
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 16
......
......@@ -54,6 +54,7 @@ public class BoostFlutterView extends FrameLayout {
private BoostFlutterEngine mFlutterEngine;
private XFlutterView mFlutterView;
private PlatformPlugin mPlatformPlugin;
private Bundle mArguments;
......@@ -113,6 +114,7 @@ public class BoostFlutterView extends FrameLayout {
if (mArguments == null) {
mArguments = new Bundle();
}
mPlatformPlugin = new PlatformPlugin((Activity) getContext(), mFlutterEngine.getPlatformChannel());
mFlutterView = new XFlutterView(getContext(), getRenderMode(), getTransparencyMode());
addView(mFlutterView, new FrameLayout.LayoutParams(
......@@ -288,6 +290,7 @@ public class BoostFlutterView extends FrameLayout {
}
}
public void onDestroy() {
Debuger.log("BoostFlutterView onDestroy");
......
......@@ -13,6 +13,7 @@ public class XAndroidKeyProcessor {
private final KeyEventChannel keyEventChannel;
@NonNull
private final XTextInputPlugin textInputPlugin;
private int combiningCharacter;
public XAndroidKeyProcessor(@NonNull KeyEventChannel keyEventChannel, @NonNull XTextInputPlugin textInputPlugin) {
......@@ -20,6 +21,7 @@ public class XAndroidKeyProcessor {
this.textInputPlugin = textInputPlugin;
}
public void onKeyUp(@NonNull KeyEvent keyEvent) {
Character complexCharacter = applyCombiningCharacterToBaseCharacter(keyEvent.getUnicodeChar());
keyEventChannel.keyUp(
......
package com.idlefish.flutterboost;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
......@@ -34,6 +35,7 @@ import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.view.AccessibilityBridge;
public class XFlutterView extends FrameLayout {
......@@ -430,6 +432,7 @@ public class XFlutterView extends FrameLayout {
* {@link FlutterEngine}.
*/
public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
Log.d(TAG, "attachToFlutterEngine()");
if (isAttachedToFlutterEngine()) {
if (flutterEngine == this.flutterEngine) {
......@@ -445,21 +448,27 @@ public class XFlutterView extends FrameLayout {
this.flutterEngine = flutterEngine;
// initialize PlatformViewsController
this.flutterEngine.getPluginRegistry().getPlatformViewsController().attach(getContext(),flutterEngine.getRenderer(),flutterEngine.getDartExecutor());
// Instruct our FlutterRenderer that we are now its designated RenderSurface.
this.flutterEngine.getRenderer().attachToRenderSurface(renderSurface);
// Initialize various components that know how to process Android View I/O
// in a way that Flutter understands.
if(textInputPlugin==null){
textInputPlugin = new XTextInputPlugin(
this,
this.flutterEngine.getDartExecutor()
);
androidKeyProcessor = new XAndroidKeyProcessor(
this.flutterEngine.getKeyEventChannel(),
textInputPlugin
flutterEngine.getTextInputChannel()
);
}
textInputPlugin.setTextInputMethodHandler();
textInputPlugin.getInputMethodManager().restartInput(this);
androidKeyProcessor = new XAndroidKeyProcessor(
this.flutterEngine.getKeyEventChannel(),
textInputPlugin
);
......@@ -480,7 +489,6 @@ public class XFlutterView extends FrameLayout {
accessibilityBridge.isAccessibilityEnabled(),
accessibilityBridge.isTouchExplorationEnabled()
);
textInputPlugin.getInputMethodManager().restartInput(this);
}
......@@ -524,12 +532,17 @@ public class XFlutterView extends FrameLayout {
}
Log.d(TAG, "Detaching from Flutter Engine");
// detach platformviews in page in case memory leak
flutterEngine.getPluginRegistry().getPlatformViewsController().detach();
flutterEngine.getPluginRegistry().getPlatformViewsController().onFlutterViewDestroyed();
// Inform the Android framework that it should retrieve a new InputConnection
// now that the engine is detached. The new InputConnection will be null, which
// signifies that this View does not process input (until a new engine is attached).
// TODO(mattcarroll): once this is proven to work, move this line ot TextInputPlugin
textInputPlugin.getInputMethodManager().restartInput(this);
// textInputPlugin.getInputMethodManager().restartInput(this);
// Instruct our FlutterRenderer that we are no longer interested in being its RenderSurface.
// this.textInputPlugin.getInputMethodManager().restartInput(this);
flutterEngine.getRenderer().detachFromRenderSurface();
flutterEngine = null;
......
......@@ -24,7 +24,6 @@ public class XTextInputPlugin {
@NonNull
private final InputMethodManager mImm;
@NonNull
private final TextInputChannel textInputChannel;
private int mClient = 0;
@Nullable
private TextInputChannel.Configuration configuration;
......@@ -33,13 +32,17 @@ public class XTextInputPlugin {
private boolean mRestartInputPending;
@Nullable
private InputConnection lastInputConnection;
public XTextInputPlugin(View view, @NonNull DartExecutor dartExecutor) {
private TextInputChannel textInputChannel;
public XTextInputPlugin(View view, TextInputChannel mTextInputChannel) {
mView = view;
mImm = (InputMethodManager) view.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
textInputChannel=mTextInputChannel;
}
textInputChannel = new TextInputChannel(dartExecutor);
public void setTextInputMethodHandler( ){
textInputChannel.setTextInputMethodHandler(new TextInputChannel.TextInputMethodHandler() {
@Override
public void show() {
......@@ -173,6 +176,7 @@ public class XTextInputPlugin {
}
private void showTextInput(View view) {
if(view==null) return;
view.requestFocus();
mImm.showSoftInput(view, 0);
}
......
......@@ -3,6 +3,7 @@ package com.taobao.idlefish.flutterboostexample;
import android.app.Application;
import android.content.Context;
import com.idlefish.flutterboost.BoostChannel;
import com.idlefish.flutterboost.BoostEngineProvider;
import com.idlefish.flutterboost.BoostFlutterEngine;
import com.idlefish.flutterboost.FlutterBoost;
......@@ -34,18 +35,18 @@ public class MyApplication extends FlutterApplication {
@Override
public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
PageRouter.openPageByUrl(context,url,urlParams,requestCode);
PageRouter.openPageByUrl(context, url, urlParams, requestCode);
}
@Override
public IFlutterEngineProvider engineProvider() {
return new BoostEngineProvider(){
return new BoostEngineProvider() {
@Override
public BoostFlutterEngine createEngine(Context context) {
return new BoostFlutterEngine(context, new DartExecutor.DartEntrypoint(
context.getResources().getAssets(),
FlutterMain.findAppBundlePath(context),
"main"),"/");
"main"), "/");
}
};
}
......@@ -55,5 +56,13 @@ public class MyApplication extends FlutterApplication {
return ANY_ACTIVITY_CREATED;
}
});
BoostChannel.addActionAfterRegistered(new BoostChannel.ActionAfterRegistered() {
@Override
public void onChannelRegistered(BoostChannel channel) {
//platform view register should use FlutterPluginRegistry instread of BoostPluginRegistry
TextPlatformViewPlugin.register(FlutterBoost.singleton().engineProvider().tryGetEngine().getPluginRegistry());
}
});
}
}
package com.taobao.idlefish.flutterboostexample;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import io.flutter.plugin.common.MessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
public class TextPlatformViewFactory extends PlatformViewFactory {
public TextPlatformViewFactory(MessageCodec<Object> createArgsCodec) {
super(createArgsCodec);
}
@Override
public PlatformView create(Context context, int i, Object o) {
return new TextPlatformView(context);
}
private static class TextPlatformView implements PlatformView {
private TextView platformTv;
public TextPlatformView(Context context) {
platformTv = new TextView(context);
platformTv.setText("PlatformView Demo");
}
@Override
public View getView() {
return platformTv;
}
@Override
public void dispose() {
}
}
}
package com.taobao.idlefish.flutterboostexample;
import io.flutter.app.FlutterPluginRegistry;
import io.flutter.plugin.common.StandardMessageCodec;
public class TextPlatformViewPlugin {
public static void register(FlutterPluginRegistry registry) {
registry.getPlatformViewsController().getRegistry().registerViewFactory("plugins.test/view",
new TextPlatformViewFactory(StandardMessageCodec.INSTANCE));
}
}
......@@ -23,7 +23,7 @@
DF544AA62177253600931378 /* UIViewControllerDemo.m in Sources */ = {isa = PBXBuildFile; fileRef = DF544AA42177253600931378 /* UIViewControllerDemo.m */; };
DF544AA72177253600931378 /* UIViewControllerDemo.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF544AA52177253600931378 /* UIViewControllerDemo.xib */; };
DF544AD4217838EF00931378 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DF544AD3217838EF00931378 /* libc++.tbd */; };
DFD80BFA217DF95400E3F036 /* DemoRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = DFD80BF9217DF95400E3F036 /* DemoRouter.m */; };
DFD80BFA217DF95400E3F036 /* PlatformRouterImp.m in Sources */ = {isa = PBXBuildFile; fileRef = DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
......@@ -66,8 +66,8 @@
DF544AA52177253600931378 /* UIViewControllerDemo.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UIViewControllerDemo.xib; sourceTree = "<group>"; };
DF544ACF217836F600931378 /* libstdc++.6.0.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.6.0.9.tbd"; path = "usr/lib/libstdc++.6.0.9.tbd"; sourceTree = SDKROOT; };
DF544AD3217838EF00931378 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
DFD80BF8217DF95400E3F036 /* DemoRouter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoRouter.h; sourceTree = "<group>"; };
DFD80BF9217DF95400E3F036 /* DemoRouter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoRouter.m; sourceTree = "<group>"; };
DFD80BF8217DF95400E3F036 /* PlatformRouterImp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformRouterImp.h; sourceTree = "<group>"; };
DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformRouterImp.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -142,8 +142,8 @@
DF544AA32177253600931378 /* UIViewControllerDemo.h */,
DF544AA42177253600931378 /* UIViewControllerDemo.m */,
DF544AA52177253600931378 /* UIViewControllerDemo.xib */,
DFD80BF8217DF95400E3F036 /* DemoRouter.h */,
DFD80BF9217DF95400E3F036 /* DemoRouter.m */,
DFD80BF8217DF95400E3F036 /* PlatformRouterImp.h */,
DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */,
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
......@@ -328,7 +328,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DFD80BFA217DF95400E3F036 /* DemoRouter.m in Sources */,
DFD80BFA217DF95400E3F036 /* PlatformRouterImp.m in Sources */,
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
......@@ -472,6 +472,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
......@@ -497,6 +498,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
......
......@@ -8,7 +8,7 @@
#import "AppDelegate.h"
#import "UIViewControllerDemo.h"
#import "DemoRouter.h"
#import "PlatformRouterImp.h"
#import <flutter_boost/FlutterBoost.h>
@interface AppDelegate ()
......@@ -19,9 +19,9 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
DemoRouter *router = [DemoRouter sharedRouter];
PlatformRouterImp *router = [PlatformRouterImp new];
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
onStart:^(FlutterEngine *fvc) {
onStart:^(FlutterEngine *engine) {
}];
......
......@@ -14,13 +14,12 @@ NS_ASSUME_NONNULL_BEGIN
@protocol FLBPlatform;
@interface DemoRouter : NSObject<FLBPlatform>
/**
* 实现平台侧的页面打开和关闭,不建议直接使用用于页面打开,建议使用FlutterBoostPlugin中的open和close方法来打开或关闭页面;
* FlutterBoostPlugin带有页面返回数据的能力
*/
@interface PlatformRouterImp : NSObject<FLBPlatform>
@property (nonatomic,strong) UINavigationController *navigationController;
+ (DemoRouter *)sharedRouter;
@end
NS_ASSUME_NONNULL_END
......@@ -6,20 +6,13 @@
// Copyright © 2018年 The Chromium Authors. All rights reserved.
//
#import "DemoRouter.h"
#import "PlatformRouterImp.h"
#import <flutter_boost/FlutterBoost.h>
@implementation DemoRouter
@interface PlatformRouterImp()
@end
+ (DemoRouter *)sharedRouter
{
static id instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
@implementation PlatformRouterImp
#pragma mark - Boost 1.5
- (void)open:(NSString *)name
......@@ -28,18 +21,23 @@
completion:(void (^)(BOOL))completion
{
BOOL animated = [exts[@"animated"] boolValue];
if([params[@"present"] boolValue]){
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
[self.navigationController presentViewController:vc animated:animated completion:^{
if(completion) completion(YES);
}];
}else{
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
[self.navigationController pushViewController:vc animated:animated];
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
[self.navigationController pushViewController:vc animated:animated];
if(completion) completion(YES);
}
- (void)present:(NSString *)name
urlParams:(NSDictionary *)params
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion
{
BOOL animated = [exts[@"animated"] boolValue];
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
[self.navigationController presentViewController:vc animated:animated completion:^{
if(completion) completion(YES);
}
}];
}
- (void)close:(NSString *)uid
......@@ -56,27 +54,4 @@
[self.navigationController popViewControllerAnimated:animated];
}
}
#pragma mark - Boost 1.0 - deprecated~
- (void)openPage:(NSString *)name
params:(NSDictionary *)params
animated:(BOOL)animated
completion:(void (^)(BOOL))completion
{
NSMutableDictionary *exts = NSMutableDictionary.new;
exts[@"url"] = name;
exts[@"params"] = params;
exts[@"animated"] = @(animated);
[self open:name urlParams:params exts:exts completion:completion];
return;
}
- (void)closePage:(NSString *)uid animated:(BOOL)animated params:(NSDictionary *)params completion:(void (^)(BOOL))completion
{
NSMutableDictionary *exts = NSMutableDictionary.new;
exts[@"params"] = params;
exts[@"animated"] = @(animated);
[self close:uid result:@{} exts:exts completion:completion];
return;
}
@end
......@@ -8,7 +8,6 @@
#import "UIViewControllerDemo.h"
#import <Flutter/Flutter.h>
#import "DemoRouter.h"
#import <flutter_boost/FlutterBoostPlugin.h>
......@@ -24,20 +23,19 @@
}
- (IBAction)pushFlutterPage:(id)sender {
[DemoRouter.sharedRouter open:@"first"
urlParams:@{}
exts:@{@"animated":@(YES)}
completion:^(BOOL f){
[FlutterBoostPlugin open:@"first" urlParams:@{kPageCallBackId:@"MycallbackId#1"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is opened");
}];
}
- (IBAction)present:(id)sender {
[DemoRouter.sharedRouter open:@"second"
urlParams:@{@"present":@(YES)}
exts:@{@"animated":@(YES)}
completion:^(BOOL f){}];
// [self dismissViewControllerAnimated:YES completion:completion];
[FlutterBoostPlugin open:@"second" urlParams:@{@"present":@(YES),kPageCallBackId:@"MycallbackId#2"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) {
NSLog(@"call me when page finished, and your result is:%@", result);
} completion:^(BOOL f) {
NSLog(@"page is presented");
}];
}
/*
......
......@@ -12,13 +12,10 @@ class FirstRouteWidget extends StatelessWidget {
child: RaisedButton(
child: Text('Open second route'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value){
print("did recieve second route result");
print("did recieve second route result $value");
FlutterBoost.singleton.open("second").then((Map value) {
print("call me when page is finished. did recieve second route result $value");
});
},
),
),
......@@ -37,9 +34,11 @@ class SecondRouteWidget extends StatelessWidget {
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings = BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,result: {"result":"data from second"});
BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result: {"result": "data from second"});
},
child: Text('Go back with result!'),
),
......@@ -103,7 +102,7 @@ class FlutterRouteWidget extends StatelessWidget {
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://nativePage", urlParams:{
FlutterBoost.singleton.open("sample://nativePage", urlParams: {
"query": {"aaa": "bbb"}
}),
),
......@@ -120,7 +119,7 @@ class FlutterRouteWidget extends StatelessWidget {
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://flutterPage", urlParams:{
FlutterBoost.singleton.open("sample://flutterPage", urlParams: {
"query": {"aaa": "bbb"}
}),
),
......@@ -141,15 +140,15 @@ class FlutterRouteWidget extends StatelessWidget {
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton
.open("sample://flutterFragmentPage"),
)
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
),
],
),
);
......@@ -196,8 +195,7 @@ class FragmentRouteWidget extends StatelessWidget {
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open("sample://nativePage"),
onTap: () => FlutterBoost.singleton.open("sample://nativePage"),
),
InkWell(
child: Container(
......@@ -208,8 +206,7 @@ class FragmentRouteWidget extends StatelessWidget {
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterPage"),
onTap: () => FlutterBoost.singleton.open("sample://flutterPage"),
),
InkWell(
child: Container(
......@@ -220,8 +217,8 @@ class FragmentRouteWidget extends StatelessWidget {
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton
.open("sample://flutterFragmentPage"),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
)
],
),
......@@ -268,6 +265,6 @@ class _PushWidgetState extends State<PushWidget> {
@override
Widget build(BuildContext context) {
return FlutterRouteWidget(message:"Pushed Widget");
return FlutterRouteWidget(message: "Pushed Widget");
}
}
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages
.pub-cache/
.pub/
/build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: d226c1b0400dd8666bfff7716f9db3edb978f576
channel: yujie_working_meta
project_type: app
# example_swift
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.example_swift"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example_swift">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example_swift">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="example_swift"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example_swift">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
buildscript {
ext.kotlin_version = '1.2.71'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx1536M
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}
# pod 'flutter_boost', :path => '../../ios'
# pod 'xservice_kit', :path => '.symlinks/plugins/xservice_kit/ios'
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(p[:path], 'ios')
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
PODS:
- Flutter (1.0.0)
- flutter_boost (0.0.2):
- Flutter
DEPENDENCIES:
- Flutter (from `.symlinks/flutter/ios`)
- flutter_boost (from `/Users/yujie/Desktop/FlutterWork/flutter_boost/ios`)
EXTERNAL SOURCES:
Flutter:
:path: ".symlinks/flutter/ios"
flutter_boost:
:path: "/Users/yujie/Desktop/FlutterWork/flutter_boost/ios"
SPEC CHECKSUMS:
Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
flutter_boost: a7cfa776b75329d5e7d101d0cd33e75042bcde69
PODFILE CHECKSUM: 2a757a7bdc03b37a2814666652fdff1cf694243f
COCOAPODS: 1.2.0
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
</dict>
</plist>
import UIKit
import Flutter
//import flutter_boost
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
let router = PlatformRouterImp.init();
FlutterBoostPlugin.sharedInstance()?.startFlutter(with: router, onStart: { (engine) in
});
self.window = UIWindow.init(frame: UIScreen.main.bounds)
let viewController = ViewController.init()
let navi = UINavigationController.init(rootViewController: viewController)
self.window.rootViewController = navi
self.window.makeKeyAndVisible()
return true;//super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example_swift</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
//
// PlatformRouterImp.swift
// Runner
//
// Created by yujie on 2019/9/18.
// Copyright © 2019 The Chromium Authors. All rights reserved.
//
import Foundation
//import flutter_boost
class PlatformRouterImp: NSObject, FLBPlatform {
func open(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
var animated = false;
if exts["animated"] != nil{
animated = exts["animated"] as! Bool;
}
let vc = FLBFlutterViewContainer.init();
vc.setName(url, params: urlParams);
self.navigationController().pushViewController(vc, animated: animated);
completion(true);
}
func present(_ url: String, urlParams: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
var animated = false;
if exts["animated"] != nil{
animated = exts["animated"] as! Bool;
}
let vc = FLBFlutterViewContainer.init();
vc.setName(url, params: urlParams);
navigationController().present(vc, animated: animated) {
completion(true);
};
}
func close(_ uid: String, result: [AnyHashable : Any], exts: [AnyHashable : Any], completion: @escaping (Bool) -> Void) {
var animated = false;
if exts["animated"] != nil{
animated = exts["animated"] as! Bool;
}
let presentedVC = self.navigationController().presentedViewController;
let vc = presentedVC as? FLBFlutterViewContainer;
if vc?.uniqueIDString() == uid {
vc?.dismiss(animated: animated, completion: {
completion(true);
});
}else{
self.navigationController().popViewController(animated: animated);
}
}
func navigationController() -> UINavigationController {
let delegate = UIApplication.shared.delegate as! AppDelegate
let navigationController = delegate.window?.rootViewController as! UINavigationController
return navigationController;
}
}
#import "GeneratedPluginRegistrant.h"
#import <flutter_boost/FlutterBoost.h>
//
// ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func onClickPushFlutterPage(_ sender: UIButton, forEvent event: UIEvent){
FlutterBoostPlugin.open("first", urlParams:[kPageCallBackId:"MycallbackId#1"], exts: ["animated":true], onPageFinished: { (_ result:Any?) in
print(String(format:"call me when page finished, and your result is:%@", result as! CVarArg));
}) { (f:Bool) in
print(String(format:"page is opened"));
}
}
@IBAction func onClickPresentFlutterPage(_ sender: UIButton, forEvent event: UIEvent){
FlutterBoostPlugin.present("second", urlParams:[kPageCallBackId:"MycallbackId#2"], exts: ["animated":true], onPageFinished: { (_ result:Any?) in
print(String(format:"call me when page finished, and your result is:%@", result as! CVarArg));
}) { (f:Bool) in
print(String(format:"page is presented"));
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ViewController" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="view" destination="iN0-l3-epB" id="QCx-IN-Rvv"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="56F-Aq-MpV">
<rect key="frame" x="142" y="477" width="131" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Push Flutter Page"/>
<connections>
<action selector="onClickPushFlutterPage:forEvent:" destination="-2" eventType="touchDown" id="5vn-QH-QFi"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SLD-B1-poO">
<rect key="frame" x="133" y="557" width="148" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Present Flutter Page"/>
<connections>
<action selector="onClickPresentFlutterPage:forEvent:" destination="-2" eventType="touchDown" id="Ifi-Nd-kuj"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="This a native page" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aKb-hH-mdT">
<rect key="frame" x="138" y="376" width="139" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="0.1013311844" blue="0.1087444469" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<point key="canvasLocation" x="47.826086956521742" y="35.491071428571423"/>
</view>
</objects>
</document>
Future<Map<String,dynamic>> open(String url,{Map<String,dynamic> urlParams,Map<String,dynamic> exts}){
}
void close(String id,{Map<String,dynamic> result,Map<String,dynamic> exts}){
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'simple_page_widgets.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
'tab': (pageName, params, _) => TabRouteWidget(),
'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
///可以在native层通过 getContainerParams 来传递参数
'flutterPage': (pageName, params, _) {
print("flutterPage params:$params");
return FlutterRouteWidget();
},
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container());
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {
}
}
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
class FirstRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: Text('Open second route'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print("call me when page is finished. did recieve second route result $value");
});
},
),
),
);
}
}
class SecondRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result: {"result": "data from second"});
},
child: Text('Go back with result!'),
),
),
);
}
}
class TabRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tab Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
FlutterBoost.singleton.open("second");
},
child: Text('Open second route'),
),
),
);
}
}
class FlutterRouteWidget extends StatelessWidget {
final String message;
FlutterRouteWidget({this.message});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
message ?? "This is a flutter activity",
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
),
Expanded(child: Container()),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://nativePage", urlParams: {
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://flutterPage", urlParams: {
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (_) => PushWidget()));
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
),
],
),
);
}
}
class FragmentRouteWidget extends StatelessWidget {
final Map params;
FragmentRouteWidget(this.params);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
"This is a flutter fragment",
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
),
Container(
margin: const EdgeInsets.only(top: 32.0),
child: Text(
params['tag'] ?? '',
style: TextStyle(fontSize: 28.0, color: Colors.red),
),
alignment: AlignmentDirectional.center,
),
Expanded(child: Container()),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://nativePage"),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://flutterPage"),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
)
],
),
);
}
}
class PushWidget extends StatefulWidget {
@override
_PushWidgetState createState() => _PushWidgetState();
}
class _PushWidgetState extends State<PushWidget> {
VoidCallback _backPressedListenerUnsub;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
// if (_backPressedListenerUnsub == null) {
// _backPressedListenerUnsub =
// BoostContainer.of(context).addBackPressedListener(() {
// if (BoostContainer.of(context).onstage &&
// ModalRoute.of(context).isCurrent) {
// Navigator.pop(context);
// }
// });
// }
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_backPressedListenerUnsub?.call();
}
@override
Widget build(BuildContext context) {
return FlutterRouteWidget(message: "Pushed Widget");
}
}
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key key, this.title = "Input Test"}) : super(key: key);
final String title;
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
bottom: false,
child: ListView(
children: <Widget>[
Container(
child: Text(
'You have pushed the button this many times:',
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
Container(
child: Container(
color: Colors.red,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.orange,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.green,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.blue,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.yellow,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
],
)),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class TestTextField extends StatefulWidget {
@override
_TestTextFieldState createState() => _TestTextFieldState();
}
class _TestTextFieldState extends State<TestTextField> {
FocusNode _node;
PersistentBottomSheetController _controller;
@override
void initState() {
// TODO: implement initState
super.initState();
_node = FocusNode();
_node.addListener(() {
if (_node.hasFocus) {
print('showBottomSheet');
_controller = Scaffold.of(context)
.showBottomSheet((BuildContext ctx) => Container(
width: double.infinity,
height: 36.0,
color: Colors.deepPurple,
));
} else {
if (_controller != null) {
//Navigator.of(context).pop();
print('closeBottomSheet');
_controller.close();
}
_controller = null;
}
});
}
@override
Widget build(BuildContext context) {
return Container(
child: TextField(
minLines: 2,
maxLines: 10,
focusNode: _node,
),
padding: const EdgeInsets.all(8.0),
);
}
}
name: flutter_boost_example
description: Demonstrates how to use the flutter_boost plugin.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_boost:
path: ../
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:example_swift/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
......@@ -35,9 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
- (id<FLBFlutterProvider>)flutterProvider;
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(id<FlutterBinaryMessenger,
FlutterTextureRegistry,
FlutterPluginRegistry> engine))callback;
onStart:(void (^)(FlutterEngine *engine))callback;
- (FlutterViewController *)flutterViewController;
......@@ -55,14 +53,14 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - handle messages
- (void)close:(NSString *)uid
result:(NSDictionary *)result
result:(NSDictionary *)resultData
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion;
- (void)open:(NSString *)url
- (void)open:(NSString *)uri
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
reult:(void (^)(NSDictionary *))resultCallback
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion;
......
......@@ -24,17 +24,55 @@
#import <Foundation/Foundation.h>
#define kPageCallBackId @"__callback_id__"
NS_ASSUME_NONNULL_BEGIN
/**
* 定义协议:平台侧的页面打开和关闭,不建议直接使用该协议的实现来页面打开/关闭,建议使用FlutterBoostPlugin中的open和close方法来打开或关闭页面;
* FlutterBoostPlugin带有页面返回数据的能力
*/
@protocol FLBPlatform <NSObject>
@optional
- (NSString *)entryForDart;
@required
/**
* 基于Native平台实现页面打开,Dart层的页面打开能力依赖于这个函数实现;Native或者Dart侧不建议直接使用这个函数。应直接使用FlutterBoost封装的函数
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
- (void)open:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
completion:(void (^)(BOOL finished))completion;
/**
* 基于Native平台实现present页面打开,Dart层的页面打开能力依赖于这个函数实现;Native或者Dart侧不建议直接使用这个函数。应直接使用FlutterBoost封装的函数
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
@optional
- (void)present:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
completion:(void (^)(BOOL finished))completion;
/**
* 基于Native平台实现页面关闭,Dart层的页面关闭能力依赖于这个函数实现;Native或者Dart侧不建议直接使用这个函数。应直接使用FlutterBoost封装的函数
*
* @param uid 关闭的页面唯一ID符
* @param result 页面要返回的结果(给上一个页面),会作为页面返回函数的回调参数
* @param exts 额外参数
* @param completion 关闭页面的即时回调,页面一旦关闭即回调
*/
- (void)close:(NSString *)uid
result:(NSDictionary *)result
exts:(NSDictionary *)exts
......
......@@ -30,10 +30,14 @@
#pragma mark - Initializer
+ (instancetype)sharedInstance;
/**
* 初始化FlutterBoost混合栈环境。应在程序使用混合栈之前调用。如在AppDelegate中
*
* @param platform 平台层实现FLBPlatform的对象
* @param callback 启动之后回调
*/
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(id<FlutterBinaryMessenger,
FlutterTextureRegistry,
FlutterPluginRegistry> engine))callback;
onStart:(void (^)(FlutterEngine *engine))callback;
#pragma mark - Some properties.
- (BOOL)isRunning;
......@@ -46,4 +50,49 @@
- (FLBVoidCallback)addEventListener:(FLBEventListener)listner
forName:(NSString *)name;
#pragma mark - open/close Page
/**
* 关闭页面,混合栈推荐使用的用于操作页面的接口
*
* @param uniqueId 关闭的页面唯一ID符
* @param resultData 页面要返回的结果(给上一个页面),会作为页面返回函数的回调参数
* @param exts 额外参数
* @param completion 关闭页面的即时回调,页面一旦关闭即回调
*/
+ (void)close:(NSString *)uniqueId
result:(NSDictionary *)resultData
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion;
/**
* 打开新页面(默认以push方式),混合栈推荐使用的用于操作页面的接口;通过urlParams可以设置为以present方式打开页面:urlParams:@{@"present":@(YES)}
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param resultCallback 当页面结束返回时执行的回调,通过这个回调可以取得页面的返回数据,如close函数传入的resultData
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
+ (void)open:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion;
/**
* Present方式打开新页面,混合栈推荐使用的用于操作页面的接口
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param resultCallback 当页面结束返回时执行的回调,通过这个回调可以取得页面的返回数据,如close函数传入的resultData
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
+ (void)present:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion;
@end
......@@ -86,7 +86,7 @@
[[FlutterBoostPlugin sharedInstance].application open:url
urlParams:urlParams
exts:exts
reult:result
onPageFinished:result
completion:^(BOOL r) {}];
}else if([@"pageOnStart" isEqualToString:call.method]){
NSMutableDictionary *pageInfo = [NSMutableDictionary new];
......@@ -124,9 +124,7 @@
}
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(id<FlutterBinaryMessenger,
FlutterTextureRegistry,
FlutterPluginRegistry> engine))callback;
onStart:(void (^)(FlutterEngine *engine))callback;
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
......@@ -164,4 +162,21 @@
forName:name];
}
#pragma mark - open/close Page
+ (void)open:(NSString *)url urlParams:(NSDictionary *)urlParams exts:(NSDictionary *)exts onPageFinished:(void (^)(NSDictionary *))resultCallback completion:(void (^)(BOOL))completion{
id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application];
[app open:url urlParams:urlParams exts:exts onPageFinished:resultCallback completion:completion];
}
+ (void)present:(NSString *)url urlParams:(NSDictionary *)urlParams exts:(NSDictionary *)exts onPageFinished:(void (^)(NSDictionary *))resultCallback completion:(void (^)(BOOL))completion{
id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application];
NSMutableDictionary *myParams = [[NSMutableDictionary alloc]initWithDictionary:urlParams];
[myParams setObject:@(YES) forKey:@"present"];
[app open:url urlParams:myParams exts:exts onPageFinished:resultCallback completion:completion];
}
+ (void)close:(NSString *)uniqueId result:(NSDictionary *)resultData exts:(NSDictionary *)exts completion:(void (^)(BOOL))completion{
id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application];
[app close:uniqueId result:resultData exts:exts completion:completion];
}
@end
......@@ -30,7 +30,7 @@
- (id<FLBFlutterApplicationInterface>)createApplication:(id<FLBPlatform>)platform
{
return FLBFlutterApplication.new;
return [FLBFlutterApplication sharedApplication];
}
- (id<FLBFlutterContainer>)createFlutterContainer
......
......@@ -30,6 +30,6 @@
NS_ASSUME_NONNULL_BEGIN
@interface FLBFlutterApplication : NSObject<FLBFlutterApplicationInterface>
@property (nonatomic,strong) id<FLBPlatform> platform;
+ (FLBFlutterApplication *)sharedApplication;
@end
NS_ASSUME_NONNULL_END
......@@ -37,6 +37,7 @@
@implementation FLBFlutterApplication
@synthesize platform;
+ (FLBFlutterApplication *)sharedApplication
{
......@@ -59,7 +60,7 @@
}
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(id<FlutterBinaryMessenger,FlutterTextureRegistry,FlutterPluginRegistry> _Nonnull))callback
onStart:(void (^)(FlutterEngine *engine))callback
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
......@@ -151,18 +152,18 @@
}
- (void)close:(NSString *)uniqueId
result:(NSDictionary *)result
result:(NSDictionary *)resultData
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion
{
[self.platform close:uniqueId
result:result
result:resultData
exts:exts
completion:completion];
if(_pageResultCallbacks[uniqueId]){
void (^cb)(NSDictionary *) = _pageResultCallbacks[uniqueId];
cb(result);
cb(resultData);
[_pageResultCallbacks removeObjectForKey:uniqueId];
}
}
......@@ -170,30 +171,39 @@
- (void)open:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
reult:(void (^)(NSDictionary *))resultCallback
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion
{
NSString *cid = urlParams[@"__calback_id__"];
NSString *cid = urlParams[kPageCallBackId];
if(!cid){
static int64_t sCallbackID = 1;
cid = @(sCallbackID).stringValue;
sCallbackID += 2;
NSMutableDictionary *newParams = [[NSMutableDictionary alloc]initWithDictionary:urlParams];
[newParams setObject:cid?cid:@"__default#0__" forKey:kPageCallBackId];
urlParams = newParams;
}
_callbackCache[cid] = resultCallback;
[self.platform open:url
urlParams:urlParams
exts:exts
completion:completion];
if([urlParams[@"present"]respondsToSelector:@selector(boolValue)] && [urlParams[@"present"] boolValue] && [self.platform respondsToSelector:@selector(present:urlParams:exts:completion:)]){
[self.platform present:url
urlParams:urlParams
exts:exts
completion:completion];
}else{
[self.platform open:url
urlParams:urlParams
exts:exts
completion:completion];
}
}
- (void)didInitPageContainer:(NSString *)url
params:(NSDictionary *)urlParams
uniqueId:(NSString *)uniqueId
{
NSString *cid = urlParams[@"__calback_id__"];
NSString *cid = urlParams[kPageCallBackId];
if(cid && _callbackCache[cid]){
_pageResultCallbacks[uniqueId] = _callbackCache[cid];
[_callbackCache removeObjectForKey:cid];
......
......@@ -28,6 +28,6 @@
NS_ASSUME_NONNULL_BEGIN
@interface FLBFlutterEngine : NSObject<FLBFlutterProvider>
- (instancetype)initWithPlatform:(id<FLBPlatform>)platform;
- (instancetype)initWithPlatform:(id<FLBPlatform>_Nullable)platform;
@end
NS_ASSUME_NONNULL_END
......@@ -35,7 +35,7 @@
@implementation FLBFlutterEngine
- (instancetype)initWithPlatform:(id<FLBPlatform>)platform
- (instancetype)initWithPlatform:(id<FLBPlatform> _Nullable)platform
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
......
......@@ -37,6 +37,8 @@
@property (nonatomic,assign) long long identifier;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation FLBFlutterViewContainer
- (instancetype)init
......@@ -236,3 +238,4 @@ static NSUInteger kInstanceCounter = 0;
@end
#pragma clang diagnostic pop
......@@ -95,25 +95,25 @@ class FlutterBoost {
ContainerCoordinator.singleton.registerPageBuilders(builders);
}
Future<Map<String,dynamic>> open(String url,{Map<String,dynamic> urlParams,Map<String,dynamic> exts}){
Future<Map<dynamic,dynamic>> open(String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts}){
Map<String, dynamic> properties = new Map<String, dynamic>();
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
properties["url"] = url;
properties["urlParams"] = urlParams;
properties["exts"] = exts;
return channel.invokeMethod<Map<String,dynamic>>(
return channel.invokeMethod<Map<dynamic,dynamic>>(
'openPage', properties);
}
Future<bool> close(String id,{Map<String,dynamic> result,Map<String,dynamic> exts}){
Future<bool> close(String id,{Map<dynamic,dynamic> result,Map<dynamic,dynamic> exts}){
assert(id != null);
BoostContainerSettings settings = containerManager?.onstageSettings;
Map<String, dynamic> properties = new Map<String, dynamic>();
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
if(exts == null){
exts = Map<String,dynamic>();
exts = Map<dynamic,dynamic>();
}
exts["params"] = settings.params;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment