Most companies now have projects that they have been developing for many years, and it’s not possible to just use the Flutter to develop a suite from scratch, that doesn’t work, unless it’s a small project, so you have to use the Flutter to develop new business or to restructure old business, and that’s where the hybrid development of the Flutter is

1. Create the Flutter module

With hybrid development, you can’t just go ahead and create a Flutter project as before, but instead use the Flutter template

#Flutter_module_lxf can be named whatever you want
flutter create --template module flutter_module_lxf

#--template can be replaced with -t
# flutter create -t module flutter_module_lxf
Copy the code

The created Flutter module will still open and run just as the previously created Flutter project.

There are also ios and Android directories under the directory, but in front of a dot, as a point directory.

Second, the iOS

integration

Through Cocoapods, you can compile the Flutter module into a library that can be introduced and used in native projects

Add two lines of configuration to your Podfile

# Specifies the path of the Flutter module we just created
flutter_application_path = '.. /flutter_module_lxf'

# joining together the path of the script file: ios/Flutter/podhelper rb
load File.join(flutter_application_path, '.ios'.'Flutter'.'podhelper.rb')
Copy the code

Under each Target that needs to reference the Flutter, a configuration line needs to be added

install_all_flutter_pods(flutter_application_path)
Copy the code

After the addition, it looks like the following:

flutter_application_path = '.. /flutter_module_lxf'
load File.join(flutter_application_path, '.ios'.'Flutter'.'podhelper.rb')

use_frameworks!
target 'LXFFlutterHybridDemo' do
  
  install_all_flutter_pods(flutter_application_path)
  
end
Copy the code

After the addition is complete, execute pod Install once

use

Two steps

  1. Get the Flutter engineFlutterEngine
  2. throughFlutterEnginecreateFlutterViewController

The basic use

A declaration in the AppDelegate class FlutterEngine variables, start Flutter engine in didFinishLaunchingWithOptions method

// AppDelegate.swift

import Flutter

@UIApplicationMain
class AppDelegate: UIResponder.UIApplicationDelegate {
  
    // Create the Flutter engine
    lazy var flutterEngine = FlutterEngine(name: "lxf")

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Start the Flutter engine
        flutterEngine.run()
        
        return true}... }Copy the code

Add a button to the ViewController and click to pop up the Flutter module

// ViewController.swift

override func viewDidLoad(a) {
  super.viewDidLoad()

  let btn = UIButton(type: .custom)
  btn.frame = CGRect(x: 100, y: 200, width: 200, height: 44)
  btn.backgroundColor = .black
  btn.addTarget(self, action: #selector(showFlutterVc), for: .touchUpInside)
  btn.setTitle("Ejecting Flutter module".for: .normal)
  self.view.addSubview(btn)
}

@objc func showFlutterVc(a) {
  / / create FlutterViewController
  let flutterVc = FlutterViewController(engine: fetchFlutterEngine(), nibName: nil, bundle: nil)
  self.present(flutterVc, animated: true, completion: nil)}func fetchFlutterEngine(a) -> FlutterEngine {
  return (UIApplication.shared.delegate as! AppDelegate).flutterEngine
}
Copy the code

Error: Command PhaseScriptExecution failed with a nonzero exit code

Please open the Flutter module project using Android Studio or VSCode and run it on an iOS device to help us do some initial configuration for the iOS project. After running the Flutter module successfully, you can close the project and then open the native project in Xcode.

Modifying an initial Route

The official documentation mentions that the initial route needs to be modified by calling setInitialRoute via invokeMethod before the Flutter engine runs. The code is as follows

// Modify the initial route
flutterEngine.navigationChannel.invokeMethod("setInitialRoute", arguments: "/other")
// Start the Flutter engine
flutterEngine.run()
Copy the code

However, I found that writing this did not work, and it was also mentioned in the official issue of Flutter: SetInitialRoute is broken for iOS Add-to-App #59895

Temporary can be used as follows:

let flutterVc = FlutterViewController(project: FlutterDartProject(), nibName: nil, bundle: nil)
flutterVc.setInitialRoute("/other")
self.present(flutterVc, animated: true, completion: nil)
Copy the code

Although writing this way can achieve this, there is a noticeable lag, because using this method to create a FlutterViewController implicitly creates and starts a FlutterEngine, When we pop up FlutterViewController, FlutterEngine is not loaded yet, so we will see a transparent interface pop up first, and then the interface view corresponding to the /other route is displayed.

Using FlutterAppDelegate

Using the FlutterAppDelegate is not required, but is recommended if you want the Flutter module to use the native functionality as well

Native function

  • To deal withopenURLThe callback
  • The list view rolls to the top after clicking on the status bar
class AppDelegate: FlutterAppDelegate 
Copy the code

For more detailed use, please read the official documentation

Third, the Android

Modify the Settings. Gradle file in the android project root directory

// settings.gradle

include ':app'                                    // assumed existing content
setBinding(new Binding([gradle: this]))                                // new
evaluate(new File(                                                     // new
  settingsDir.parentFile,                                              // new
  // Here's flutter_module_lxf please change the directory name of the Flutter template you created for yourself
  'flutter_module_lxf/.android/include_flutter.groovy'                 // new
))  
Copy the code

Modify the build.gradle file in the Android project app directory

// app/build.gradle

dependencies {
  ...
  // Configure the flutter dependency
  implementation project(':flutter')}Copy the code

If the following error is encountered during compilation

Default interface methods are only supported starting with Android N (--min-api 24): void androidx.lifecycle.DefaultLifecycleObserver.onCreate(androidx.lifecycle.LifecycleOwner)
Copy the code

Please confirm whether Java 8 is specified for compilation.

Modify the build.gradle file in the Android project app directory

// app/build.gradle

android {
	...
  compileOptions {
      sourceCompatibility 1.8 targetCompatibility 1.8}... }Copy the code

Modify the app/SRC/main/AndroidManifest. XML file

// app/src/main/AndroidManifest.xml

<activity
  android:name="io.flutter.embedding.android.FlutterActivity"
  android:theme="@style/AppTheme"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize"
  />
Copy the code

Add a button and click to pop up the Flutter module

<! -- activity_main.xml -->

<Button
    android:id="@+id/btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="20sp"
    android:text="Ejecting Flutter module"
    android:background="# 000000"
    android:textColor="#ffffff"
    android:gravity="center"
    android:onClick="btnClick"
    />
Copy the code
// MainActivity.java

public void btnClick(View v) {
    startActivity(
        FlutterActivity.createDefaultIntent(this)); }Copy the code

Four, debugging and hot overload

Since we are currently running the project using a native development tool (e.g. Xcode), every time we modify the code of our Flutter module, we need to rerunning it to see the effect, unlike before when we could hot reload by pressing Cmd + S. The development of the Flutter module is extremely inefficient. Is there a way to hot-load the module like we did with the Flutter project? And the answer is yes

The Flutter official provides the Flutter Attach to help us develop and execute it on the terminal

flutter attach
Copy the code

If there are multiple devices, we will be prompted to specify which device to attach

Add the specified parameters as required

flutter attach -d FE305309-9E79-418D-BA3F-7EFECF2980BC
Copy the code

After you make any changes to the interface in the Dart file, press R for hot reload and r for hot launch.

If you are using Android Studio, you can directly select the device, click the Flutter Attach button on the right, and press Cmd + S to hot-reload as before.

Five, the data

  • GitHub

    LXFFlutterHybridDemo

  • The official documentation

    add-to-app | add-to-app/ios | add-to-app/android | Debugging & hot reload