+1

Flutter - Add Flutter module to Native app

TLDR;

Bài hướng dẫn sau tập trung cho hai mục tiêu:

  • Trong trường hợp bạn có sẵn source code Android native (Java, Kotlit) và iOS (Objective-C, Swift) và mong muốn tiếp tục phát triển thêm tính năng mới bằng Flutter framework thay vì phải maintain và phát triển trên 2 source code khác nhau.
  • Trong trường hợp bạn muốn kếp hợp 2 ứng dụng với nhau, một được build bằng Native, hai được build bằng Flutter

Prepare

  • Đảm bảo bạn đã setup thành công môi trường dev cho Android, iOS và Flutter.
  • Môi trường phát triển của bạn phải đáp ứng các yêu cầu hệ thống macOS dành cho Flutter:
    • Có cài đặt Xcode, hỗ trợ iOS 11 trở lên.
    • Bạn sẽ cần CocoaPods phiên bản 1.10 trở lên.
  • Module organization
some/path/project_workspace
├── my_flutter/
│   └── .ios/
│   |   └── Flutter/
│   |     	└── podhelper.rb
|   └── .android/
|	|	└── Flutter
|	|	└── app
|	|	└── include_flutter.groovy	
|	└──	pubspec.yaml
└── iOSApp (com.example.app)/
|   └── Podfile
└── AndroidApp (com.example.app)/
    └── settings.gradle

Để có được cấu trúc trên, tại some/path/project_workspace tạo flutter module bằng cmd sau

flutter create -t module --org com.example my_flutter

Sau khi module được tạo, bạn mở file pubspec.yaml trong my_flutter và chỉnh sửa bundle id cho native app

 module:
    androidX: true
    androidPackage: com.example.app
    iosBundleIdentifier: com.example.app

Setup Android project

Notes
  • Ứng dụng Android của bạn có thể hỗ trợ các kiến trúc như mips hoặc x86. Flutter hiện chỉ hỗ trợ xây dựng các thư viện cho x86_64, armeabi-v7aarm64-v8a. Chỉnh sửa file AndroidApp/app/build.gradle
android {
  //...
  defaultConfig {
    ndk {
      // Filter for architectures supported by Flutter.
      abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
    }
  }
}
  • Up to dated các dependencies trước khi thực hiện việc thêm Flutter module

Add the Flutter module as a dependency

  • Thêm Flutter module như là một subproject trong AndroidApp/settings.gradle.
// Include the host app project.
include ':app'                                    // assumed existing content
setBinding(new Binding([gradle: this]))                                // new
evaluate(new File(                                                     // new
    settingsDir.parentFile,                                            // new
    'my_flutter/.android/include_flutter.groovy'                   		// new
))                                                                     // new
  • Thêm Flutter module dependency vào AndroidApp/app/build.gradlesync lại project
dependencies {
    implementation project(':flutter')
}

Add a Flutter screen to an Android app

  • Thêm FlutterActivity vào AndroidManifest.xml
<activity
  android:name="io.flutter.embedding.android.FlutterActivity" />
  • Gọi mở Flutter module từ native
startActivity(
	FlutterActivity
        .withNewEngine()
        .build(currentActivity)
);

Setup iOS project

Add the Flutter module as a dependency with CocoaPods

Nếu iOSApp chưa có Podfile, chạy cmd pod init ở thử mục iOSApp để tạo.

1. Thêm các dòng sau vào của bạn iOSApp/Podfile:

platform :ios, '11.0'

flutter_application_path = '../my_flutter'							# new
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')			# new

2. Gọi install_all_flutter_pods(flutter_application_path) trong mỗi target

target 'MyApp' do
  install_all_flutter_pods(flutter_application_path)
end

3. Gọi flutter_post_install(installer) trong Podfile’s post_install

post_install do |installer|
  flutter_post_install(installer) if defined?(flutter_post_install)
end

4. Run pod install.

Add a Flutter screen to an iOS app

  • Trong AppDelegate.swift khai báo FlutterEngine
import UIKit
import Flutter		//new
// The following library connects plugins with iOS platform code to this app.
import FlutterPluginRegistrant		//new

@UIApplicationMain
class AppDelegate: UIApplicationDelegate {
  lazy var flutterEngine = FlutterEngine(name: "my_flutter_engine") 		//new

  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Runs the default Dart entrypoint with a default Flutter route.
    flutterEngine.run();		//new
    // Connects plugins with iOS platform code to this app.
    GeneratedPluginRegistrant.register(with: self.flutterEngine);		//new
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions);
  }
}
  • Hiển thị FlutterViewController với FlutterEngine vừa tạo ở trên
let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
present(flutterViewController, animated: true, completion: nil)

Done, vậy là một cách cơ bản nhất, bạn đã có thể gọi mở Flutter module từ Native app. Mặc định sẽ gọi hàm main trong main.dart của Flutter module Nếu bạn muốn truyền thêm arguments từ native sang flutter hoặc bạn mong muốn đổi hàm mặc định, file mặc định mà Native sẽ gọi sang Flutter, bạn tham khảo thêm các sử dụng FlutterEngine.

Cám ơn và chúc các bạn thành công!

Tham khảo


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.