1. 程式人生 > >android開發中懸浮窗被禁用,無許可權開啟懸浮窗的解決方案

android開發中懸浮窗被禁用,無許可權開啟懸浮窗的解決方案

首先,感謝這兩篇博文http://blog.csdn.net/cankingapp/article/details/51569576
http://blog.csdn.net/cool_fuwei/article/details/53070232
瞭解知識:
1.首先要知道6.0版本許可權模型跟原來版本是不同的,不再是統一在manifest中預設系統授權,而是有需要的時候,向系統請求授權,提高使用者體驗。
2.瞭解許可權檢測流程,一點注意點是如果系統許可權彈窗提示框被不再提醒了,需要我們自定義提示彈窗,引導使用者去授權。
3.明白許可權型別,分為normal和dangerous型別,同時,在dangerous中還需要注意一點,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS這兩個特殊授權請求方式,跟一般授權請求方式不同。
4.在判斷APP是否執行在Android M上,可以用版本號來判斷,可以準確點。

問題一:在安卓開發中處理懸浮窗許可權時,發現魅族和小米手機無論android4.4.4、android5.1.1還是android6.0,許可權manifest中:android.permission.SYSTEM_ALERT_WINDOW許可權也加過了,就是彈不起。這個許可權也不是android 6.0中的敏感許可權,所以android 6.0動態申請許可權也是行不通的,這個問題很難通過diamante開啟懸浮窗,沒轍之後想到,呼叫應用的設定介面引導使用者去手動的開啟。

問題二:在三星6.0或android6.0及android 6.0以上的手機(小米和魅族處理方式另外處理同上),未處理彈窗問題可能會引發以下問題,

android.view.WindowManager$BadTokenException: Unable to add window 

android.view.ViewRootImpl[email protected] -- permission denied for this window type


 at android.view.ViewRootImpl.setView(ViewRootImpl.java:879)


 at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:337)


 at android.view
.WindowManagerImpl.addView(WindowManagerImpl.java:91) at android.app.Dialog.show(Dialog.java:350)

話不多說,直接上程式碼處理以上兩個疑問。

 @Override
    public void onClick(View view) {
        String user = edit_user.getText().toString();
        String pwd = edit_pwd.getText().toString();
        if (user.equals("123") && pwd.equals("123")) {
            editor = pref.edit();
            editor.putString("user", user);
            editor.putString("pwd", pwd);
            editor.commit();
            //開啟懸浮窗前先請求許可權
            if ("Xiaomi".equals(Build.MANUFACTURER)) {//小米手機
                LogUtil.E("小米手機");
                requestPermission();
            } else if ("Meizu".equals(Build.MANUFACTURER)) {//魅族手機
                LogUtil.E("魅族手機");
                requestPermission();
            } else {//其他手機
                LogUtil.E("其他手機");
                if (Build.VERSION.SDK_INT >= 23) {
                    if (!Settings.canDrawOverlays(this)) {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                        startActivityForResult(intent, 12);
                    } else {
                        switchActivity();
                    }
                } else {
                    switchActivity();
                }
            }
        } else {
            ToastUtil.show(this, "這麼簡單都出錯,腦子呢?");
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 11) {
            if (isFloatWindowOpAllowed(this)) {//已經開啟
                switchActivity();
            } else {
                ToastUtil.show(this, "開啟懸浮窗失敗");
            }
        } else if (requestCode == 12) {
            if (Build.VERSION.SDK_INT >= 23) {
                if (!Settings.canDrawOverlays(LoginActivity.this)) {
                    ToastUtil.show(this, "許可權授予失敗,無法開啟懸浮窗");
                } else {
                    switchActivity();
                }
            }
        }

    }

    /**
     * 跳轉Activity
     */
    private void switchActivity() {
        startActivity(new Intent(LoginActivity.this, Main2Activity.class));
        ToastUtil.show(LoginActivity.this, "吆,竟然蒙對了!");
        finish();
    }

    /**
     * 判斷懸浮窗許可權
     *
     * @param context
     * @return
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean isFloatWindowOpAllowed(Context context) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= 19) {
            return checkOp(context, 24);  // AppOpsManager.OP_SYSTEM_ALERT_WINDOW
        } else {
            if ((context.getApplicationInfo().flags & 1 << 27) == 1 << 27) {
                return true;
            } else {
                return false;
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean checkOp(Context context, int op) {
        final int version = Build.VERSION.SDK_INT;

        if (version >= 19) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {
                Class<?> spClazz = Class.forName(manager.getClass().getName());
                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
                int property = (Integer) method.invoke(manager, op,
                        Binder.getCallingUid(), context.getPackageName());
                Log.e("399", " property: " + property);

                if (AppOpsManager.MODE_ALLOWED == property) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.e("399", "Below API 19 cannot invoke!");
        }
        return false;
    }


    /**
     * 請求使用者給予懸浮窗的許可權
     */
    public void requestPermission() {
        if (isFloatWindowOpAllowed(this)) {//已經開啟
            switchActivity();
        } else {
            openSetting();
        }
    }


    /**
     * 開啟許可權設定介面
     */
    public void openSetting() {
        try {
            Intent localIntent = new Intent(
                    "miui.intent.action.APP_PERM_EDITOR");
            localIntent.setClassName("com.miui.securitycenter",
                    "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            localIntent.putExtra("extra_pkgname", getPackageName());
            startActivityForResult(localIntent, 11);
            LogUtil.E("啟動小米懸浮窗設定介面");
        } catch (ActivityNotFoundException localActivityNotFoundException) {
            Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", getPackageName(), null);
            intent1.setData(uri);
            startActivityForResult(intent1, 11);
            LogUtil.E("啟動懸浮窗介面");
        }

    }

相關推薦

android開發懸浮禁用許可權開啟懸浮解決方案

首先,感謝這兩篇博文http://blog.csdn.net/cankingapp/article/details/51569576 http://blog.csdn.net/cool_fuwei/article/details/53070232 瞭解知識:

Android6.0(Android M) 懸浮禁用許可權開啟懸浮解決方案

最近需要在Android6.0的機子上實現一個懸浮窗的功能,發現6.0之前的機子都能使用懸浮窗,但是唯獨6.0版本不行,以下我是查到的相關資料,挺有意思的,順帶說一下: 國內查,所有的新聞統一都說是谷歌有意禁止該功能(預設關閉),且說不會妥協去修改,僅此而已,未找到相關的開

android開發RadioGroup動態新增元件的時候checkedId自動累加的解決方案

radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedCh

Android開發的SQLite事務處理即beginTransaction()方法

使用SQLiteDatabase的beginTransaction()方法可以開啟一個事務,程式執行到endTransaction() 方法時會檢查事務的標誌是否為成功,如果程式執行到endTransaction()之前呼叫了setTransactionSuccessful() 

關於Android開發實現錨點技術也是焦點的改變

        今天朋友問了我一個問題,他的需求是點選listview的item跳轉到另一個listview中,由於需要跳轉的操作比較多,他想在一個佈局中實現,我給他一個建議就是做控制元件焦點的切換,

Android開發資料庫(sqlite)的檢視及一些問題的解決方法

最近在學習Android中的Sqlite遇到一些問題,這裡做一下總結。 一、建立資料庫 首先你要新建一個使用Sqlite的APP,開發工具Ecplise、AndroidStudio都可,這裡以後者AS為例。如果你沒有現成的程式,可以用博主的這個、 檔名

【轉】SQL2008的sa賬戶禁用其他賬戶無法連線的解決方法

百度知道上搜來的,不過答案好像也是CSDN的。但我沒有找到地址,先貼出來方法備忘,侵刪。 或者你還有其它的sysadmin許可權的賬號,你可以用此賬號登入,重置SA密碼。 但是在以下情況下,怎麼辦呢? 1. SA密碼丟失或者SA賬號被禁用。 2. 你進行了一些安全操作,把B

Qt 執行cmd命令失敗許可權需要提升程式以管理員執行 vs2013設定

程式中有些 地方 需要執行windows cmd 命令, 如 taskkill 程序命令 (QString c = "taskkill /im osk.exe /f";m_pProcess->execute(c);)  這種 命令是需要管理員身份的, 因此程式必須以管理員身份執行

Windows7 64位系統,讀取登錄檔檔案路勁重定位解決方案

在Windows7 64位系統中,讀取登錄檔,檔案路勁會進行重定位。以下是解決辦法: //第一步:定義巨集 #define KEY_WOW64_64KEY (0x0100) //支援讀寫64位登錄檔

sudoers檔案更改錯誤root許可權無法使用的解決方案

/etc/sudoers: syntax error near line sudo: parse error in /etc/sudoers near line 25 sudo: no valid sudoers sources found, quitting 終極解決方案

Android開發Fragment巢狀Fragments遇到的問題

Fragment,簡稱碎片,是Android 3.0(API11)提出的,為了相容低版本,support-v4庫中也開發了一套Fragment API,最低相容Android 1.6。 Fragment是依賴於Activity的,不能獨立存在的。 一個Acti

Android開發使用 EditText 輸入內容如何進行一鍵清空內容處理

本文僅為個人的處理方式,希望能對您有所幫助,歡迎各位留言指正,抱拳了 1、text.xml示例: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://s

Android開發有哪些讓你覺得相見恨晚的方法、類或介面

1、Throwable介面中的getStackTrace()方法(或者Thread類的getStackTrace()方法),根據這個方法可以得到函式的逐層呼叫地址,其返回值為StackTraceElement[]; 2、StackTraceElement類,其中四個方法getClassName(),getFi

啟動虛擬機器會有錯誤報告:二進位制轉換與此平臺上的長模式不相容。此虛擬環境的長模式將禁用因此需要使用長模式的應用程式將無法正常執行

1.先安裝VMware2.常建立虛擬機器3.啟動虛擬機器,啟動會有:二進位制轉換與此平臺上的長模式不相容。此虛擬環境中的長模式將被禁用,因此需要使用長模式的應用程式將無法正常執行  解決辦法:需要開啟BIOS系統把  Intel  Virtual Technology 改為e

android開發遇到的進位制轉換16進位制資料流轉和字串的相互轉換

最近開發的程式是利用無線網路,收發資料,其中,接收和傳送的格式是16進位制位元組陣列 byte[],而顯示到介面中則不可能把一堆的位元組流顯示出來。因此,需要進行一下轉換。  直接說轉換的演算法吧        一、16進位制位元組陣列轉換成字串 核心的語句就一句getSt

Android開發dialog的實現方式

在Android開發中,我們經常會需要在Android介面上彈出一些對話方塊,比如詢問使用者或者讓使用者選擇。這些功能我們叫它Android Dialog對話方塊,在我們使用Android的過程中,我歸納了一下,Android Dialog的型別無非也就7種,下面我分別向

Android開發佈局與元件(一)—— 螢幕尺寸單位dppxsp的探究

在Android開發中,常用的尺寸單位有 dp , px , sp 。當然還有其他的單位如 pt , mm 等,不過這些都是不常用,所以我們重點來探究一下 dp , px , sp 這三個常用的單位。 px 英文 pixel 的縮寫,即畫素。無論螢幕密度為多少,一個畫素單位對應

Android開發 十進位制十六進位制的相互轉化

最近的開發 Android專案中要實現使用者自定義顏色,於是就自己利用 SeekBar 和 EditText 實現了一個拾色器。 原理也很簡單,就是用四個SeekBar 分別代表顏色的四個值:R,G,B,Alpha,每個顏色值都用0-255來表示,最終在轉化為十六進位制顏色值。 但是

Android學習筆記 —— Android 開發限制 EditText 輸入框不能輸入中文(漢字)

今天在練習開發一個小專案的時候,需要限制 EditText 輸入框不能輸入中文(漢字),在網上找了很多例子,  結合自己的實際,終於完成了這一功能。現在把程式碼記錄下來,方便以後查詢! 首先是xml佈

Android開發一些冷落但卻很有用的類和方法

來自:http://luckyandyzhang.github.io/ Resources.getIdentifier : 這個我 用過,記得以前做過一個面板切換功能,可以通過這個方法從面板包 獲取面板資源。 (面板包的資源名稱和 主包的資源名稱id 名是一樣的