基于Xamarin的考试APP如何检测悬浮/multiwindow应用及应用切换并终止考试?
Hey there! Great question—this is a critical requirement for exam proctoring apps, and totally achievable with Xamarin. Let’s break this down by platform since Android and iOS handle app lifecycle, multi-window, and overlay detection very differently:
Android Implementation
Android gives us more flexibility to monitor system-level events, but you’ll need to request specific permissions first.
1. Detect App Switches (Foreground/Background)
To check if your app is no longer in the foreground, you have two reliable options:
- Activity Lifecycle Hooks: Override
OnPause()in your main Activity, but note this can trigger for normal actions like screen rotation. For stricter checks, use theUsageStatsManagerto verify the current foreground app package:using Android.App; using Android.Content; using Android.App.Usage; using System; public bool IsAppInForeground(Context context) { var usageStatsManager = (UsageStatsManager)context.GetSystemService(Context.UsageStatsService); long currentTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var stats = usageStatsManager.QueryUsageStats(UsageStatsInterval.Daily, currentTime - 10000, currentTime); if (stats?.Count > 0) { string currentPackage = null; long lastUsed = 0; foreach (var stat in stats) { if (stat.LastTimeUsed > lastUsed) { lastUsed = stat.LastTimeUsed; currentPackage = stat.PackageName; } } return currentPackage == context.PackageName; } return false; } - Schedule Periodic Checks: Use a
HandlerorAlarmManagerto run the above check every few seconds. If it returnsfalse, trigger the exam termination.
2. Detect Multi-Window Mode
Android has a built-in callback for multi-window state changes. Add this to your main Activity:
protected override void OnMultiWindowModeChanged(bool isInMultiWindowMode, Android.OS.Configuration newConfig) { base.OnMultiWindowModeChanged(isInMultiWindowMode, newConfig); if (isInMultiWindowMode) { // Trigger exam termination here TerminateExam(this); } } private void TerminateExam(Activity activity) { activity.RunOnUiThread(() => { new AlertDialog.Builder(activity) .SetTitle("Exam Terminated") .SetMessage("Multi-window mode detected. Your exam has been ended.") .SetPositiveButton("OK", (s, e) => activity.Finish()) .Show(); }); }
3. Detect Floating/Overlay Apps
To detect floating overlays (like chat heads or screen recorders):
- First, request the
SYSTEM_ALERT_WINDOWpermission in yourAndroidManifest.xml:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> - Use an
AccessibilityServiceto monitor window events. Create a service class:[Service(Label = "Overlay Monitor", Permission = Android.Manifest.Permission.BindAccessibilityService)] [IntentFilter(new[] { Android.Accessibility.AccessibilityService.ActionAccessibilityService })] [MetaData(Android.Accessibility.AccessibilityService.MetaDataAccessibilityService, Resource = "@xml/accessibility_service_config")] public class OverlayMonitorService : AccessibilityService { public override void OnAccessibilityEvent(AccessibilityEvent e) { if (e.EventType == Android.Accessibility.EventTypes.WindowStateChanged) { var windowType = e.WindowType; // Check if the window is an overlay if (windowType == Android.Views.WindowManagerTypes.ApplicationOverlay) { // Trigger exam termination TerminateExam(this); } } } public override void OnInterrupt() { } } - Create an accessibility config file (
Resources/xml/accessibility_service_config.xml) to enable window monitoring:<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true"/> - You’ll need to guide users to enable accessibility permissions for your app in system settings.
Required Permissions
Don’t forget to add these to your AndroidManifest.xml:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
iOS Implementation
iOS is more restrictive, but you can still monitor app switches and multi-window (iPad-only) events using lifecycle callbacks.
1. Detect App Switches
iOS triggers DidEnterBackground when the app is sent to the background (e.g., user switches to another app). Add this to your AppDelegate:
public override void DidEnterBackground(UIApplication application) { base.DidEnterBackground(application); // Trigger exam termination TerminateExam(); } private void TerminateExam() { UIApplication.SharedApplication.InvokeOnMainThread(() => { var alert = UIAlertController.Create("Exam Terminated", "App switch detected. Your exam has been ended.", UIAlertControllerStyle.Alert); alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, (action) => { // Close all view controllers or exit the app foreach (var window in UIApplication.SharedApplication.Windows) { window.RootViewController.DismissViewController(true, null); } })); UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alert, true, null); }); }
2. Detect Multi-Window Mode (iPad)
For iPad multi-window support, use SceneDelegate to monitor scene activation states:
public override void DidEnterBackground(UIScene scene) { base.DidEnterBackground(scene); // Check if any scene is still active var activeScene = UIApplication.SharedApplication.ConnectedScenes .FirstOrDefault(s => s.ActivationState == UISceneActivationState.ForegroundActive); if (activeScene == null) { TerminateExam(); } }
3. Detect Floating Apps
iOS doesn’t allow third-party apps to monitor system overlays directly, but you can check for system-level floating features like Picture-in-Picture by listening to relevant notifications (e.g., AVPlayerPictureInPictureControllerDidStartPictureInPictureNotification if your app uses video). For most exam scenarios, monitoring app background state is sufficient to catch users switching to other tools.
Xamarin.Forms Unified Approach
To keep your code clean, use DependencyService to wrap platform-specific monitoring logic:
- Define a shared interface in your Forms project:
public interface IExamMonitorService { void StartMonitoring(); void StopMonitoring(); } - Implement this interface in your Android and iOS projects as shown above.
- Initialize the service in your Forms app:
DependencyService.Get<IExamMonitorService>().StartMonitoring();
内容的提问来源于stack exchange,提问作者Alberto Pineda

