之前搞的Flutter版工具链已经弄完了,感兴趣的朋友可以围观下,Android版本dio库(v2.0.14)发送网络请求老是报错,去官方提了issue还没回,于是今天搞一下把Flutter??榻尤氲揭延邢钅恐?。
首先Flutter官方已经出了wiki,教大家怎么接入。懒得看官方原文的可以看看这个简易版快速集成,先来看看效果。
一、创建Flutter???/h3>
一般用Flutter
或者React Native
的团队大部分原因都是因为需要跨平台,所以在已有项目目录的上一级创建Flutter
??椋┤缒愕墓ぷ髂柯荚?code>some/path/MyApp,那么你需要在some/path
下执行,这样Flutter
可以单独交给一个虚拟团队维护,各自独立。
$ cd some/path/
$ flutter create -t module my_flutter
文件结构如下:
some/path/
my_flutter/
lib/main.dart
.ios/
MyApp/
MyApp.xcodeproj
Podfile
MyApp/
AppDelegate.h
AppDelegate.m (or swift)
二、利用Cocoapods添加依赖
没用过Cocoapods
的童鞋可以google
搜一下,之前写过很多Cocoapods
的文章由于博客主机商跑路都没了,说多了都是泪
1.在Podfile文件加入以下代码:
flutter_application_path = '../my_flutter/'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)
注意my_flutter
的路径,因为我们是以xcodeproj
文件的上一级创建的,所以需要加../,这个和React Native
引入依赖路径是一样的,都需要注意这个问题。
2.执行pod install
注:如果报错
[!] InvalidPodfilefile: No such file or directory @ rb_sysopen - ./my_flutter/.ios/Flutter/podhelper.rb.
需要在my_flutter
文件夹下执行以下flutter run
,把.ios
和.android
等flutter
配置生成出来。
3.禁用bitcode,设置环境变量
找到你的target
,Build Settings->Build Options->Enable Bitcode
设置为NO
,另外在Preprocessor Macros
添加FLUTTER_BUILD_MODE=Debug
和FLUTTER_BUILD_MODE=Release
,如果还有其他环境需要根据情况选择Debug
或Release
。
4.添加run script
找到你的target
,Build Phases -> + -> New Run Script Phase
,并且在bash
或zsh
配置FLUTTER_ROOT
,否则打包会出错找不到flutter
。涉及多人开发还需要安装路径位置,否则团队小伙伴每个人的路径不一样。
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
注:把这个script放到Target Dependencies phasescript的后面。
5.添加assets资源
官网说需要添加Flutter.framework
资源,但是这个Cocoapods
已经帮忙引入了,所以就不需要了,如果没有被引入进去那就手动引入下。这里只需要添加flutter_assets
就行了,记得选Creat folder references
引入方式。Flutter
1.0.0版本路径是my_flutter->build->flutter_assets
6.修改AppDelegate
Objective-C:
AppDelegate.h
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
AppDelegate.m
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Only if you have Flutter Plugins
#include "AppDelegate.h"
@implementation AppDelegate
// This override can be omitted if you do not have any Flutter Plugins.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
Swift:
AppDelegate.swift
import UIKit
import Flutter
import FlutterPluginRegistrant // Only if you have Flutter Plugins.
@UIApplicationMain
class AppDelegate: FlutterAppDelegate {
var flutterEngine : FlutterEngine?;
// Only if you have Flutter plugins.
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil);
self.flutterEngine?.run(withEntrypoint: nil);
GeneratedPluginRegistrant.register(with: self.flutterEngine);
return super.application(application, didFinishLaunchingWithOptions: launchOptions);
}
}
到这里,我们的Flutter就算已经引入工程了
三、跳转Flutter页面
Objective-C:
ViewController.m
#import <Flutter/Flutter.h>
#import "AppDelegate.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(handleButtonAction)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Press me" forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blueColor]];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)handleButtonAction {
FlutterEngine *flutterEngine = [(AppDelegate *)[[UIApplication sharedApplication] delegate] flutterEngine];
FlutterViewController *flutterViewController = [[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:false completion:nil];
}
@end
Swift:
ViewController.swift
import UIKit
import Flutter
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type:UIButtonType.custom)
button.addTarget(self, action: #selector(handleButtonAction), for: .touchUpInside)
button.setTitle("Press me", for: UIControlState.normal)
button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
button.backgroundColor = UIColor.blue
self.view.addSubview(button)
}
@objc func handleButtonAction() {
let flutterEngine = (UIApplication.shared.delegate as? AppDelegate)?.flutterEngine;
let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)!;
self.present(flutterViewController, animated: false, completion: nil)
}
}
剩下的就是写Flutter
页面逻辑了以及Flutter
模块需要调用Native API
(后面专门写一篇文章)。
写完Flutter
页面,如果要跳转到指定页面使用Flutter
的路由就可以了
Objective-C:
[flutterViewController setInitialRoute:@"route1"];
Swift:
flutterViewController.setInitialRoute("route1")
四、运行
在my_flutter
手动flutter run
一下,或者直接开启热加载,然后就可以在原有的iOS
项目中用Xcoderun
起来了。
$ flutter attach --isolate-filter='debug'
Waiting for a connection from Flutter...
Done.
Syncing files to device... 1.1s
?? To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler is available at: http://127.0.0.1:43343/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".
Connected view:
debug isolate (isolates/642101161)
五、发布
执行flutter build ios
以创建release
版本(flutter build
默认为--release
)