java关闭悬浮窗,Android8.0通知栏和悬浮窗新改动

Android8.0通知栏和悬浮窗新改动

通知栏

Android8.0新引入了Notification Channels(Notification Channels),以提供统一的系统来帮助用户管理通知,如果使用的8.0系统,必须调用Notification.Builder.setChannelId(String channelId)来设置渠道id。

具体可以参考Android O Preview 之 通知渠道

设置ChannelId的具体代码(Android8.0下不需要设置这个ChannelId)

// 通知渠道的id

String id = "my_channel_01";

// 用户可以看到的通知渠道的名字.

CharSequence name = getString(R.string.channel_name);

// 用户可以看到的通知渠道的描述

String description = getString(R.string.channel_description);

int importance = NotificationManager.IMPORTANCE_HIGH;

//注意Name和description不能为null或者""

NotificationChannel mChannel = new NotificationChannel(id, name, importance);

// 配置通知渠道的属性

mChannel.setDescription(description);

// 设置通知出现时的闪灯(如果 android 设备支持的话)

mChannel.enableLights(true);

mChannel.setLightColor(Color.RED);

// 设置通知出现时的震动(如果 android 设备支持的话)

mChannel.enableVibration(true);

mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

//最后在notificationmanager中创建该通知渠道 notificationManager.createNotificationChannel(mChannel);

builder.setChannelId(id);

展示一个简单的通知栏的完整代码:

NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

Notification.Builder builder = new Notification.Builder(this.getApplicationContext());

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

// 通知渠道的id

String id = "my_channel_01";

// 用户可以看到的通知渠道的名字.

CharSequence name = getString(R.string.channel_name);

// 用户可以看到的通知渠道的描述

String description = getString(R.string.channel_description);

int importance = NotificationManager.IMPORTANCE_HIGH;

//注意Name和description不能为null或者""

NotificationChannel mChannel = new NotificationChannel(id, name, importance);

// 配置通知渠道的属性

mChannel.setDescription(description);

// 设置通知出现时的闪灯(如果 android 设备支持的话)

mChannel.enableLights(false);

mChannel.setLightColor(Color.RED);

// 设置通知出现时的震动(如果 android 设备支持的话)

mChannel.enableVibration(false);

mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

//最后在notificationmanager中创建该通知渠道

notificationManager.createNotificationChannel(mChannel);

builder.setChannelId(id);

}

builder.setContentInfo("补充内容");

builder.setContentText("通知标题");

builder.setContentTitle("通知内容");

builder.setSmallIcon(R.mipmap.icon);

builder.setTicker("新消息");

builder.setAutoCancel(true);

builder.setWhen(System.currentTimeMillis());

Intent intent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);

builder.setContentIntent(pendingIntent);

Notification notification = builder.build();

notificationManager.notify(1, notification);

悬浮窗

如果你的项目targetSdkVersion是在23及以上,在Android6.0以上的手机想要实现悬浮窗这个功能就必须要加入android.permission.SYSTEM_ALERT_WINDOW这个权限,并且通过Android6.0后提供的权限申请方法来申请权限成功后再实现悬浮窗功能。当然国产某些Rom也会导致虽然targetSdkVersion低于23或者系统低于6.0,但还是需要SYSTEM_ALERT_WINDOW权限才能调用悬浮窗。

这里我就不详讲低于Android8.0的手机怎么去申请悬浮窗权限了,大家可以参考下Android悬浮窗权限适配来实现悬浮窗的权限适配。

相信的大家在完成上述权限适配后会发现基本在各种手机都会运行都能顺利申请到悬浮窗权限并且展示自己的悬浮窗,但却在8.0上发现运行悬浮窗会报出以下的Crash:

// xxxx为你选择WindowManager.LayoutParams()的 mParams.type具体参数

W/System.err: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b5ad7ed -- permission denied for window type xxxx

W/System.err: at android.view.ViewRootImpl.setView(ViewRootImpl.java:788)

W/System.err: at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)

W/System.err: at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:92)

...

为什么明明权限已经申请成功,在低版本的手机上会运行的好好的,在Android8.0上会这样呢?

原来是因为8.0新增了一些行为变更Android 8.0 行为变更,对悬浮窗进行了一些限制:

提醒窗口

使用 SYSTEM_ALERT_WINDOW 权限的应用无法再使用以下窗口类型来在其他应用和系统窗口上方显示提醒窗口:

使用 TYPE_APPLICATION_OVERLAY 窗口类型显示应用的提醒窗口时,请记住新窗口类型的以下特性:

应用的提醒窗口始终显示在状态栏和输入法等关键系统窗口的下面。

系统可以移动使用 TYPE_APPLICATION_OVERLAY 窗口类型的窗口或调整其大小,以改善屏幕显示效果。

通过打开通知栏,用户可以访问设置来阻止应用显示使用 TYPE_APPLICATION_OVERLAY 窗口类型显示的提醒窗口。

所以我们只需要在为WindowManager.LayoutParams()设置type的时候改为:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

} else {

//xxxx为你原来给低版本设置的Type

mParams.type = WindowManager.LayoutParams.xxxx;

}

这样就可以适配到8.0的手机上使用悬浮窗功能啦~

具体详细原理在日后有时间再补上,目前先写到这里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的悬浮示例代码,可以在Android应用中使用: ``` public class FloatingWindowService extends Service { private WindowManager mWindowManager; private View mFloatingView; public FloatingWindowService() { } @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { super.onCreate(); // 初始化悬浮视图 mFloatingView = LayoutInflater.from(this).inflate(R.layout.floating_window_layout, null); // 设置悬浮参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); // 设置悬浮位置 params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 100; // 添加悬浮视图到口管理器 mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mWindowManager.addView(mFloatingView, params); // 设置悬浮视图事件监听 mFloatingView.setOnTouchListener(new View.OnTouchListener() { private int initialX; private int initialY; private float initialTouchX; private float initialTouchY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 记录初始位置和触摸点位置 initialX = params.x; initialY = params.y; initialTouchX = event.getRawX(); initialTouchY = event.getRawY(); return true; case MotionEvent.ACTION_UP: // 如果移动距离很小,则视为单击事件,执行相应操作 if (Math.abs(event.getRawX() - initialTouchX) < 5 && Math.abs(event.getRawY() - initialTouchY) < 5) { // TODO 执行单击事件 } return true; case MotionEvent.ACTION_MOVE: // 计算移动距离并更悬浮位置 params.x = initialX + (int) (event.getRawX() - initialTouchX); params.y = initialY + (int) (event.getRawY() - initialTouchY); mWindowManager.updateViewLayout(mFloatingView, params); return true; } return false; } }); } @Override public void onDestroy() { super.onDestroy(); // 从口管理器中移除悬浮视图 if (mFloatingView != null) { mWindowManager.removeView(mFloatingView); } } } ``` 在上述代码中,首先定义了一个`FloatingWindowService`服务类,该类继承自`Service`,并实现了`onCreate()`、`onStartCommand()`和`onDestroy()`方法。在`onCreate()`方法中,初始化了悬浮视图,并设置了悬浮参数和位置,然后将悬浮视图添加到口管理器中。同时,也设置了悬浮视图的事件监听,以便实现拖拽和单击操作。 在`onDestroy()`方法中,从口管理器中移除了悬浮视图。 需要注意的是,为了在Android 8.0及以上版本中显示悬浮,需要使用`WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY`类型的口。此外,还需要在应用的`AndroidManifest.xml`文件中添加`<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />`权限声明。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值