README_CN.md 13.4 KB
Newer Older
Jidong Chen's avatar
init  
Jidong Chen committed
1 2 3 4
<p align="center">
  <img src="flutter_boost.png">
</p>

5

yangwu.jia's avatar
yangwu.jia committed
6 7
# Release Note

yangwu.jia's avatar
yangwu.jia committed
8
 请查看最新版本0.1.60的release note 确认变更,[0.1.60 release note](https://github.com/alibaba/flutter_boost/releases)
9

Jidong Chen's avatar
init  
Jidong Chen committed
10 11 12 13 14 15
# FlutterBoost

新一代Flutter-Native混合解决方案。 FlutterBoost是一个Flutter插件,它可以轻松地为现有原生应用程序提供Flutter混合集成方案。FlutterBoost的理念是将Flutter像Webview那样来使用。在现有应用程序中同时管理Native页面和Flutter页面并非易事。 FlutterBoost帮你处理页面的映射和跳转,你只需关心页面的名字和参数即可(通常可以是URL)。


# 前置条件
yangwu.jia's avatar
yangwu.jia committed
16 17

在继续之前,您需要将Flutter集成到你现有的项目中。flutter sdk 的版本需要 v1.9.1-hotfixes,否则会编译失败.
Jidong Chen's avatar
init  
Jidong Chen committed
18 19 20 21 22 23 24

# 安装

## 在Flutter项目中添加依赖项。

打开pubspec.yaml并将以下行添加到依赖项:

yangwu.jia's avatar
yangwu.jia committed
25
support分支
Jidong Chen's avatar
Jidong Chen committed
26
```json
yangwu.jia's avatar
yangwu.jia committed
27

yangwu.jia's avatar
yangwu.jia committed
28 29 30
flutter_boost:
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
yangwu.jia's avatar
yangwu.jia committed
31 32
        ref: '0.1.60'

Jidong Chen's avatar
init  
Jidong Chen committed
33 34
```

yangwu.jia's avatar
yangwu.jia committed
35 36
androidx分支
```json
Jidong Chen's avatar
Jidong Chen committed
37
flutter_boost:
yangwu.jia's avatar
yangwu.jia committed
38 39 40
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'feature/flutter_1.9_androidx_upgrade'
Jidong Chen's avatar
Jidong Chen committed
41
```
yangwu.jia's avatar
yangwu.jia committed
42

Jidong Chen's avatar
init  
Jidong Chen committed
43 44 45 46
## Dart代码的集成
将init代码添加到App 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
}
```

## iOS代码集成。

Jidong Chen's avatar
Jidong Chen committed
91 92
注意:需要将libc++ 加入 "Linked Frameworks and Libraries" 中。

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

Jidong Chen's avatar
init  
Jidong Chen committed
95 96 97 98 99 100 101 102 103 104 105
使用FLBFlutterAppDelegate作为AppDelegate的超类

```objectivec
@interface AppDelegate : FLBFlutterAppDelegate <UIApplicationDelegate>
@end
```


为您的应用程序实现FLBPlatform协议方法。

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


余玠's avatar
余玠 committed
111
@implementation PlatformRouterImp
Jidong Chen's avatar
init  
Jidong Chen committed
112

yangwu.jia's avatar
yangwu.jia committed
113 114 115 116 117
#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
118
{
yangwu.jia's avatar
yangwu.jia committed
119 120 121 122 123
    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
124 125
}

yangwu.jia's avatar
yangwu.jia committed
126 127 128 129 130 131 132 133 134 135 136 137
- (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
138

yangwu.jia's avatar
yangwu.jia committed
139 140 141 142
- (void)close:(NSString *)uid
       result:(NSDictionary *)result
         exts:(NSDictionary *)exts
   completion:(void (^)(BOOL))completion
Jidong Chen's avatar
init  
Jidong Chen committed
143
{
yangwu.jia's avatar
yangwu.jia committed
144 145
    BOOL animated = [exts[@"animated"] boolValue];
    animated = YES;
Jidong Chen's avatar
init  
Jidong Chen committed
146 147 148 149 150 151 152 153 154 155 156 157
    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
```

在应用程序开头使用FLBPlatform初始化FlutterBoost。

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

yangwu.jia's avatar
yangwu.jia committed
166 167 168 169 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
### swift:

初始化
```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)
  }
}
```

为您的应用程序实现FLBPlatform协议方法。
```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
244 245 246 247 248
## Android代码集成。

在Application.onCreate()中初始化FlutterBoost

```java
yangwu.jia's avatar
yangwu.jia committed
249 250 251
public class MyApplication extends Application {


Jidong Chen's avatar
init  
Jidong Chen committed
252 253 254
    @Override
    public void onCreate() {
        super.onCreate();
yangwu.jia's avatar
yangwu.jia committed
255
        INativeRouter router =new INativeRouter() {
Jidong Chen's avatar
init  
Jidong Chen committed
256
            @Override
yangwu.jia's avatar
yangwu.jia committed
257 258 259
            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
260 261
            }

yangwu.jia's avatar
yangwu.jia committed
262
        };
Jidong Chen's avatar
init  
Jidong Chen committed
263

yangwu.jia's avatar
yangwu.jia committed
264
        FlutterBoost.BoostLifecycleListener lifecycleListener= new FlutterBoost.BoostLifecycleListener() {
Jidong Chen's avatar
init  
Jidong Chen committed
265
            @Override
yangwu.jia's avatar
yangwu.jia committed
266 267
            public void onEngineCreated() {

Jidong Chen's avatar
init  
Jidong Chen committed
268 269 270
            }

            @Override
yangwu.jia's avatar
yangwu.jia committed
271 272 273 274 275
            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
276 277 278
            }

            @Override
yangwu.jia's avatar
yangwu.jia committed
279 280
            public void onEngineDestroy() {

Jidong Chen's avatar
init  
Jidong Chen committed
281
            }
yangwu.jia's avatar
yangwu.jia committed
282 283 284 285 286 287 288 289 290 291 292 293 294
        };
        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);



Jidong Chen's avatar
init  
Jidong Chen committed
295
    }
yangwu.jia's avatar
yangwu.jia committed
296
}
Jidong Chen's avatar
init  
Jidong Chen committed
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
```

# 基本用法
## 概念

所有页面路由请求都将发送到Native路由器。Native路由器与Native Container Manager通信,Native Container Manager负责构建和销毁Native Containers。

## 使用Flutter Boost Native Container用Native代码打开Flutter页面。

```objc
 FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
        [vc setName:name params:params];
        [self.navigationController presentViewController:vc animated:animated completion:^{}];
```

余玠's avatar
余玠 committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
但是,这种方式无法获取页面返回的数据,建议你按上面的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];
```
Jidong Chen's avatar
init  
Jidong Chen committed
330 331 332
Android

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

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


yangwu.jia's avatar
yangwu.jia committed
338 339 340
        put("first", "first");
        put("second", "second");
        put("tab", "tab");
Jidong Chen's avatar
init  
Jidong Chen committed
341

yangwu.jia's avatar
yangwu.jia committed
342 343
        put("sample://flutterPage", "flutterPage");
    }};
Jidong Chen's avatar
init  
Jidong Chen committed
344

yangwu.jia's avatar
yangwu.jia committed
345 346 347
    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
348

yangwu.jia's avatar
yangwu.jia committed
349 350
    public static boolean openPageByUrl(Context context, String url, Map params) {
        return openPageByUrl(context, url, params, 0);
Jidong Chen's avatar
init  
Jidong Chen committed
351 352
    }

yangwu.jia's avatar
yangwu.jia committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
    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
379 380 381 382 383 384 385 386 387
    }
}
```


## 使用Flutter Boost在dart代码打开页面。
Dart

```java
yangwu.jia's avatar
yangwu.jia committed
388 389 390 391

 FlutterBoost.singleton
                .open("sample://flutterFragmentPage")

Jidong Chen's avatar
init  
Jidong Chen committed
392 393 394 395 396 397
```


## 使用Flutter Boost在dart代码关闭页面。

```java
yangwu.jia's avatar
yangwu.jia committed
398
 FlutterBoost.singleton.close(uniqueId);
Jidong Chen's avatar
init  
Jidong Chen committed
399 400 401 402 403 404 405 406
```

# Examples
更详细的使用例子请参考Demo

# 许可证
该项目根据MIT许可证授权 - 有关详细信息,请参阅[LICENSE.md](LICENSE.md)文件
<a name="Acknowledgments"> </a>
tino.wjf's avatar
tino.wjf committed
407

yangwu.jia's avatar
yangwu.jia committed
408 409 410 411 412
# 问题反馈群(钉钉群)

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


tino.wjf's avatar
tino.wjf committed
413 414 415 416 417 418 419 420 421 422 423 424 425
## 关于我们
阿里巴巴-闲鱼技术是国内最早也是最大规模线上运行Flutter的团队。

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

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

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

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

订阅地址

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

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