flutter悬浮窗后台唤起app

99 阅读1分钟

,通过receivePort进行监听,写原生服务文件, 在app/src/main/androidmainifest引入 OverlayService文件: package com.xxx.chat

import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Handler import android.os.Looper

class OverlayReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == "com.xxxx.chat.OVERLAY_CLICK") { try { // 创建启动主 Activity 的 Intent val launchIntent = Intent(context, MainActivity::class.java).apply { // 这些标志确保应用被正确带到前台 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

                // 添加额外数据以标识来自悬浮窗
                putExtra("from_overlay", true)
            }
            
            context?.startActivity(launchIntent)
            
            // 给 Flutter 端一些时间来准备
            Handler(Looper.getMainLooper()).postDelayed({
                // Flutter 端会通过 IsolateNameServer 接收消息
            }, 300)
            
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

} mainActivity.kt: package com.xxxx.chat

import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import android.content.Intent import androidx.annotation.NonNull import android.os.Bundle

class MainActivity : FlutterActivity(){ private val OVERLAY_CHANNEL = "com.xxxx.chat/overlay_channel"

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    handleOverlayIntent(intent)
}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    handleOverlayIntent(intent)
}

private fun handleOverlayIntent(intent: Intent?) {
    if (intent?.getBooleanExtra("from_overlay", false) == true) {
        // 可选:从悬浮窗进入时做处理
    }
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine)

    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, OVERLAY_CHANNEL).setMethodCallHandler { call, result ->
        when (call.method) {
            "sendOverlayClickBroadcast" -> {
                val intent = Intent("com.xxx.chat.OVERLAY_CLICK")
                sendBroadcast(intent)
                result.success(null)
            }
            "startOverlayService" -> {
                val intent = Intent(this, OverlayService::class.java)
                startForegroundService(intent)
                result.success(null)
            }
            "stopOverlayService" -> {
                val intent = Intent(this, OverlayService::class.java)
                stopService(intent)
                result.success(null)
            }
            "startMainActivity" -> {
                try {
                    val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
                    launchIntent?.apply {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
                        addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                        addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                    }
                    if (launchIntent != null) startActivity(launchIntent)
                    result.success(null)
                } catch (e: Exception) {
                    result.error("OPEN_ACTIVITY_ERROR", e.message, null)
                }
            }
            else -> result.notImplemented()
        }
    }
}
}

main.dart文件主线程监听进行调用
final receivePort = ReceivePort();

IsolateNameServer.registerPortWithName( receivePort.sendPort, kOverlayClickPortName, );

receivePort.listen((message) async { try { debugPrint('收到浮窗消息: $message');

  // 验证消息格式
  if (message == 'clicked') {
     const platform = MethodChannel('com.xxx.chat/overlay_channel');
    await platform.invokeMethod('startMainActivity'); // 唤醒到前台

    // 先关浮窗
    await FlutterOverlayWindow.closeOverlay();
    // 获取当前通话的 ID
    final RtcController rtcController = Get.find<RtcController>();
    final currentCallId = rtcController.onids.value.toString();
    // 再做跳转
    if (currentCallId != 0) {
      // 再做跳转,使用实际的通话 ID
      Get.toNamed(
        AppRoutes.voiceCallPageprivate,
        arguments: {
          'id': currentCallId.toString(),
          'mode': 'video',
          'type': 'PRIVATE',
          'jsz': false,
          'fromOverlay': true, // 标记是从悬浮窗返回的
        },
      );
    }
  }
} catch (e) {
  debugPrint('处理浮窗消息时出错: $e');
}

}); 悬浮窗组件的点击事件 try {

          final SendPort? mainPort = IsolateNameServer.lookupPortByName(
            kOverlayClickPortName,
          );
          

          if (mainPort != null) {
            mainPort.send('clicked'); }这样就可以实现了