如何从Android原生Broadcast Receiver向Flutter传输数据流?
Android原生向Flutter同步短信发送报告的两种方案
方案一:通过EventChannel实时传输数据(推荐)
这种方案借助Flutter提供的EventChannel实现原生与Flutter的数据流通信,实时将短信发送状态传递到Flutter端,再由Flutter完成本地数据库更新。
原生端改造步骤
- 在MainActivity中注册EventChannel并保存事件接收器
public class MainActivity extends FlutterActivity { private static final String RECEIVE_REPORT = "com.esnanosoft/sms_sent_report"; private EventChannel.EventSink smsSentEventSink; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 注册EventChannel,监听Flutter的订阅请求 new EventChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), RECEIVE_REPORT) .setStreamHandler(new EventChannel.StreamHandler() { @Override public void onListen(Object arguments, EventChannel.EventSink sink) { smsSentEventSink = sink; // 保存接收器,用于后续发送事件 } @Override public void onCancel(Object arguments) { smsSentEventSink = null; // 取消订阅时清空接收器 } }); // 将MainActivity实例存入Application,方便BroadcastReceiver调用 ((MyApplication) getApplication()).setMainActivity(this); } // 对外提供发送短信报告的方法 public void sendSmsSentReport(String messageId) { if (smsSentEventSink != null) { smsSentEventSink.success(messageId); // 向Flutter发送事件数据 } } }
- 自定义Application类存储MainActivity实例
public class MyApplication extends FlutterApplication { private MainActivity mainActivity; public MainActivity getMainActivity() { return mainActivity; } public void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; } }
- 修改SentReceiver,触发事件发送
public class SentReceiver extends BroadcastReceiver { private static final String TAG = "SentReceiver"; @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "onReceive: " + intent.getAction()); int resultCode = getResultCode(); boolean successfullySent = resultCode == Activity.RESULT_OK; if (successfullySent) { String messageId = intent.getStringExtra("messageId"); Log.e(TAG, "run: " + messageId); // 从Application获取MainActivity实例,发送事件到Flutter MainActivity mainActivity = ((MyApplication) context.getApplicationContext()).getMainActivity(); if (mainActivity != null) { mainActivity.sendSmsSentReport(messageId); } } } }
Flutter端完善代码
import 'package:flutter/services.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; class SmsReportManager { static const String RECEIVE_REPORT = "com.esnanosoft/sms_sent_report"; static const sentSMSChannel = EventChannel(RECEIVE_REPORT); StreamSubscription? _streamSubscription; Database? _database; // 初始化数据库(复用你已有的逻辑) Future<void> initDB() async { final dbPath = await getDatabasesPath(); final path = join(dbPath, "ESNanoSoft.db"); _database = await openDatabase(path, version: 1, onCreate: _createDB, onUpgrade: _onUpgrade); } // 开始监听原生发送的事件 void startListening() { _streamSubscription = sentSMSChannel.receiveBroadcastStream().listen((event) { print("收到短信发送报告:messageId = $event"); // 更新本地数据库状态 _updateSmsStatus(event as String, true); }, onError: (error) { print("接收发送报告出错:$error"); }); } // 停止监听,避免内存泄漏 void stopListening() { _streamSubscription?.cancel(); _streamSubscription = null; } // 更新数据库中短信的发送状态 Future<void> _updateSmsStatus(String messageId, bool isSent) async { if (_database == null) return; await _database!.update( 'sms_table', // 替换为你的实际表名 {'is_sent': isSent ? 1 : 0}, // 替换为你的状态字段名 where: 'id = ?', // 替换为你的主键字段 whereArgs: [messageId], ); } // 数据库创建和升级逻辑(复用你已有的代码) void _createDB(Database db, int version) { // 你的表创建语句 } void _onUpgrade(Database db, int oldVersion, int newVersion) { // 你的表升级逻辑 } }
方案二:原生直接访问Flutter的SQLite数据库
如果不需要实时通知,也可以让原生直接定位到Flutter的SQLite数据库文件,直接执行更新操作。
原生端修改SentReceiver
public class SentReceiver extends BroadcastReceiver { private static final String TAG = "SentReceiver"; @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "onReceive: " + intent.getAction()); int resultCode = getResultCode(); boolean successfullySent = resultCode == Activity.RESULT_OK; if (successfullySent) { String messageId = intent.getStringExtra("messageId"); Log.e(TAG, "run: " + messageId); // 将数据库操作放到子线程,避免主线程ANR new Thread(() -> { // 获取Flutter SQLite数据库的路径 String dbDir = context.getFilesDir().getParentFile().getPath() + "/databases"; String dbPath = dbDir + "/ESNanoSoft.db"; // 打开数据库并更新状态 SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE); ContentValues values = new ContentValues(); values.put("is_sent", 1); // 替换为你的状态字段名,1表示发送成功 db.update("sms_table", values, "id = ?", new String[]{messageId}); // 替换为你的表名和主键 db.close(); }).start(); } } }
注意事项
- 原生端的表结构、字段名必须与Flutter端完全一致,否则会触发数据库异常
- 数据库版本升级时,原生端的升级逻辑需要和Flutter端保持同步
- 必须在子线程中执行数据库操作,避免BroadcastReceiver在主线程执行耗时操作导致ANR
内容的提问来源于stack exchange,提问作者SALMAN ABOHOLIQAH
相关产品推荐
相关产品推荐

