开发含第三方SDK的Flutter插件:onIdleTimeout触发时用EventChannel通知Flutter(Kotlin)
Got it, let's work through this together! I'll show you exactly how to set up the EventChannel in your Kotlin Flutter plugin and trigger it from the overridden onIdleTimeout() method—no native login popup required.
Core Idea
The key here is to hold a reference to the EventChannel's EventSink so you can send messages to Flutter from anywhere in your plugin code, including the SDK's callback method. We'll skip the SDK's default behavior (the login popup) and instead fire an event to let your Dart code handle the timeout.
Step-by-Step Implementation
1. Initialize EventChannel and Store the EventSink
In your plugin's main Kotlin class, set up the EventChannel when the plugin attaches to Flutter, and save the EventSink as a nullable property for later use.
2. Override the SDK's onIdleTimeout()
Skip calling the super implementation (that's what triggers the native login popup) and use the saved EventSink to send a message to Flutter.
3. Clean Up to Avoid Leaks
Null out the EventSink when the channel is canceled, and detach the SDK listener when the plugin is detached from Flutter.
Full Kotlin Plugin Code Example
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.plugin.common.EventChannel import com.yourthirdparty.sdk.ThirdPartySdk // Replace with your actual SDK import class IdleTimeoutPlugin : FlutterPlugin, ActivityAware, ThirdPartySdk.IdleListener { private var eventSink: EventChannel.EventSink? = null // Use a unique channel name for your plugin private val EVENT_CHANNEL = "com.yourplugin/idle_timeout_events" override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { // Initialize the EventChannel val channel = EventChannel(binding.binaryMessenger, EVENT_CHANNEL) channel.setStreamHandler(object : EventChannel.StreamHandler { override fun onListen(arguments: Any?, sink: EventChannel.EventSink?) { // Save the sink to use later in onIdleTimeout eventSink = sink } override fun onCancel(arguments: Any?) { // Clean up to prevent memory leaks eventSink = null } }) // Register this class as the SDK's idle timeout listener ThirdPartySdk.setIdleListener(this) } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { // Remove the SDK listener and clear the event sink ThirdPartySdk.removeIdleListener() eventSink = null } // Override the SDK's onIdleTimeout method override fun onIdleTimeout() { // DO NOT call super.onIdleTimeout() — this skips the native login popup // Send the event to Flutter eventSink?.success("idle_timeout_triggered") // Optional: If you need to manually log out the user, do it here // ThirdPartySdk.logoutUser() } // ActivityAware methods (required if your SDK needs an Activity reference) override fun onAttachedToActivity(binding: ActivityPluginBinding) {} override fun onDetachedFromActivityForConfigChanges() {} override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {} override fun onDetachedFromActivity() {} }
Flutter Dart Side Listener Example
In your Flutter app, set up a stream listener to receive the idle timeout event:
import 'package:flutter/services.dart'; class IdleTimeoutService { static const _eventChannel = EventChannel('com.yourplugin/idle_timeout_events'); static Stream<String> get idleTimeoutStream { return _eventChannel.receiveBroadcastStream().map((event) => event as String); } } // Usage in your widget: @override void initState() { super.initState(); IdleTimeoutService.idleTimeoutStream.listen((event) { if (event == 'idle_timeout_triggered') { // Handle the timeout here (e.g., navigate to your Flutter login screen) print('Idle timeout detected! Redirecting to login...'); } }); }
Important Notes
- Preventing the Popup: The most critical line is skipping
super.onIdleTimeout()—this stops the SDK from launching its native login UI. If the SDK uses a different mechanism to trigger the popup, check its docs for a flag to disable this behavior. - Null Safety: Always check if
eventSinkis not null before callingsuccess()to avoid crashes (this can happen if the Flutter side has canceled the stream). - SDK Initialization: Make sure your third-party SDK is properly initialized with your plugin class as the listener, as shown in
onAttachedToEngine.
内容的提问来源于stack exchange,提问作者Derek Hannah

