Flutter

Flutter——iOS项目混合flutter界面

2021-07-02  本文已影响0人  Lucky_Blue

1.创建flutter module

image.png

方式一

cd ~/Desktop/Flutter
flutter create --template module video_flutter

方式二


Android Studio

注意⚠️创建的module最好和iOS原生的项目在同一个层级的文件目录,因为iOS项目需要引用Flutter项目中的文件和库。

2.编写flutter代码

@pragma('vm:entry-point')
void main() {
  runApp(MainApp());
}

@pragma('vm:entry-point')
void channel() {
  runApp(ChannelApp());
}

@pragma('vm:entry-point')
void mine() {
  runApp(MineApp());
}
image.png
1.首页定义了三个函数main,channelmine, 他们分别加载了MainApp(),ChannelApp()MineApp(),也可以直接理解为三个模块,他们是相互独立的。
2.由于main()函数是提供给Flutter Engine层调用,Dart中没有地方引用,预处理命令@pragma('vm:entry-point')是为了告诉编译器不要去除这个未引用的方法。

2.main_page.dart代码

由于其他两个模块代码也是类似的,就以main_page.dart为例。

import 'package:flutter/material.dart';

class MainApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "首页模块",
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MainPageState();
  }
}

class MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Scrollbar(
          child: GridView(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 10,
              childAspectRatio: 6 / 3,
            ),
            children: List.generate(100, (index) {
              return getItem(index);
            }),
          ),
        ),
      ),
    );
  }
}

/// 获取子项目
Widget getItem(int index) {
  return Container(
    decoration: BoxDecoration(color: Colors.red),
  );
}

可以看到跟普通的Flutter project 的代码没有任何差别。

3.iOS项目引入Flutter模块

首先打开iOS项目找到Podfile文件,如果没有的话就新建一个。

#1. 找到flutter module 的目录
flutter_application_path = '../video_flutter'
#2. 找到flutter module 的目录中的/.ios/Flutter/podhelper.rb文件
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'Video_iOS' do
  use_frameworks!
#3. 执行podhelper.rb中的install_all_flutter_pods方法
    install_all_flutter_pods(flutter_application_path)
end

flutter_application_pathflutter项目的路径。
执行pod install命令将Flutter SDKFlutter 代码 引入到iOS项目中。
AppDelegate创建一个FlutterEngineGroup用来管理多个FlutterEngine, 让他们共享资源等功能。

import UIKit
import Flutter
import FlutterPluginRegistrant

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var engineGroup = FlutterEngineGroup(name: "video_flutter", project: nil)

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // 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.
    }
}

创建一个继承于FlutterViewController的子类,子类会根据传过来的entrypoint初始化一个FlutterEngine,这个FlutterEngine的加载入口是main.dart文件中entrypoint函数,然后FlutterViewController子类持有这个FlutterEngine

import Flutter

class JHFlutterViewController : FlutterViewController{
    init(withEntrypoint entrypoint : String?) {
        let appDelegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
        let newEngine = appDelegate.engineGroup.makeEngine(withEntrypoint: entrypoint, libraryURI: nil)
        super.init(engine: newEngine, nibName: nil, bundle: nil)
    }
    required convenience init(coder aDecoder: NSCoder) {
        self.init(withEntrypoint : nil)
    }
}

接下来是UIViewController加载JHFlutterViewController

import UIKit

class MainViewController: UIViewController {
// 1. 懒加载 main.dart 中的main入口函数对应的Flutter App
    private lazy var subFlutterVC : JHFlutterViewController = JHFlutterViewController(withEntrypoint: nil)
    
    override func viewDidLoad() {
// 2. 添加FlutterViewController
        addChild(subFlutterVC)
        let safeFrame = self.view.safeAreaLayoutGuide.layoutFrame
        subFlutterVC.view.frame = safeFrame;
        self.view.addSubview(subFlutterVC.view)
        subFlutterVC.didMove(toParent: self)
    }
}

到现在三个Flutter module已经被集成到了我们的iOS项目中了。如果在Flutter module中用了插件来实现的,我们需要把插件统一注册到Flutter Engine中,在JHFlutterViewController子类中修改如下

import Flutter
import FlutterPluginRegistrant

class JHFlutterViewController : FlutterViewController{
    init(withEntrypoint entrypoint : String?) {
        let appDelegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
        let newEngine = appDelegate.engineGroup.makeEngine(withEntrypoint: entrypoint, libraryURI: nil)
        super.init(engine: newEngine, nibName: nil, bundle: nil)
    }
    required convenience init(coder aDecoder: NSCoder) {
        self.init(withEntrypoint : nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        GeneratedPluginRegistrant.register(with: self.pluginRegistry())
    }
}
上一篇下一篇

猜你喜欢

热点阅读