“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Native embedded Flutter-Flutter Module

If you want the Flutter code to be embedded native, you should create an official Flutter Module by doing so

cd some/path/
flutter create --template module my_flutter
Copy the code

If you look at the current directory structure command+ shift+. Display hidden files, you can see that there are also.android files and.ios files. This is mainly for debugging purposes, it is not recommended to add any code to these two files. Since this is embedded in the native, any changes made in the.android and.ios files will not be packaged into the native project.

The main code is still in main.dart

Integrate the Flutter Module with iOS

Next we create an empty iOS project that follows the current examplemy_flutterIn the same directory, as shown belowI use theCocoaPodsTo integrate in the iOS projectMyFlutterIn thepod initTo open thePodfileFile,PodfileAdd the following code to the

flutter_application_path = '.. /my_flutter'
load File.join(flutter_application_path, '.ios'.'Flutter'.'podhelper.rb')
target 'MyApp' do
  install_all_flutter_pods(flutter_application_path)
end

Copy the code

Then run Pod Install, open the iOS project and try **import Flutter**. If this works, it indicates that the Flutter code has been added to the original project.

private let flutterVc = FlutterViewController(a)@objc
private func tap1(a) {
   self.present(flutterVc, animated: true, completion: nil)}Copy the code

Note: if we look at the memory now, we can see that when the Flutter code is invoked, the memory will go from 30MB to 100+MB and I dismiss the current FlutterVC. The memory will remain in memory as soon as the Flutter is loaded.

Products-> MyFlutter->Show in Finder-> Display package contents ->Frameworks

What you can see most is the content of the Flutter rendering engine and some resource content.

setRouterouting

This is now deprecated, but we can still experiment with it:

- (void)setInitialRoute:(NSString*)route
    FLUTTER_DEPRECATED("Use FlutterViewController initializer to specify initial route");
Copy the code

In the iOS native project, create another button and click the different one to jump to different Flutter pages

    @objc
    private func tap1(a) {
      let flutterVc = FlutterViewController()
       flutterVc.setInitialRoute("one")
       self.present(flutterVc, animated: true, completion: nil)}@objc
    private func tap2(a) {
      let flutterVc = FlutterViewController()
      flutterVc.setInitialRoute("two")
      self.present(flutterVc, animated: true, completion: nil)}Copy the code

How is this implemented in Flutter? Window. defaultRouteName is the value passed in from the native

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(MyApp(
      pageIndex: window.defaultRouteName,
    ));

class MyApp extends StatelessWidget {
  final String pageIndex;
  const MyApp({Key? key, required this.pageIndex}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo', home: Scaffold( appBar: AppBar(title: Text(pageIndex)), body: Center(child: Text(pageIndex)), ), ); }}Copy the code

Command + Shift + k clear iOS cache and retry. Ok ~

ChannelThree ways to define it

Flutter defines three different channels

  1. MethodChannel: Passes a method call, a communication
  2. BasicMessageChannel: Continuous communication, can reply to messages after receiving them
  3. EventChannel: Data flow, continuous communication

MethodChannel

We can also use a MethodChannel to communicate with invokeMapMethod <==> setMethodCallHandler in flutter:

onPressed: () {
  / / communications
  const MethodChannel('one').invokeMapMethod('exit');
},
Copy the code

The corresponding callback in Swift, so click the middle button to dismiss.

    @objc
    private func tap1(a) {
        let methodChannel = FlutterMethodChannel(name: "one", binaryMessenger: self.flutterVc as! FlutterBinaryMessenger)
        methodChannel.setMethodCallHandler { call, result in
            if call.method = = "exit"{
                self.dismiss(animated: true, completion: nil)}}self.present(flutterVc, animated: true, completion: nil)}Copy the code

BasicMessageChannel

Using BasicMessageChannel is basically the same as above, but since we’re talking about continuous communication, use TextField to verify: send <==> setMethodCallHandler

  BasicMessageChannel _channel =
      const BasicMessageChannel('messageChannel', StandardMessageCodec());
// ...
 	TextField(
    onChanged: (String str) {
       _channel.send(str);
    },
    
@override
  void initState() {
    // TODO: implement initState
    super.initState();
    _channel.setMessageHandler((message) {
      print('Received from iOS$message');
      return Future(() {});
    });
  }
Copy the code
    override func viewDidLoad(a) {
        super.viewDidLoad()
        messageChannel = FlutterBasicMessageChannel(name: "messageChannel", binaryMessenger: self.flutterVc.binaryMessenger)
        messageChannel.setMessageHandler { data, reply in
            print("Received the data on Flutter\(String(describing: data))")}}override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?). {
        a + = 1;
        self.messageChannel.sendMessage("\(a)")}Copy the code