如何实现点击Android通知时弹出悬浮窗?
点击通知弹出悬浮窗的代码修改方案
核心思路
原代码通过PendingIntent.getActivity启动Activity,要实现悬浮窗,需改为启动后台服务,在服务中完成悬浮窗的创建(悬浮窗属于系统级窗口,不能直接在Activity启动逻辑里创建)。同时要处理不同Android版本的悬浮窗权限和窗口类型适配。
步骤1:添加悬浮窗权限与服务注册
在AndroidManifest.xml中声明权限并注册悬浮窗服务:
<!-- 悬浮窗权限 --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- Android 12+ 通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 注册悬浮窗服务 --> <service android:name=".FloatWindowService" android:exported="false" />
步骤2:修改通知的PendingIntent
将原代码中启动TwoActivity的逻辑,替换为启动悬浮窗服务的PendingIntent:
// 替换原Intent为启动FloatWindowService Intent intent2 = new Intent(MainActivity.this, FloatWindowService.class); intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // 使用getService获取PendingIntent,而非getActivity PendingIntent pendingIntent2 = PendingIntent.getService(MainActivity.this, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 以下原通知构建代码保留,仅绑定新的PendingIntent int notifyId = 001; NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Notification.Builder mbuilder = new Notification.Builder(MainActivity.this); mbuilder.setSmallIcon(R.drawable.icon); mbuilder.setContentTitle(_Title); mbuilder.setContentText(_Content); mbuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE); // 绑定悬浮窗服务的PendingIntent到通知 mbuilder.setContentIntent(pendingIntent2); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelId1 = "1"; String channelName1 = "channel1"; NotificationChannel channel = new NotificationChannel(channelId1, channelName1, NotificationManager.IMPORTANCE_DEFAULT); channel.enableLights(true); channel.setLightColor(Color.BLUE); channel.setShowBadge(true); channel.enableVibration(true); mbuilder.setChannelId(channelId1); if (mNotificationManager != null) { mNotificationManager.createNotificationChannel(channel); } } else { mbuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE); } if (mNotificationManager != null) { mNotificationManager.notify(notifyId, mbuilder.build()); }
步骤3:实现悬浮窗服务FloatWindowService
创建FloatWindowService类,在服务中完成悬浮窗的创建与权限检查:
public class FloatWindowService extends Service { private WindowManager mWindowManager; private View mFloatView; @Override public void onCreate() { super.onCreate(); mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); // 检查悬浮窗权限,无权限则停止服务 if (!checkFloatWindowPermission()) { stopSelf(); return; } // 加载悬浮窗布局(可替换为自定义布局) mFloatView = LayoutInflater.from(this).inflate(R.layout.float_window_layout, null); // 设置WindowManager参数,适配不同Android版本 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { params.type = WindowManager.LayoutParams.TYPE_PHONE; } params.format = PixelFormat.RGBA_8888; // 允许悬浮窗之外的区域接收触摸事件 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.gravity = Gravity.LEFT | Gravity.TOP; params.x = 100; params.y = 100; // 将悬浮窗添加到屏幕 mWindowManager.addView(mFloatView, params); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_NOT_STICKY; } @Override public void onDestroy() { super.onDestroy(); // 移除悬浮窗,避免内存泄漏 if (mFloatView != null && mWindowManager != null) { mWindowManager.removeView(mFloatView); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } // 检查悬浮窗权限(Android 6.0+ 需要动态授权) private boolean checkFloatWindowPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return Settings.canDrawOverlays(this); } return true; } }
步骤4:动态申请悬浮窗权限(Android 6.0+)
在MainActivity中添加权限检查逻辑,确保用户授予悬浮窗权限后再显示通知:
// 在需要显示通知的位置调用 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { // 跳转至权限设置页面 Intent permissionIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(permissionIntent, 1001); } else { // 权限已获取,构建并显示通知 buildAndShowNotification(); } } else { buildAndShowNotification(); } // 处理权限申请结果 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(this)) { buildAndShowNotification(); } else { Toast.makeText(this, "需要授予悬浮窗权限才能使用该功能", Toast.LENGTH_SHORT).show(); } } } } // 将步骤2中的通知构建代码封装为方法 private void buildAndShowNotification() { // 此处放步骤2的通知构建代码 }
内容的提问来源于stack exchange,提问作者My Account
相关产品推荐
相关产品推荐

