You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Wear OS前台服务黑屏时启动Activity或弹窗通知求助

解决方案与最佳实践(针对Wear OS应急应用后台触发场景)

一、修复全屏Intent启动Activity(优先方案)

BAL_BLOCK错误本质是系统拦截了后台启动Activity的请求——Wear OS对后台启动Activity的限制比手机更严格,即便配置了USE_FULL_SCREEN_INTENT,也必须通过高优先级通知绑定全屏Intent的方式触发,不能直接调用startActivity()

  • 核心代码实现

    // 构建启动主Activity的Intent
    val fullScreenIntent = Intent(context, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val pendingIntent = PendingIntent.getActivity(
        context,
        0,
        fullScreenIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
    
    // 构建绑定全屏Intent的紧急通知
    val notification = NotificationCompat.Builder(context, EMERGENCY_CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_emergency)
        .setContentTitle("紧急事件触发")
        .setContentText("请立即响应")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setCategory(NotificationCompat.CATEGORY_ALARM)
        .setFullScreenIntent(pendingIntent, true) // 强制系统处理全屏Intent
        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
        .build()
    
    // 若服务已处于前台,直接更新通知;否则启动前台服务
    startForeground(NOTIFICATION_ID, notification)
    
  • Activity配置验证:确保Manifest中Activity的属性完整,Android 14+可额外添加enableOnBackInvokedCallback避免兼容性问题:

    <activity
        android:name=".MainActivity"
        android:launchMode="singleTask"
        android:showWhenLocked="true"
        android:turnScreenOn="true"
        android:excludeFromRecents="true"> <!-- 可选,避免最近列表混乱 -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    
  • 权限补充:除已配置权限外,需添加WAKE_LOCK确保屏幕能被唤醒:

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

二、备选方案:唤醒屏幕+高优先级紧急通知

若全屏Intent仍被系统拦截,可通过唤醒锁+强化通知的组合实现需求:

  • 获取唤醒锁点亮屏幕

    val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
    val wakeLock = powerManager.newWakeLock(
        PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP,
        "EmergencyApp:WakeLock"
    )
    wakeLock.acquire(10 * 1000L) // 保持10秒,确保用户能看到通知
    
  • 强化通知紧急性:确保通知通道配置足够激进,触发系统级的提醒:

    // 初始化紧急通知通道(仅需执行一次)
    fun initEmergencyChannel(context: Context) {
        val channel = NotificationChannel(
            EMERGENCY_CHANNEL_ID,
            "紧急通知",
            NotificationManager.IMPORTANCE_HIGH
        ).apply {
            description = "紧急事件触发提醒"
            enableVibration(true)
            vibrationPattern = longArrayOf(0, 1000, 500, 1000) // 强震动模式
            setSound(
                RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM),
                AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build()
            )
            lockscreenVisibility = Notification.VISIBILITY_PUBLIC
        }
        context.getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
    }
    

三、Wear OS特有注意事项

  • 禁止后台直接调用startActivity():Wear OS不允许非通知触发的后台Activity启动,必须通过全屏Intent绑定通知的方式。
  • 排查拦截原因:可通过adb shell dumpsys activity broadcasts命令查看BAL_BLOCK的具体触发条件,比如应用是否处于空闲状态、权限是否未正确授予。
  • 考虑系统级应急API:如果是医疗类应急应用,可使用Wear OS的EmergencySosManager,系统会给予更高优先级,避免被拦截。

四、最佳实践

  • 保持服务前台状态:确保监测服务始终处于前台,避免被系统回收,同时前台通知可作为紧急事件的载体。
  • 主动申请动态权限:在应用启动时,主动请求POST_NOTIFICATIONS权限,避免通知被系统拦截。
  • 多场景测试:在黑屏、应用后台、低电量模式下验证功能,确保极端场景下的可靠性。
  • 版本兼容处理:针对Android 12+、13+、14+的权限和Intent flag差异做适配,比如PendingIntentFLAG_IMMUTABLE/FLAG_MUTABLE

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

火山引擎 最新活动