README.md 14.2 KB
Newer Older
Jidong Chen's avatar
init  
Jidong Chen committed
1 2 3 4
<p align="center">
  <img src="flutter_boost.png">
   <b></b><br>
  <a href="README_CN.md">中文文档</a>
Jidong Chen's avatar
Jidong Chen committed
5
  <a href="https://mp.weixin.qq.com/s?__biz=MzU4MDUxOTI5NA==&mid=2247484367&idx=1&sn=fcbc485f068dae5de9f68d52607ea08f&chksm=fd54d7deca235ec86249a9e3714ec18be8b2d6dc580cae19e4e5113533a6c5b44dfa5813c4c3&scene=0&subscene=131&clicktime=1551942425&ascene=7&devicetype=android-28&version=2700033b&nettype=ctnet&abtest_cookie=BAABAAoACwASABMABAAklx4AVpkeAMSZHgDWmR4AAAA%3D&lang=zh_CN&pass_ticket=1qvHqOsbLBHv3wwAcw577EHhNjg6EKXqTfnOiFbbbaw%3D&wx_header=1">中文介绍</a>
Jidong Chen's avatar
init  
Jidong Chen committed
6 7
</p>

yangwu.jia's avatar
yangwu.jia committed
8
# Release Note
yangwu.jia's avatar
yangwu.jia committed
9

yangwu.jia's avatar
yangwu.jia committed
10
Please checkout the release note for the latest 0.1.54 to see changes [0.1.54 release note](https://github.com/alibaba/flutter_boost/releases)
11

Jidong Chen's avatar
init  
Jidong Chen committed
12 13 14 15 16
# FlutterBoost
A next-generation Flutter-Native hybrid solution. FlutterBoost is a Flutter plugin which enables hybrid integration of Flutter for your existing native apps with minimum efforts.The philosophy of FlutterBoost is to use Flutter as easy as using a WebView. Managing Native pages and Flutter pages at the same time is non-trivial in an existing App. FlutterBoost takes care of page resolution for you. The only thing you need to care about is the name of the page(usually could be an URL). 
<a name="bf647454"></a>

# Prerequisites
yangwu.jia's avatar
yangwu.jia committed
17
You need to add Flutter to your project before moving on.The version of the flutter SDK requires v1.9.1+hotfixes, or it will compile error.
Jidong Chen's avatar
init  
Jidong Chen committed
18 19 20 21 22 23 24 25

# Getting Started


## Add a dependency in you Flutter project.

Open you pubspec.yaml and add the following line to dependencies:

yangwu.jia's avatar
yangwu.jia committed
26 27 28 29 30 31
support branch
```json
flutter_boost:
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'feature/flutter_1.9_upgrade'
Jidong Chen's avatar
init  
Jidong Chen committed
32
```
yangwu.jia's avatar
yangwu.jia committed
33 34
androidx branch
```json
Jidong Chen's avatar
Jidong Chen committed
35
flutter_boost:
yangwu.jia's avatar
yangwu.jia committed
36 37 38
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'feature/flutter_1.9_androidx_upgrade'
Jidong Chen's avatar
Jidong Chen committed
39 40 41
```


Jidong Chen's avatar
init  
Jidong Chen committed
42 43 44 45 46

## Integration with Flutter code.
Add init code to you App

```dart
yangwu.jia's avatar
yangwu.jia committed
47 48 49
void main() {
    runApp(MyApp());
}
Jidong Chen's avatar
init  
Jidong Chen committed
50 51

class MyApp extends StatefulWidget {
yangwu.jia's avatar
yangwu.jia committed
52 53
    @override
    _MyAppState createState() => _MyAppState();
Jidong Chen's avatar
init  
Jidong Chen committed
54 55 56
}

class _MyAppState extends State<MyApp> {
yangwu.jia's avatar
yangwu.jia committed
57 58
    @override
    void initState() {
Jidong Chen's avatar
init  
Jidong Chen committed
59
    super.initState();
yangwu.jia's avatar
yangwu.jia committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    
        FlutterBoost.singleton.registerPageBuilders({
            'first': (pageName, params, _) => FirstRouteWidget(),
            'second': (pageName, params, _) => SecondRouteWidget(),
            'tab': (pageName, params, _) => TabRouteWidget(),
            'platformView': (pageName, params, _) => PlatformRouteWidget(),
            'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
            'flutterPage': (pageName, params, _) {
                print("flutterPage params:$params");
            
                return FlutterRouteWidget(params:params);
            },
        });
    }
    
    @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 _) {
    }
Jidong Chen's avatar
init  
Jidong Chen committed
86 87 88 89 90 91
}
```


## Integration with iOS code.

Jidong Chen's avatar
Jidong Chen committed
92 93
Note: You need to add libc++ into "Linked Frameworks and Libraries" 

yangwu.jia's avatar
yangwu.jia committed
94 95
### objective-c:

Jidong Chen's avatar
init  
Jidong Chen committed
96 97
Use FLBFlutterAppDelegate as the superclass of your AppDelegate

yangwu.jia's avatar
yangwu.jia committed
98
```objectivec
Jidong Chen's avatar
init  
Jidong Chen committed
99 100 101 102 103 104 105 106
@interface AppDelegate : FLBFlutterAppDelegate <UIApplicationDelegate>
@end
```


Implement FLBPlatform protocol methods for your App.


yangwu.jia's avatar
yangwu.jia committed
107 108
```objectivec
@interface PlatformRouterImp : NSObject<FLBPlatform>
Jidong Chen's avatar
init  
Jidong Chen committed
109 110 111 112
@property (nonatomic,strong) UINavigationController *navigationController;
@end


余玠's avatar
余玠 committed
113
@implementation PlatformRouterImp
Jidong Chen's avatar
init  
Jidong Chen committed
114

yangwu.jia's avatar
yangwu.jia committed
115 116 117 118 119
#pragma mark - Boost 1.5
- (void)open:(NSString *)name
   urlParams:(NSDictionary *)params
        exts:(NSDictionary *)exts
  completion:(void (^)(BOOL))completion
Jidong Chen's avatar
init  
Jidong Chen committed
120
{
yangwu.jia's avatar
yangwu.jia committed
121 122 123 124 125
    BOOL animated = [exts[@"animated"] boolValue];
    FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
    [vc setName:name params:params];
    [self.navigationController pushViewController:vc animated:animated];
    if(completion) completion(YES);
Jidong Chen's avatar
init  
Jidong Chen committed
126 127
}

yangwu.jia's avatar
yangwu.jia committed
128 129 130 131 132 133 134 135 136 137 138 139
- (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);
    }];
}
Jidong Chen's avatar
init  
Jidong Chen committed
140

yangwu.jia's avatar
yangwu.jia committed
141 142 143 144
- (void)close:(NSString *)uid
       result:(NSDictionary *)result
         exts:(NSDictionary *)exts
   completion:(void (^)(BOOL))completion
Jidong Chen's avatar
init  
Jidong Chen committed
145
{
yangwu.jia's avatar
yangwu.jia committed
146 147
    BOOL animated = [exts[@"animated"] boolValue];
    animated = YES;
Jidong Chen's avatar
init  
Jidong Chen committed
148 149 150 151 152 153 154 155 156 157 158 159
    FLBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;
    if([vc isKindOfClass:FLBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: uid]){
        [vc dismissViewControllerAnimated:animated completion:^{}];
    }else{
        [self.navigationController popViewControllerAnimated:animated];
    }
}
@end
```



余玠's avatar
余玠 committed
160
Initialize FlutterBoost with FLBPlatform at the beginning of your App, such as AppDelegate.
Jidong Chen's avatar
init  
Jidong Chen committed
161 162

```objc
yangwu.jia's avatar
yangwu.jia committed
163 164
    PlatformRouterImp *router = [PlatformRouterImp new];
    [FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
余玠's avatar
余玠 committed
165
                                                        onStart:^(FlutterEngine *engine) {
Jidong Chen's avatar
init  
Jidong Chen committed
166 167 168 169
                                                            
                                                        }];
```

yangwu.jia's avatar
yangwu.jia committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
### swift:

init
```swift
@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)
  }
}
```

Implement FLBPlatform protocol methods for your App.

```swift
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;
    }
}
```


Jidong Chen's avatar
init  
Jidong Chen committed
248 249 250 251 252
## Integration with Android code.

Init FlutterBoost in Application.onCreate() 

```java
yangwu.jia's avatar
yangwu.jia committed
253 254 255
public class MyApplication extends Application {


Jidong Chen's avatar
init  
Jidong Chen committed
256 257 258
    @Override
    public void onCreate() {
        super.onCreate();
yangwu.jia's avatar
yangwu.jia committed
259
        INativeRouter router =new INativeRouter() {
Jidong Chen's avatar
init  
Jidong Chen committed
260
            @Override
yangwu.jia's avatar
yangwu.jia committed
261 262 263
            public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
               String  assembleUrl=Utils.assembleUrl(url,urlParams);
                PageRouter.openPageByUrl(context,assembleUrl, urlParams);
Jidong Chen's avatar
init  
Jidong Chen committed
264 265
            }

yangwu.jia's avatar
yangwu.jia committed
266 267 268
        };

        FlutterBoost.BoostLifecycleListener lifecycleListener= new FlutterBoost.BoostLifecycleListener() {
Jidong Chen's avatar
init  
Jidong Chen committed
269
            @Override
yangwu.jia's avatar
yangwu.jia committed
270 271
            public void onEngineCreated() {

Jidong Chen's avatar
init  
Jidong Chen committed
272 273 274
            }

            @Override
yangwu.jia's avatar
yangwu.jia committed
275 276 277 278 279
            public void onPluginsRegistered() {
                MethodChannel mMethodChannel = new MethodChannel( FlutterBoost.instance().engineProvider().getDartExecutor(), "methodChannel");
                Log.e("MyApplication","MethodChannel create");
                TextPlatformViewPlugin.register(FlutterBoost.instance().getPluginRegistry().registrarFor("TextPlatformViewPlugin"));

Jidong Chen's avatar
init  
Jidong Chen committed
280 281 282
            }

            @Override
yangwu.jia's avatar
yangwu.jia committed
283 284
            public void onEngineDestroy() {

Jidong Chen's avatar
init  
Jidong Chen committed
285
            }
yangwu.jia's avatar
yangwu.jia committed
286 287 288 289 290 291 292 293 294 295 296 297
        };
        Platform platform= new FlutterBoost
                .ConfigBuilder(this,router)
                .isDebug(true)
                .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
                .renderMode(FlutterView.RenderMode.texture)
                .lifecycleListener(lifecycleListener)
                .build();

        FlutterBoost.instance().init(platform);


yangwu.jia's avatar
yangwu.jia committed
298

Jidong Chen's avatar
init  
Jidong Chen committed
299
    }
yangwu.jia's avatar
yangwu.jia committed
300
}
Jidong Chen's avatar
init  
Jidong Chen committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
```


# Basic Usage
## Concepts

All page routing requests are being sent to the native router. Native router communicates with Native Container Manager, Native Container Manager takes care of building and destroying of Native Containers. 


## Use Flutter Boost Native Container to show a Flutter page in native code.

iOS

```objc
 FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
        [vc setName:name params:params];
        [self.navigationController presentViewController:vc animated:animated completion:^{}];
```
余玠's avatar
余玠 committed
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
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];
```
Jidong Chen's avatar
init  
Jidong Chen committed
336 337 338 339

Android

```java
yangwu.jia's avatar
yangwu.jia committed
340
public class PageRouter {
Jidong Chen's avatar
init  
Jidong Chen committed
341

yangwu.jia's avatar
yangwu.jia committed
342
    public final static Map<String, String> pageName = new HashMap<String, String>() {{
Jidong Chen's avatar
init  
Jidong Chen committed
343 344


yangwu.jia's avatar
yangwu.jia committed
345 346 347
        put("first", "first");
        put("second", "second");
        put("tab", "tab");
Jidong Chen's avatar
init  
Jidong Chen committed
348

yangwu.jia's avatar
yangwu.jia committed
349 350
        put("sample://flutterPage", "flutterPage");
    }};
Jidong Chen's avatar
init  
Jidong Chen committed
351

yangwu.jia's avatar
yangwu.jia committed
352 353 354
    public static final String NATIVE_PAGE_URL = "sample://nativePage";
    public static final String FLUTTER_PAGE_URL = "sample://flutterPage";
    public static final String FLUTTER_FRAGMENT_PAGE_URL = "sample://flutterFragmentPage";
Jidong Chen's avatar
init  
Jidong Chen committed
355

yangwu.jia's avatar
yangwu.jia committed
356 357
    public static boolean openPageByUrl(Context context, String url, Map params) {
        return openPageByUrl(context, url, params, 0);
Jidong Chen's avatar
init  
Jidong Chen committed
358 359
    }

yangwu.jia's avatar
yangwu.jia committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    public static boolean openPageByUrl(Context context, String url, Map params, int requestCode) {

        String path = url.split("\\?")[0];

        Log.i("openPageByUrl",path);

        try {
            if (pageName.containsKey(path)) {
                Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);

                context.startActivity(intent);

            } else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
                context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
                return true;
            } else if (url.startsWith(NATIVE_PAGE_URL)) {
                context.startActivity(new Intent(context, NativePageActivity.class));
                return true;
            } else {
                return false;
            }
        } catch (Throwable t) {
            return false;
        }
        return false;
Jidong Chen's avatar
init  
Jidong Chen committed
386 387 388 389 390 391 392 393 394 395
    }
}
```


## Use Flutter Boost to open a page in dart code.

Dart

```objc
yangwu.jia's avatar
yangwu.jia committed
396 397 398

FlutterBoost.singleton
                .open("pagename")
yangwu.jia's avatar
yangwu.jia committed
399

Jidong Chen's avatar
init  
Jidong Chen committed
400 401 402 403 404
```

## Use Flutter Boost to close a page in dart code.

```objc
yangwu.jia's avatar
yangwu.jia committed
405 406 407

FlutterBoost.singleton.close(uniqueId);

Jidong Chen's avatar
init  
Jidong Chen committed
408 409 410 411 412 413 414 415 416
```

# Running the Demo
Please see the example for details.


# License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details

yangwu.jia's avatar
yangwu.jia committed
417

yangwu.jia's avatar
yangwu.jia committed
418 419 420 421 422 423
# Problem feedback group( dingding group)

<img width="200" src="https://img.alicdn.com/tfs/TB1JSzVeYY1gK0jSZTEXXXDQVXa-892-1213.jpg">



yangwu.jia's avatar
yangwu.jia committed
424

tino.wjf's avatar
tino.wjf committed
425 426 427 428 429 430 431 432 433 434 435 436 437
## 关于我们
阿里巴巴-闲鱼技术是国内最早也是最大规模线上运行Flutter的团队。

我们在公众号中为你精选了Flutter独家干货,全面而深入。

内容包括:Flutter的接入、规模化应用、引擎探秘、工程体系、创新技术等教程和开源信息。

**架构/服务端/客户端/前端/算法/质量工程师 在公众号中投递简历,名额不限哦**

欢迎来闲鱼做一个好奇、幸福、有影响力的程序员,简历投递:tino.wjf@alibaba-inc.com

订阅地址

tino.wjf's avatar
tino.wjf committed
438
<img src="https://img.alicdn.com/tfs/TB17Ki5XubviK0jSZFNXXaApXXa-656-656.png" width="328px" height="328px">
tino.wjf's avatar
tino.wjf committed
439 440

[For English](https://twitter.com/xianyutech "For English")