You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MAUI Blazor WebView后台5分钟后停止处理的解决方案咨询

问题描述

我使用MAUI混合模式开发Android应用,采用Blazor-WebView组件,通过蓝牙接收智能笔的数据包,借助perfect-freehand库在画布上绘制笔迹。

遇到的问题:应用进入后台(切换至其他应用或熄屏)后,前5分钟可正常处理数据包并绘制笔迹,但5分钟后,MAUI层仍能接收数据包,却无法被Blazor-WebView处理。

观察到的行为:后台前5分钟,笔迹绘制及数据库存储均正常;5分钟后,await js.InvokeVoidAsync("onDeviceNotification", id, val, mac)调用出现阻塞;将应用带回前台后,所有排队的数据包会被依次正确处理。

已尝试方案

  • 实现ForegroundService以维持应用后台运行;
  • 使用PowerManager.WakeLock防止CPU休眠;
  • 添加WebView设置以允许后台JavaScript执行:
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
{
    e.WebView.SetRendererPriorityPolicy(RendererPriority.Important, false);
}

提问

如何让Android端的WebView(Blazor)在后台持续保持活跃并处理JavaScript调用,即使超过5分钟?鉴于iOS无此问题,是否存在遗漏的Android专属优化设置?希望获取维持WebView长时间后台活跃的建议,以匹配iOS端的表现。

补充信息:目标Android版本33,MAUI版本7


解决方案建议

1. 调整WebView的进程优先级与后台渲染策略

针对Android 9+,除现有设置外,补充以下配置强化WebView后台活跃性:

// 确保基础JS执行权限
e.WebView.Settings.JavaScriptEnabled = true;
// 禁用WebView省电暗模式(Android 10+)
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
{
    e.WebView.Settings.SetForceDark(WebSettings.ForceDarkOff);
}
// 强制保持屏幕唤醒(配合WakeLock双重保障)
e.WebView.SetKeepScreenOn(true);

同时修改渲染优先级策略,强制提升渲染进程优先级:

if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
{
    e.WebView.SetRendererPriorityPolicy(RendererPriority.Important, true);
}

2. 优化ForegroundService配置

确保前台服务的通知具备最高优先级,避免系统限制:

var notification = new Notification.Builder(this, CHANNEL_ID)
    .SetContentTitle("智能笔服务运行中")
    .SetContentText("正在接收笔迹数据")
    .SetSmallIcon(Resource.Drawable.ic_notification)
    .SetPriority(NotificationPriority.High)
    .SetOngoing(true) // 设为不可关闭的持续通知
    .Build();

StartForeground(SERVICE_ID, notification);

在AndroidManifest.xml中补充权限与服务声明:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />

<service
    android:name=".SmartPenForegroundService"
    android:foregroundServiceType="connectedDevice"
    android:exported="false" />

3. 异步队列优化JS调用逻辑

避免在蓝牙回调中直接调用js.InvokeVoidAsync导致阻塞,改用线程安全队列批量处理:

// 定义线程安全的数据包队列
private ConcurrentQueue<(int id, byte[] val, string mac)> _dataQueue = new();
private Handler _webViewMainHandler;

// WebView初始化时获取主线程Handler
_webViewMainHandler = new Handler(Looper.MainLooper);

// 蓝牙回调中仅将数据加入队列
void OnBluetoothDataReceived(int id, byte[] val, string mac)
{
    _dataQueue.Enqueue((id, val, mac));
    _webViewMainHandler.PostDelayed(ProcessPendingData, 50);
}

// 批量处理队列数据
async void ProcessPendingData()
{
    if (_dataQueue.IsEmpty) return;
    
    while (_dataQueue.TryDequeue(out var data))
    {
        try
        {
            await js.InvokeVoidAsync("onDeviceNotification", data.id, data.val, data.mac);
        }
        catch (Exception ex)
        {
            // 记录异常,不中断后续处理
        }
    }
}

4. 禁用WebView自动暂停机制

通过注入定时JS脚本,避免WebView在后台自动暂停执行:

public class PersistentWebViewClient : WebViewClient
{
    public override void OnPageFinished(WebView view, string url)
    {
        base.OnPageFinished(view, url);
        // 每3秒执行一次空脚本,维持页面活跃
        view.EvaluateJavascript("setInterval(() => { /* keep alive */ }, 3000);", null);
    }
}

// 给WebView绑定自定义Client
e.WebView.SetWebViewClient(new PersistentWebViewClient());

5. Android 13+权限补充

针对目标版本33,需动态请求POST_NOTIFICATIONS权限,确保前台服务通知正常显示,否则系统可能强制停止服务:

if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu)
{
    if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.PostNotifications) != Permission.Granted)
    {
        ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.PostNotifications }, NOTIFICATION_PERM_REQUEST_CODE);
    }
}

内容的提问来源于stack exchange,提问作者Siml

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:42:43