在Flutter 开发中混合的形式主要有两种

  • 作为独立的页面 进行维护
  • 可以相互嵌套

flutter3 和android原生混合开发 flutter和java混合开发_Flutter 混合开发

 

flutter3 和android原生混合开发 flutter和java混合开发_ios_02

 原生集成 Flutte 混合开发的步骤

  1. 创建 Flutter module
  2. 添加 Flutter module 依赖(为原生项目添加 Flutter 依赖)
  3. 在 Java/Object-c 中调用 Flutter module
  4. 编写 Dart 代码

➠ 运行项目

➠ 热重启 / 热加载

➠ 调试代码

➠ 发布应用

Android:

1. 创建 Flutter module 

首先你得有 原生 android 工程; 路径如下:D:\MineGit\flutter_trip\native_peoject

flutter3 和android原生混合开发 flutter和java混合开发_android_03

首先切换到 原生工程的上一级目录;并且 创建一个flutter模块

C:\Users\user>D: C:\Users\user>cd D:\MineGit\flutter_trip\native_peoject D:\MineGit\flutter_trip\native_peoject>cd.. D:\MineGit\flutter_trip>flutter create -t module flutter_module_john

flutter3 和android原生混合开发 flutter和java混合开发_ios_04

模块就建好了:

flutter3 和android原生混合开发 flutter和java混合开发_flutter_05

文件结构如下

flutter3 和android原生混合开发 flutter和java混合开发_ios_06

 上面就是 flutter_module_john 模块中的文件结构; 你会发现它里面包含 .android 与 .ios,这两个文件夹是 隐藏文件夹(mac 中你必须打开隐藏开关 才能看到文件夹),也是 flutter_module_john 宿主工程

  • .android            -> flutter_module_john模块  的Android 宿主工程
  • .ios                    -> flutter_module_john模块 的 IOS 宿主工程
  • lib                      -> flutter_module_john模块 的 Dart 部分的代码
  • pubspec.yaml   -> flutter_module_john模块 项目依赖配置文件

因为宿主工程的存在, 我们这个 flutter_module 在补额外配置的情况下是 可以独立运行 的, 通过安装了 Flutter 与 Dart 插件的 AndroidStudio 打开这个 Flutter_module 项目,通过运行按钮就能直接运行它


flutter3 和android原生混合开发 flutter和java混合开发_flutter_07

能顺利运行到手机上面 就说明这个模块 创建的没问题


2. 添加 Flutter module 依赖

这里我们将 刚刚创建的 Flutter_module 加入到 Android 原生工程中:

1. settings.gradle 首先我们修改项目

setBinding(new Binding([gradle:this])) evaluate(new File( settingsDir.parentFile, 'flutter_module_john/.android/include_flutter.groovy' ))

就是把 flutter_module 模块添加到 项目中;注意项目路径的写法;得写成你自己的路径;

下面截图中的两行 是编辑器自己给我添加的 可以移除

flutter3 和android原生混合开发 flutter和java混合开发_flutter_08

 检查下 minSdkVersion 版本最低 16(flutter 支持的最低版本)

flutter3 和android原生混合开发 flutter和java混合开发_android_09


2.  build.gradle (app)

添加工程依赖

flutter3 和android原生混合开发 flutter和java混合开发_ios_10

3. 在 Java 中调用 Flutter module

在 Java 中调用 Flutter 模块的两种方式:

  1. 使用 Flutter.createView  API 方式创建 (作为页面的一部分) Flutter.createView() 已经被官方弃用 Flutter 1.12版本废弃了io.flutter.facade包导致的;这里使用 FlutterFragment 来创建 FlutterFragment.createDefault();

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.test).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //没有指定路由 传值;只能调到 默认路由(开始界面) // FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); // fragmentTransaction.add(R.id.someContainer, FlutterFragment.createDefault()); // //fragmentTransaction.replace(R.id.someContainer, FlutterFragment.createDefault()); // fragmentTransaction.commit(); //指定路由并且传值 FlutterFragment flutterFragment = FlutterFragment.withNewEngine() .initialRoute("{name:'devio',dataList:['aa','bb','bb']}") .build(); getSupportFragmentManager() .beginTransaction() .replace(R.id.someContainer, flutterFragment) .commit(); } }); } }

原生传值可以直接 接收到参数:

import 'dart:ui' as ui;

final String initParams = ui.window.defaultRouteName;

 

flutter3 和android原生混合开发 flutter和java混合开发_android_11

       编辑的时候:编辑原生原生代码只能修改原生的代码;编辑dart 代码; Flutter_module lib 文件夹里面的代码;直接运行 Flutter_module;只能运行 Flutter_module里面的工程;


4. 热重启 /重启加载

大家知道我们在做 Flutter 开发的时候,它自带热 重启/重新加载的功能, 但是你可以能会发现;在混合开发中 Android 项目集成 Flutter 项目的时候 重启/重新加载不起作用了;那在混合开发中怎么启用 重启/重新加载:

  1. 手机连接我们的 电脑
  2. 关闭我们的应用;然后 运行 flutter attach;(在对应的 flutter_module 项目根路径)
  3. 当出现 “Waiting for a connection from Flutter on PACM00... 的时候打开我们原生App;并且进入我们的 Flutter 界面

然后会提示同步信息和 命令信息

D:\MineGit\flutter_trip\flutter_module_john>flutter attach Multiple devices found: SM G9650 (mobile) • 21a9f15c1d037ece • android-arm64 • Android 10 (API 29) PACM00 (mobile) • JZU8PB9DQOG68D6D • android-arm64 • Android 10 (API 29) [1]: SM G9650 (21a9f15c1d037ece) [2]: PACM00 (JZU8PB9DQOG68D6D) Please choose one (To quit, press "q/Q"): 2 Waiting for a connection from Flutter on PACM00... Syncing files to device PACM00... 7.4s Flutter run key commands. r Hot reload. R Hot restart. h Repeat this help message. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). Running with sound null safety

 现在你只要 修改完毕 dart 代码保存;然后在 按 r 键就能立马看到效果了

flutter3 和android原生混合开发 flutter和java混合开发_android_12

flutter3 和android原生混合开发 flutter和java混合开发_flutter_13

5. 调试 dart 代码

在混合开发模式下, 如何更好的调试我们的代码:

  1. 关闭App(这一步很关键)
  2. 点击 AndroidStudio 的 Flutter Attch 按钮(前提是 安装过flutter 与 dart 插件)
  3. 启动App

打上断点  就能进入 对应的断点 了

flutter3 和android原生混合开发 flutter和java混合开发_ios_14


6. 发布应用 配置好证书

signingConfigs {//添加
        release {
            storeFile file(MYAPP_RELEASE_KEY_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release//添加
        }
    }

直接运行命令:

>gradlew assembleRelease

或者:

flutter3 和android原生混合开发 flutter和java混合开发_android_15

打出来的APK 有:

flutter3 和android原生混合开发 flutter和java混合开发_flutter_16

 在这里可以设置:armeabi-v7a

  指定 APK 只支持32位 类型 减小包体

flutter3 和android原生混合开发 flutter和java混合开发_flutter_17

flutter3 和android原生混合开发 flutter和java混合开发_flutter_18

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.john.nativetoflutter"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        ndk {
            abiFilters 'armeabi-v7a'
//            abiFilters "armeabi", "armeabi-v7a", "x86_64", "x86"
        }
    }
    signingConfigs {//添加
        release {
            storeFile file(MYAPP_RELEASE_KEY_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release//添加
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation project(':flutter')
}

IOS: 原生嵌入 Flutter

  1. 首先你得有原生工程
  2. 你的 Mac 正确配置 Flutter 所需要的环境tt
  3. 你得有 Flutter_Module 工程;我是直接使用上面 android 功能已经创建好的;
  4. 因为 Flutter 有依赖  pod 管理插件;

Pod:  Podfile

# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'

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

target 'native_project_ios' do
  # Comment the next line if you don't want to use dynamic frameworks
  

  install_all_flutter_pods(flutter_application_path)

  # Pods for native_project_ios

  target 'native_project_iosTests' do
    inherit! :search_paths
    # Pods for testingå
  end

  target 'native_project_iosUITests' do
    # Pods for testing
  end

end

flutter3 和android原生混合开发 flutter和java混合开发_flutter_19

flutter3 和android原生混合开发 flutter和java混合开发_Flutter 混合开发_20

 Flutter Module 里面的 .ios  和 .android 是一个隐藏文件夹; mac 上面想要看见隐藏文件夹;shift + commond+ .

这里自己 根据自己的目录进行配置就可以了;然后写一个按钮 实现跳转 传值:

#import <Flutter/Flutter.h>
///

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    UIButton *button =[UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self action:@selector(handleButtonAction) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Flutter " forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor redColor]];
    button.frame = CGRectMake(80, 210, 160, 40);
    [self.view addSubview:button];
}
- (void)handleButtonAction{
    FlutterViewController *flutterviewController =[FlutterViewController new];
    [flutterviewController setInitialRoute:@"{name:'devio',dataList:['aa','bb','bb']}"];
    
    [self presentViewController:flutterviewController animated:true completion:nil];
}

flutter3 和android原生混合开发 flutter和java混合开发_android_21

flutter3 和android原生混合开发 flutter和java混合开发_Flutter 混合开发_22