flutter集成到Android混合开发

#场景#

把一个fluter页面运行到原生App中

#实现步骤#

1:配置

复制代码
#创建Flutter模块
flutter create -t module flutter_moule

#Android的settings.gradle的配置#

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)  ##修改
    repositories {
        google()
        mavenCentral()
        maven { url "https://storage.googleapis.com/download.flutter.io" } ##新增的
    }
}

include ':app'
setBinding(new Binding([gradle: this]))    ##新增的
evaluate(new File(settingsDir.parentFile,'flutter_module/.android/include_flutter.groovy'))  ##新增的
#Android的app里的build.gradle配置#
dependencies {

    implementation libs.appcompat
    implementation libs.material
    implementation libs.activity
    implementation libs.constraintlayout
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
    implementation project(':flutter') ##新增的
}

2:编写代码

注意 flutter工程和Android在一个目录下

两种方案:方案 1 最简(推荐,改启动页为 FlutterActivity)、方案 2 原生 Activity 内嵌 FlutterFragment

方案 1:直接把 APP 启动页设为 FlutterActivity【一行搞定,首选】

1、AndroidManifest.xml 修改启动入口

找到原来的启动 Activity,删掉 LAUNCHER 配置,把启动给到 FlutterActivity

xml

复制代码
<application ...>

    <!-- 原生Activity去掉 android.intent.category.LAUNCHER -->
    <activity android:name=".MainActivity">
    </activity>

    <!-- FlutterActivity 设为APP首页,开机直接进Flutter -->
    <activity
        android:name="io.flutter.embedding.android.FlutterActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <!-- 固定初始路由 -->
        <meta-data
            android:name="io.flutter.embedding.android.FLUTTER_INITIAL_ROUTE"
            android:value="/home"/>
    </activity>

</application>

android:value="/home" = Dart 接收的初始路由地址

2、Flutter Module main.dart 接收路由

dart

复制代码
import 'package:flutter/material.dart';
import 'dart:ui';

void main() {
  final String initRoute = PlatformDispatcher.instance.defaultRouteName;
  runApp(MyApp(initRoute));
}

class MyApp extends StatelessWidget {
  final String initRoute;
  const MyApp(this.initRoute, {super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: initRoute,
      routes: {
        '/': (ctx) => const HomePage(),
        '/home': (ctx) => const MainFlutterPage()
      },
    );
  }
}

运行 App → 打开直接就是 Flutter 页面

方案 2:保留原生 MainActivity,onCreate 直接加载 FlutterFragment(原生壳 + Flutter 内容)

1. activity_main.xml 全屏容器

xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_flutter_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

2. MainActivity.java(启动自动加载 Flutter)

java

运行

复制代码
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import io.flutter.embedding.android.FlutterFragment;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 新建引擎,指定初始路由
        FlutterFragment fragment = FlutterFragment.withNewEngine()
                .initialRoute("/home")
                .build();

        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.root_flutter_container, fragment)
                .commit();
    }
}

3. AndroidManifest 保留 MainActivity 为启动项

xml

复制代码
<activity android:name=".MainActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

优化:预加载引擎,消除启动白屏(全局 Application 缓存引擎)

MyApplication.java

java

运行

复制代码
import android.app.Application;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;

public class MyApp extends Application {
    public static final String FLUTTER_ENGINE_KEY = "cache_engine";

    @Override
    public void onCreate() {
        super.onCreate();
        // 预初始化Flutter引擎
        FlutterEngine engine = new FlutterEngine(this);
        engine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
        FlutterEngineCache.getInstance().put(FLUTTER_ENGINE_KEY, engine);
    }
}

AndroidManifest 中 application 标签添加:

xml

复制代码
android:name=".MyApp"

使用缓存引擎(修改 Fragment/Activity 创建代码)

java

运行

复制代码
// Fragment写法
FlutterFragment fragment = FlutterFragment.withCachedEngine(MyApp.FLUTTER_ENGINE_KEY).build();

// FlutterActivity清单固定缓存引擎
<meta-data
    android:name="io.flutter.embedding.android.FLUTTER_ENGINE_ID"
    android:value="cache_engine"/>

关键小结

  1. 最简方案:清单把 FlutterActivity 设置为 LAUNCHER,打开 APP 直接 Flutter 全屏
  2. 保留原生壳:MainActivity 加载全屏 FlutterFragment
  3. 预缓存引擎 = 去掉冷启动白屏
相关推荐
墨狂之逸才12 小时前
Android TV WebView 遥控器按键处理:从全透传到白名单
android
plainGeekDev18 小时前
MVC 写法 → MVVM
android·java·kotlin
用户9655973619018 小时前
Provider vs Bloc vs GetX vs Riverpod:Flutter 状态管理方案怎么选?
flutter
恋猫de小郭18 小时前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter
三少爷的鞋20 小时前
“结构化”这个词,本质上就是——把混乱的东西变成有组织、有规则、有边界的东西
android
程序员老刘1 天前
跑分第一的编程大模型,我为啥不用?
flutter·ai编程·vibecoding
方白羽2 天前
Android Gradle 缓存与文件目录深度解析
android·gradle·android studio
曲幽2 天前
Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招!
android·termux·nohup·services·wake-lock
plainGeekDev2 天前
单例模式 → object 声明
android·java·kotlin
程序员陆业聪2 天前
读者点单·03|Compose 与传统 View 混用的 12 个真实坑
android