1待诅、Flutter環(huán)境配置 Flutter中文網(wǎng) 跟著里面一步一步來就完事了介袜。
2偎漫、iOS工程Enable Bitcode 需要關閉再登,因為Flutter混合開發(fā)目前還不支持Bitcode
3、創(chuàng)建flutter module
FlutterMixDemo/BaseFramework/ (BaseFramework 是我的 iOS 工程項目)
進入在 FlutterMixDemo 目錄下付秕,終端執(zhí)行命令:
flutter create -t module flutter_module
flutter_module是自己起的名字兰珍,記得字母都要小寫,不然會報錯盹牧。
這里也有Flutter官方網(wǎng)站英文文檔 → iOS接入Flutter教程
4俩垃、添加以下代碼到Podfile:(沒有Podfile怎么辦?終端先cd到BaseFramework項目里汰寓,執(zhí)行pod init)
platform :ios, '9.0'
target 'BaseFramework' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
#需要添加的代碼 flutter_module是自己創(chuàng)建的名字
flutter_application_path = '../flutter_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
install_all_flutter_pods(flutter_application_path)
end
執(zhí)行pod install口柳,如果有報錯,根據(jù)錯誤提示一個個解決有滑,具體哪些報錯不懂的話就谷歌百度吧跃闹。。。
注意:當你在flutter_module/pubspec.yaml中有改變了Flutter插件的依賴關系時(不管有沒修改啥望艺,只要按了command+s保存后)苛秕,一定要在BaseFramework(自己的項目)里再次運行pod install。
5找默、在iOS應用里使用 FlutterViewController
創(chuàng)建FlutterEngine
AppDelegate.h
@import UIKit;
@import Flutter;
@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
AppDelegate.m
#import <FlutterPluginRegistrant/GeneratedPluginRegistrant.h> // Used to connect plugins.
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
// Runs the default Dart entrypoint with a default Flutter route.
[self.flutterEngine run];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
用FlutterEngine顯示一個FlutterViewController艇劫,簡單示例:在入口文件里創(chuàng)建一個button用來點擊彈出
ViewController.m
@import Flutter;
#import "AppDelegate.h"
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建一個button用來點擊彈出FlutterViewController
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:@selector(showFlutter)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"Show Flutter!" forState:UIControlStateNormal];
button.backgroundColor = UIColor.blueColor;
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)showFlutter {
FlutterEngine *flutterEngine =
((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
[self presentViewController:flutterViewController animated:YES completion:nil];
}
@end
當然也可以使用隱式FlutterEngine創(chuàng)建一個FlutterViewController。這里我用了個延遲0.5秒自動彈出FlutterViewController惩激,F(xiàn)lutterEngine創(chuàng)建也是需要時間店煞,如果FlutterEngine還沒創(chuàng)建好就彈出FlutterViewController會失敗。如果想一啟動app就立馬彈出Flutter风钻,就要考慮這個問題了顷蟀。
- (void)viewDidLoad {
[super viewDidLoad];
[self showFlutter2];
}
- (void)showFlutter2 {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
FlutterViewController *flutterViewController =
[[FlutterViewController alloc] initWithProject:nil nibName:nil bundle:nil];
flutterViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:flutterViewController animated:NO completion:nil];
});
}
FlutterAppDelegate可以實現(xiàn)如下功能,比如:
將應用程序回調(diào)(如openURL)轉發(fā)到插件(如local_auth)骡技。
轉發(fā)狀態(tài)欄點擊(只能在AppDelegate中檢測到)讓Flutter以實現(xiàn)滾動到頂部鸣个。
使用FlutterAppDelegate,建議使用UIApplicationDelegate子類FlutterAppDelegate布朦,但不是必需的囤萤。
如果你的AppDelegate不能直接使FlutterAppDelegate成為子類,那AppDelegate需要實現(xiàn)FlutterAppLifeCycleProvider協(xié)議是趴,以確保插件收到必要的回調(diào)阁将。否則,依賴于這些事件的插件可能會有未定義的行為右遭。代碼↓
代碼是從Flutter官網(wǎng)直接拷過來的,親測沒任何毛病缤削。
AppDelegate.h
@import Flutter;
@import UIKit;
@import FlutterPluginRegistrant;
@interface AppDelegate : UIResponder <UIApplicationDelegate, FlutterAppLifeCycleProvider>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end
AppDelegate.m
@interface AppDelegate ()
@property (nonatomic, strong) FlutterPluginAppLifeCycleDelegate* lifeCycleDelegate;
@end
@implementation AppDelegate
- (instancetype)init {
if (self = [super init]) {
_lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
}
return self;
}
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id>*))launchOptions {
self.flutterEngine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
[self.flutterEngine runWithEntrypoint:nil];
[GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions];
}
// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
if ([viewController isKindOfClass:[FlutterViewController class]]) {
return (FlutterViewController*)viewController;
}
return nil;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
[super touchesBegan:touches withEvent:event];
// Pass status bar taps to key window Flutter rootViewController.
if (self.rootFlutterViewController != nil) {
[self.rootFlutterViewController handleStatusBarTouches:event];
}
}
- (void)application:(UIApplication*)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
[_lifeCycleDelegate application:application
didRegisterUserNotificationSettings:notificationSettings];
}
- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
[_lifeCycleDelegate application:application
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication*)application
didReceiveRemoteNotification:(NSDictionary*)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[_lifeCycleDelegate application:application
didReceiveRemoteNotification:userInfo
fetchCompletionHandler:completionHandler];
}
- (BOOL)application:(UIApplication*)application
openURL:(NSURL*)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
return [_lifeCycleDelegate application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
return [_lifeCycleDelegate application:application handleOpenURL:url];
}
- (BOOL)application:(UIApplication*)application
openURL:(NSURL*)url
sourceApplication:(NSString*)sourceApplication
annotation:(id)annotation {
return [_lifeCycleDelegate application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
- (void)application:(UIApplication*)application
performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
completionHandler:(void (^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) {
[_lifeCycleDelegate application:application
performActionForShortcutItem:shortcutItem
completionHandler:completionHandler];
}
- (void)application:(UIApplication*)application
handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
completionHandler:(nonnull void (^)(void))completionHandler {
[_lifeCycleDelegate application:application
handleEventsForBackgroundURLSession:identifier
completionHandler:completionHandler];
}
- (void)application:(UIApplication*)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[_lifeCycleDelegate application:application performFetchWithCompletionHandler:completionHandler];
}
- (void)addApplicationLifeCycleDelegate:(NSObject<FlutterPlugin>*)delegate {
[_lifeCycleDelegate addDelegate:delegate];
}
@end
6窘哈、當你需要從彈出的Flutter界面返回iOS界面,需要在Flutter的文件里實現(xiàn)SystemNavigator.pop()這個方法亭敢。比如在Flutter里定義一個按鈕滚婉,實現(xiàn)其方法 ↓,注意:需要引入 services.dart
模塊才可以使用
import 'package:flutter/services.dart';
RaisedButton(
onPressed: (){
SystemNavigator.pop(animated: true);
},
child: Text('返回'),
),
注意:當你的根視圖控制器是UINavigationController時帅刀,SystemNavigator.pop()調(diào)用的是' popViewControllerAnimated: '让腹。如果是通過presentViewController:FlutterViewController,那么SystemNavigator.pop()調(diào)用的是' dismissViewControllerAnimated:completion: '扣溺。
Flutter里還有個exit(0)方法骇窍,是強制退出app,使用這個方法要先引入import 'dart:io'和上面的services.dart
;
7锥余、Dart里的入口函數(shù)默認是調(diào)用 main()腹纳,入口文件:``lib/main.dart
:
你也可以修改Dart的入口函數(shù)并在iOS里調(diào)用,例如:↓,就把入口函數(shù)修改為myOtherEntrypoint()嘲恍,
入口文件:lib/other_file.dart
[flutterEngine runWithEntrypoint:@"myOtherEntrypoint" libraryURI:@"other_file.dart"];
參考:
https://flutter.dev/docs/development/add-to-app/ios/project-setup
https://flutter.dev/docs/development/add-to-app/ios/add-flutter-screen
?