在Android实现类iOS风格通知的技术求助
问题描述
- 用Kotlin开发Android应用,接收服务器推送的data消息,需实现类iOS风格通知:
- 手机亮屏/解锁状态(当前应用、其他应用或桌面):弹出heads-up提示消息
- 手机熄屏/锁屏状态:通知栏显示展开式通知并点亮屏幕
- 现有实现问题:
- 用
LockscreenActivity实现亮屏会全屏显示,不符合需求 - 不使用该Activity则无法点亮屏幕
- 点击通知跳转
MainActivity时,setShowWhenLocked(true)和setTurnScreenOn(true)无效
- 用
最简解决方案
无需额外的LockscreenActivity,通过以下步骤实现需求:
1. 添加必要权限
在AndroidManifest.xml中添加唤醒屏幕和通知相关权限:
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISPLAY_NOTIFICATION_POLICY" /> <!-- Android 14+ 需添加 --> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
2. 配置MainActivity
在Manifest中设置Activity属性
<activity android:name=".MainActivity" android:showWhenLocked="true" android:turnScreenOn="true" android:excludeFromRecents="false"> <!-- 其他原有配置 --> </activity>
补充MainActivity代码
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 适配不同Android版本的锁屏显示与唤醒 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.insetsController?.let { it.show(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } } else { @Suppress("DEPRECATION") window.addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ) } setContentView(R.layout.activity_main) }
3. 修改NotificationService代码
移除全屏Intent相关逻辑,改用WakeLock点亮屏幕,优化通知配置:
class NotificationService : FirebaseMessagingService() { private val TAG = "NotificationService" override fun onMessageReceived(remoteMessage: RemoteMessage) { // 优先取data消息,其次取notification消息 val messageBody = remoteMessage.data["my_alert"] ?: remoteMessage.notification?.body ?: return sendNotification(messageBody) } private fun sendNotification(messageBody: String) { val channelId = getString(R.string.default_notification_channel_id) val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager // 创建通知渠道(仅Android O+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "My alerts", NotificationManager.IMPORTANCE_HIGH // 必须设为HIGH才能触发heads-up ).apply { description = "Notifications description." setShowBadge(false) lockscreenVisibility = Notification.VISIBILITY_PUBLIC enableVibration(true) vibrationPattern = longArrayOf(200, 200, 200, 200, 200) enableLights(true) // 可选:开启通知指示灯 } notificationManager.createNotificationChannel(channel) } // 配置跳转MainActivity的PendingIntent val contentIntent = Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val contentPendingIntent = PendingIntent.getActivity( this, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 构建通知,添加展开式样式 val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(getString(R.string.alert_title)) .setContentText(messageBody) .setStyle(NotificationCompat.BigTextStyle().bigText(messageBody)) // 展开式通知 .setSound(defaultSoundUri) .setPriority(NotificationCompat.PRIORITY_HIGH) .setOnlyAlertOnce(true) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setContentIntent(contentPendingIntent) .setAutoCancel(true) // 点亮屏幕(无需额外Activity) wakeUpScreen() // 发送通知(用时间戳做ID避免重复覆盖) val notificationId = System.currentTimeMillis().toInt() notificationManager.notify(notificationId, notificationBuilder.build()) } private fun wakeUpScreen() { val powerManager = getSystemService(POWER_SERVICE) as PowerManager val wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP, "${packageName}:notification_wake_lock" ) wakeLock.acquire(10000) // 保持亮屏10秒,可按需调整时长 } }
关键说明
- Heads-up触发:通知渠道
IMPORTANCE_HIGH+通知PRIORITY_HIGH,系统会自动在亮屏状态下弹出heads-up提示 - 亮屏实现:通过
PowerManager的WakeLock直接唤醒屏幕,避免额外Activity导致的全屏问题 - 锁屏跳转:通过Manifest和代码双配置
showWhenLocked/turnScreenOn,确保跳转时直接解锁显示应用
内容的提问来源于stack exchange,提问作者orbital_mechanic
相关产品推荐
相关产品推荐

