当前位置: 首页 > news >正文

Android 原生与 Flutter 通信完整实现 (Kotlin 版)

1. 项目配置

pubspec.yaml 添加依赖

dependencies:flutter:sdk: flutterprovider: ^6.0.5

2. Flutter 端实现

状态管理类

// settings_provider.dart
import 'package:flutter/foundation.dart';class SettingsProvider with ChangeNotifier {String _themeColor = 'blue';bool _darkMode = false;String get themeColor => _themeColor;bool get darkMode => _darkMode;void updateSettings(String color, bool dark) {_themeColor = color;_darkMode = dark;notifyListeners();}
}

主界面

// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/services.dart';void main() {runApp(ChangeNotifierProvider(create: (_) => SettingsProvider(),child: const MyApp(),),);
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: const MainPage(),);}
}class MainPage extends StatefulWidget {const MainPage({super.key});State<MainPage> createState() => _MainPageState();
}class _MainPageState extends State<MainPage> {static const platform = MethodChannel('com.example.app/settings');void initState() {super.initState();_initMethodChannel();}void _initMethodChannel() {platform.setMethodCallHandler((call) async {if (call.method == 'updateSettings') {final args = call.arguments as Map<dynamic, dynamic>;Provider.of<SettingsProvider>(context, listen: false).updateSettings(args['color'] as String,args['darkMode'] as bool,);}return null;});}Widget build(BuildContext context) {final settings = Provider.of<SettingsProvider>(context);return Scaffold(appBar: AppBar(title: const Text('主界面'),backgroundColor: _getColor(settings.themeColor),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text('当前主题色: ${settings.themeColor}',style: TextStyle(color: settings.darkMode ? Colors.white : Colors.black,),),const SizedBox(height: 20),Text('暗黑模式: ${settings.darkMode ? "开启" : "关闭"}',style: TextStyle(color: settings.darkMode ? Colors.white : Colors.black,),),const SizedBox(height: 40),ElevatedButton(onPressed: _openNativeSettings,child: const Text('打开原生设置页面'),),],),),backgroundColor: settings.darkMode ? Colors.grey[800] : Colors.white,);}Color _getColor(String colorName) {return switch (colorName) {'red' => Colors.red,'green' => Colors.green,_ => Colors.blue,};}Future<void> _openNativeSettings() async {try {final settings = Provider.of<SettingsProvider>(context, listen: false);await platform.invokeMethod('openSettings', {'color': settings.themeColor,'darkMode': settings.darkMode,});} on PlatformException catch (e) {debugPrint("打开设置失败: ${e.message}");}}
}

3. Android 原生端实现 (Kotlin)

MainActivity.kt

package com.example.myappimport android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannelclass MainActivity : FlutterActivity() {private val CHANNEL = "com.example.app/settings"private var latestSettings: Map<String, Any>? = nulloverride fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->when (call.method) {"openSettings" -> {val color = call.argument<String>("color") ?: "blue"val darkMode = call.argument<Boolean>("darkMode") ?: falseIntent(this, SettingsActivity::class.java).apply {putExtra("color", color)putExtra("darkMode", darkMode)startActivityForResult(this, 101)}result.success(null)}else -> result.notImplemented()}}}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 101 && resultCode == RESULT_OK) {data?.extras?.let { extras ->val settings = mapOf("color" to extras.getString("color", "blue"),"darkMode" to extras.getBoolean("darkMode", false))latestSettings = settingsHandler(Looper.getMainLooper()).post {MethodChannel(flutterEngine?.dartExecutor, CHANNEL).invokeMethod("updateSettings", settings)}}}}
}

SettingsActivity.kt

package com.example.myappimport android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.databinding.ActivitySettingsBindingclass SettingsActivity : AppCompatActivity() {private lateinit var binding: ActivitySettingsBindingprivate var selectedColor = "blue"private var darkMode = falseoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivitySettingsBinding.inflate(layoutInflater)setContentView(binding.root)// 获取初始值selectedColor = intent.getStringExtra("color") ?: "blue"darkMode = intent.getBooleanExtra("darkMode", false)// 初始化UI状态when (selectedColor) {"red" -> binding.colorGroup.check(R.id.red)"green" -> binding.colorGroup.check(R.id.green)else -> binding.colorGroup.check(R.id.blue)}binding.darkModeSwitch.isChecked = darkMode// 保存按钮点击binding.saveButton.setOnClickListener {selectedColor = when (binding.colorGroup.checkedRadioButtonId) {R.id.red -> "red"R.id.green -> "green"else -> "blue"}darkMode = binding.darkModeSwitch.isCheckedIntent().apply {putExtra("color", selectedColor)putExtra("darkMode", darkMode)setResult(RESULT_OK, this)}finish()}}
}

activity_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="主题颜色"android:textSize="18sp"/><RadioGroupandroid:id="@+id/colorGroup"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/red"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="红色"/><RadioButtonandroid:id="@+id/green"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="绿色"android:layout_marginStart="16dp"/><RadioButtonandroid:id="@+id/blue"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="蓝色"android:layout_marginStart="16dp"/></RadioGroup><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginTop="24dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="暗黑模式"android:textSize="18sp"/><Switchandroid:id="@+id/darkModeSwitch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"/></LinearLayout><Buttonandroid:id="@+id/saveButton"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="保存设置"android:layout_marginTop="32dp"/>
</LinearLayout>

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"><applicationandroid:label="MyApp"android:icon="@mipmap/ic_launcher"><activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTop"android:theme="@style/LaunchTheme"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:hardwareAccelerated="true"android:windowSoftInputMode="adjustResize"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activityandroid:name=".SettingsActivity"android:theme="@style/Theme.AppCompat.Light.DialogWhenLarge"android:exported="false" /></application>
</manifest>

4. 关键点总结

  1. 通信流程:

    • Flutter → 通过 MethodChannel 调用原生方法
    • Android → 通过 startActivityForResult 启动设置页
    • 设置页 → 返回结果通过 MethodChannel 传回Flutter
  2. Kotlin特性利用:

    • 使用 lateinit 延迟初始化绑定
    • 使用 apply 简化对象配置
    • 使用 when 表达式替代 switch-case
  3. 类型安全:

    • 使用Kotlin的空安全操作符 ?
    • 明确指定泛型类型 Map<String, Any>
  4. 线程安全:

    • 通过 Handler(Looper.getMainLooper()) 确保在主线程更新UI
  5. 资源管理:

    • 使用 View Binding (ActivitySettingsBinding)
    • 合理处理 Activity 生命周期

这个实现完整展示了 Flutter 与 Android 原生页面之间的双向通信,所有代码均采用 Kotlin 编写,符合现代 Android 开发最佳实践。

http://www.dtcms.com/a/319241.html

相关文章:

  • C++基础:继承
  • qt系统--事件
  • 设计模式中的行为模式
  • sqli-labs-master/Less-41~Less-50
  • 论文Review 激光实时动态物体剔除 DUFOMap | KTH出品!RAL2024!| 不上感知,激光的动态物体在线剔除还能有什么方法?
  • DrissionPage自动化:高效Web操作新选择
  • 【人工智能99问】NLP(自然语言处理)大模型有哪些?(20/99)
  • 【多重BFS】Monsters
  • 调用阿里云-阿里云百炼 AI
  • 表驱动法-灵活编程范式
  • Java 中 Object 类的解析:知识点与注意事项
  • Oracle参数Process
  • 深度学习的视觉惯性里程计(VIO)算法优化实践
  • PCB制造中压接孔、插接孔、沉头孔、台阶孔的区别及生产流程
  • [Oracle] MOD()函数
  • 数据库入门:从零开始构建你的第一个数据库
  • idea工具maven下载报错:PKIX path building failed,配置忽略SSL检查
  • [Oracle] CEIL()函数
  • 无人机航拍数据集|第7期 无人机绵羊红外目标检测YOLO数据集1964张yolov11/yolov8/yolov5可训练
  • 计算虚拟化技术
  • vscode.window.activeTextEditor 获取不到 png 图片路径问题
  • 僵尸进程问题排查
  • Github创建仓库,克隆提交代码到远程
  • 内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer
  • 【3D图像技术分析与实现】谷歌的AlphaEarth是如何实现的?
  • 鸿蒙RichEditor
  • 使用萤石云播放视频及主题模版配置
  • python安装部署rknn-toolkit2(ModuleNotFoundError: No module named ‘rknn_toolkit2‘)
  • 技术速递|Copilot Coding Agent:自定义设置步骤更可靠、更易于调试
  • P8250 交友问题