项目地址: https://github.com/tianzhilan0/OCFlutter
注:项目比较大600多兆

最终效果图如下

m0007-1fvip.gif

1、创建OC项目

image.png
image.png

2、添加cocoapods

cd /Users/lc/Desktop/Test/OCFlutter 
pod init
pod install

image.png

3、创建Flutter 工程

在OCFlutter项目的相同路径上创建module
cd /Users/lc/Desktop/Test
flutter create -t module flutter_module

image.png

4、在OCFlutter项目新建Config目录,在这个目录下新建3个配置文件

  • Flutter.xccofig,内容如下:
#include "../flutter_module/.ios/Flutter/Generated.xcconfig"
ENABLE_BITCODE=NO
  • Debug.xccofig,内容如下:
#include "Flutter.xcconfig"
#include "Pods/Target Support Files/Pods-iOS项目名称/Pods-iOS项目名称.debug.xcconfig"
  • Release.xccofig,内容如下:
#include "Flutter.xcconfig"
#include "Pods/Target Support Files/Pods-iOS项目名称/Pods-iOS项目名称.debug.xcconfig"
FLUTTER_BUILD_MODE=release

image.png
image.png

image.png

image.png

5、修改OCFlutter配置

  • 关闭Bitcode

image.png

  • 修改运行环境

image.png

  • 添加Run Script
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

image.png
image.png

  • 修改Podfile内容,添加如下内容,添加完成之后再执行一次pod install
flutter_application_path = '../flutter_module'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

image.png
image.png

6、运行一下flutter_module,生成一些文件,运行成功之后,关闭就行

image.png

7、在OCFlutter项目下添加Flutter目录

  • command+shift+。显示隐藏文件

image.png

  • 在Flutter文件下添加flutter_assets

将此处的flutter_assets拷贝至Flutter目录下,导入到项目
image.png
image.png

  • 在Flutter文件下添加App.framework

将此处的App.framework拷贝至Flutter目录下,导入到项目
image.png
image.png

  • 在Flutter文件下添加engine

将此处的engine拷贝至Flutter目录下,导入到项目
image.png
image.png

  • 最终显示如下样式

image.png

在此处编译一下OCFlutter项目,如不报错,则已准备完成,接下来就是撸代码了。

8、撸代码

  • 修改AppDelegate.h代码
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>


@interface AppDelegate : FlutterAppDelegate <UIApplicationDelegate, FlutterAppLifeCycleProvider>

@property (strong, nonatomic) UIWindow *window;


@end
  • 修改AppDelegate.m代码

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate
{
    FlutterPluginAppLifeCycleDelegate *_lifeCycleDelegate;
}

- (instancetype)init {
    if (self = [super init]) {
        _lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
    }
    return self;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions];
}

- (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];
}

#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options  API_AVAILABLE(ios(13.0)){
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}

- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions  API_AVAILABLE(ios(13.0)){
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

@end

  • ViewController.m中代码如下

#import "ViewController.h"
#import <Flutter/FlutterViewController.h>
#import "LoginViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (IBAction)jumpToFlutter:(id)sender {
    FlutterViewController* flutterViewController = [[FlutterViewController alloc]init];
    [flutterViewController setInitialRoute:@"pag1"];
    
    FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"com.pages.your/native_get" binaryMessenger:(NSObject<FlutterBinaryMessenger> *)flutterViewController];
    [channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        NSString *method = [call method];
        if ([method isEqualToString:@"FlutterPopIOS"]) {
            NSLog(@"FlutterPopIOS:获取Flutter返回时传的值 == %@",[call arguments]);
            [self.navigationController popViewControllerAnimated:true];
        }
        if ([method isEqualToString:@"FlutterCickedActionPushIOSNewVC"]) {
            NSLog(@"FlutterCickedActionPushIOSNewVC:返回来传的参数是 == %@",[call arguments]);
            LoginViewController *loginCV = [[LoginViewController alloc] init];
            [self.navigationController pushViewController:loginCV animated:true];
        }
        if ([method isEqualToString:@"FlutterGetIOSArguments"]) {
            NSDictionary *dic = @{@"name":@"名字"};
            result(dic);
        }
        
    }];
    [self.navigationController pushViewController:flutterViewController animated:YES];
}

@end

  • flutter_modulemain.dart代码如下
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 创建一个给native的channel (类似iOS的通知)
  static const methodChannel = const MethodChannel('com.pages.your/native_get');

  String _textString = "null";

  void _backAction() {
    _iOSPushToVC();
  }

  _iOSPushToVC() async {
    await methodChannel.invokeMethod('FlutterPopIOS', '我是返回数据');
  }

  void _pushIOSNewVC() async {
    Map<String, dynamic> map = {
      "code": "200",
      "data": [1, 2, 3]
    };

    await methodChannel.invokeMethod('FlutterCickedActionPushIOSNewVC', map);
  }

  // 给客户端发送一些东东 , 并且拿到一些东东
  Future<Null> _flutterGetIOSArguments(para) async {
    dynamic result;
    try {
      result = await methodChannel.invokeMethod('FlutterGetIOSArguments', para);
      _textString = result["name"];
    } on PlatformException {
      result = 100000;
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              onPressed: _backAction,
              child: Text("返回原生"),
            ),
            RaisedButton(
              onPressed: _pushIOSNewVC,
              child: Text("跳转进入一个新的原生页面"),
            ),
            RaisedButton(
              onPressed: () {
                _flutterGetIOSArguments("flutter传值");
              },
              child: Text("从原生页面获取数据"),
            ),
            Text("从原生获取的内容:$_textString"),
          ],
        ),
      ),
    );
  }
}

Logo

智屏生态联盟致力于大屏生态发展,利用大屏快应用技术降低开发者开发、发布大屏应用门槛

更多推荐