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

如何实现点击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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 03:48:35