懸浮窗設置TYPE_TOAST出現崩潰的解決方案

關於懸浮窗設置TYPE_TOAST崩潰的問題

  • 最近在做項目有用到懸浮窗,發現了一個問題,WindowManager.LayoutParams的屬性設置爲TYPE_TOAST在安卓7.1.1系統出現崩潰。在使用Type Toast懸浮窗的同時,使用了Toast,必現崩潰,即使catch 了Throwable也無法解決,但是假如什麼都沒做則不會崩潰,不過幾秒後就消失了

查了一下資料發現在安卓7.1.1的系統上谷歌限制了開發者對TYPE_TOAST的濫用
這裏寫圖片描述
google在該版本開始對TYPE TOAST進行管控,防止一個應用的懸浮窗一直懸浮在另一個應用上造成干擾

// If adding a toast requires a token for this app we always schedule hiding
            // toast windows to make sure they don't stick around longer then necessary.
            // We hide instead of remove such windows as apps aren't prepared to handle
            // windows being removed under them.
            //
            // If the app is older it can add toasts without a token and hence overlay
            // other apps. To be maximally compatible with these apps we will hide the
            // window after the toast timeout only if the focused window is from another
            // UID, otherwise we allow unlimited duration. When a UID looses focus we
            // schedule hiding all of its toast windows.
            if (type == TYPE_TOAST) {
                if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                }
                // Make sure this happens before we moved focus as one can make the
                // toast focusable to force it not being hidden after the timeout.
                // Focusable toasts are always timed out to prevent a focused app to
                // show a focusable toasts while it has focus which will be kept on
                // the screen after the activity goes away.
                if (addToastWindowRequiresToken
                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
                        || mCurrentFocus == null
                        || mCurrentFocus.mOwnerUid != callingUid) {
                    mH.sendMessageDelayed(
                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
                            win.mAttrs.hideTimeoutMilliseconds);
                }
            }

從源碼可以看出假如添加了TYPE_TOAST,則顯示,並且設置了延遲消息,延遲時間爲hideTimeoutMilliseconds

時間到了則強制隱藏

case WINDOW_HIDE_TIMEOUT:{
   final windowState window = (WindowState)msg.obj;
   synchronized(mWindowMap){
       window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
       window.hidePermanentlyLw();
       window.setDisplayLayoutNeeded();
       mWindowPlacerLocked.performSurfacePlacement();
          }
}
break;

時間到了強制隱藏~

我這裏解決的方案是判斷系統,如果大於7.0的話則使用TYPE_SYSTEM_ALERT來顯示

   //設置type,系統提示型窗口,在應用程序之上
            if (FloatPermissionChecker.checkSDKVersion()) {
                mParmas!!.type = WindowManager.LayoutParams.TYPE_TOAST
            } else {
                mParmas!!.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
            }

這樣的話就需要手動去開啓設置裏面的懸浮窗開關,我們代碼裏面可以這麼寫去引導用戶打開懸浮窗

     val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
     //這句是重點,可以調到對應的應用界面裏
     intent.data = Uri.parse("package:" + context.activity!!.packageName)
     context.startActivityForResult(intent, DeveloperComponent.PERMISSION_REQUEST, null, listener)

然後通過Settings.canDrawOverlays(application)來判斷應用是否授權了懸浮窗顯示權限。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章