Android M及以上版本系統 懸浮窗許可權 的解決方案
阿新 • • 發佈:2018-12-19
Android M及以上版本系統 懸浮窗許可權 的解決方案
Android的視窗體系中,WindowManager佔有非常重要的地位,平時我們使用懸浮窗會遇到一些許可權的問題。
當 Android工程在targetSdkVersion 23
編譯,Android6.0及其以上版本手機使用懸浮窗功能時候,會發生如下的異常,導致程式崩潰。
java.lang.RuntimeException: Unable to create service
com.fb.tangyc.fbtools.service.FBService: android.view.WindowManager$BadTokenException:
Unable to add window [email protected]
-- permission denied for this window type
當Android工程在targetSdkVersion 22
編譯,Android6.0及其以上版本手機使用懸浮窗功能會正常使用
其實原因很簡單,大部分的Android6.0手機(尤其是三星,谷歌原生手機)
在大於等於23版本下編譯,懸浮窗許可權預設是關閉沒有許可權,然在小於23版本下編譯懸浮窗許可權是開啟有許可權的。
所以在大於23版本下編譯時需要去檢測懸浮窗許可權,並且獲取懸浮窗許可權,下面我就羅列下怎麼去檢測懸浮窗許可權並且獲取懸浮窗許可權
if ( Build.VERSION.SDK_INT> = 23 ) { if (Settings.canDrawOverlays(this)) { //有懸浮窗許可權開啟服務繫結 繫結許可權 Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent); } else { //沒有懸浮窗許可權m,去開啟懸浮窗許可權 try { Intent intent=new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); } catch (Exception e) { e.printStackTrace(); } } } else { // 預設有懸浮窗許可權 但是 華為, 小米,oppo 等手機會有自己的一套 Android6.0 以下 // 會有自己的一套懸浮窗許可權管理 也需要做適配 Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent); }
每次使用懸浮窗的時候都要去檢測許可權,因為懸浮窗許可權是可以手動關閉的。
位置位於 (三星S6為例Android6.0.1版本)設定-- 應用程式--應用程式管理器 -- 更多 --可出現在頂部的應用程式 --- 選擇你的APP -- 執行在其他應用的上層顯示
下圖所示:
當你點選懸浮窗許可權app開關時候 退出 會在activity 有回撥方法。
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { if(Build.VERSION.SDK_INT>=23) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "許可權授予失敗,無法開啟懸浮窗", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "許可權授予成功!", Toast.LENGTH_SHORT).show(); //有懸浮窗許可權開啟服務繫結 繫結許可權 Intent intent = new Intent(MainActivity.this, FBService.class); startService(intent); } } } }
下面就羅列下Service中啟動懸浮的實現
首先 你需要在配置檔案懸浮窗許可權
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
第二需要在服務中開啟懸浮窗
public class FBService extends Service {
private WindowManager wManager;// 視窗管理者
private WindowManager.LayoutParams mParams;// 視窗的屬性
private FloatButtonLayout windowView;
private SurfaceHolder holder;
public static final String *ACTION_ALPHA *= "com.fb.alpha";
private ServiceReceiver receiver;
@Override
public void onCreate() {
super.onCreate();
wManager = (WindowManager) getSystemService(Context.*WINDOW_SERVICE*);
mParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.*TYPE_SYSTEM_ERROR*, WindowManager.LayoutParams.*FLAG_NOT_FOCUSABLE*, PixelFormat.*TRANSPARENT*);
mParams.type = WindowManager.LayoutParams.*TYPE_SYSTEM_ERROR*;// 系統提示window
mParams.format = PixelFormat.*TRANSLUCENT*;// 支援透明
// mParams.format = PixelFormat.RGBA_8888;
mParams.flags |= WindowManager.LayoutParams.*FLAG_NOT_TOUCH_MODAL *| WindowManager.LayoutParams.*FLAG_NOT_FOCUSABLE*;// 焦點
mParams.width = WindowManager.LayoutParams.*WRAP_CONTENT*;// 視窗的寬和高
mParams.height = WindowManager.LayoutParams.*WRAP_CONTENT*;
mParams.gravity = Gravity.*LEFT *| Gravity.*TOP*;
mParams.y = SharedPreferencesUtils.*getSharedPreferencesUtils*().getParamsY(getApplicationContext());
mParams.x = SharedPreferencesUtils.*getSharedPreferencesUtils*().getParamsX(getApplicationContext());
mParams.windowAnimations = android.R.style.*Animation_Toast*;
// mParams.alpha = 0.8f;//視窗的透明度
LayoutInflater layoutInflater = LayoutInflater.*from*(getApplicationContext());
windowView = (FloatButtonLayout) layoutInflater.inflate(R.layout.*float_button_layout*, null);
wManager.addView(windowView, mParams);// 新增視窗
}
第三,關閉服務時候,關閉懸浮窗
@Override
public void onDestroy() {
if (wManager!=null&&windowView != null) {
wManager.removeView(windowView);
}
super.onDestroy();
}
這就是在Android下面開啟懸浮窗許可權的全部流程。