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. 关键点总结
-
通信流程:
- Flutter → 通过
MethodChannel
调用原生方法 - Android → 通过
startActivityForResult
启动设置页 - 设置页 → 返回结果通过
MethodChannel
传回Flutter
- Flutter → 通过
-
Kotlin特性利用:
- 使用
lateinit
延迟初始化绑定 - 使用
apply
简化对象配置 - 使用
when
表达式替代 switch-case
- 使用
-
类型安全:
- 使用Kotlin的空安全操作符
?
- 明确指定泛型类型
Map<String, Any>
- 使用Kotlin的空安全操作符
-
线程安全:
- 通过
Handler(Looper.getMainLooper())
确保在主线程更新UI
- 通过
-
资源管理:
- 使用 View Binding (
ActivitySettingsBinding
) - 合理处理 Activity 生命周期
- 使用 View Binding (
这个实现完整展示了 Flutter 与 Android 原生页面之间的双向通信,所有代码均采用 Kotlin 编写,符合现代 Android 开发最佳实践。