記一次懸浮窗的上線以及坑點總結

       剛剛發了一個大版本,終於有時間來總結一下技術點了,今天就來總結一下上個版本用到的懸浮窗吧,相似於微信公衆號文章裏的效果,能夠拖動能夠點擊,拖動之後根據拖動的位置顯示不一樣的懸浮窗圖片,具有左右自動吸頂效果,當前app不在前臺時會自動隱藏。目前已經順利上線,不少問題已經解決,線上並無出現大的問題。今天我想把本身此次使用懸浮窗的方法以及其中的坑點告訴你們,但願能對你們有所幫助,碰到問題也能夠一塊兒討論,歡迎小夥伴們一塊兒進步,come on快上車。android


       最開始接到懸浮窗的需求也是有點虛的,由於以前沒有作過這方面,只是據說過這個比較坑,等作完才發現這個是真的坑。廢話少說,直接進入主題,首先從我調研這個需求提及吧。遇到沒作過的需求,習慣性地去往github上搜索懸浮窗相關的第三方庫,但願能站在巨人的肩膀上。不出因此然,我找到了一個第三方git庫:github.com/yhaolpz/Flo…,我下載了demo跑了一遍,發現還不錯,支持滑動事件和點擊事件,能夠設置大小,能夠設置懸浮窗的顯隱。內心樂滋滋地準備往本身項目裏搬運,但是剛想搬的時候發現就不對勁了,咱們項目是在須要的時候再申請權限,而不是打開app就申請權限並顯示。因而我一通亂改,因爲對這一套不瞭解,改完發現越改越亂bug越多,心態已經崩了。這個時候忽然靈光一閃,先去issue裏找找看有沒有人碰到一樣的問題,果真是船到橋頭天然直,還真讓我找到了。有個大神碰到相同的問題而且已經解決了,fork了代碼而且進行了修改,這個git庫是:github.com/baneyue/Flo…,在此很是感謝前輩們的付出,站在巨人的肩膀上的感受就是如此奇妙,本身也要多出一些技術博客分享給別人,由於每一個人作的技術需求都不大相同,應用場景不同也會致使遇到的Bug不經相同,要取長補短,哈哈。git

       安卓的懸浮窗仍是比較坑的,最坑的是權限,其次沒有成熟的官方庫來作這個事情,致使不少開發者本身去作或多或少地都有不一樣的問題,再次懸浮窗是window,自己谷歌提供的api就很難使用,好比只能add不能replace,而且屢次add還會致使crash,這種奇葩的爲難開發者的設計真是毀三觀啊。吐槽完了活兒仍是得本身幹,這裏先給你們介紹一個第三方懸浮窗代碼的具體實現吧,代碼也比較簡單,可能我一貼出來你們一下就能看懂了。github

懸浮窗關鍵代碼解讀

1.如何申請權限

首先靜態申請一下api

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />複製代碼

而後爲了兼容高API,須要進行動態權限申請,這裏須要根據API版本以及廠商進行區分了。若是版本大於26使用TYPE_APPLICATION_OVERLAY的方式便可,不然使用TYPE_PHONE。其次通常6.0之前是不須要動態申請懸浮窗權限的,但小米是個特例,並且小米不一樣版本申請的方式可能還不同,在6.0以上申請方式和其餘手機同樣,可是6.0如下就不一樣了安全


小米6.0如下申請權限bash

小米6.0如下申請權限和小米MIUI版本有關,以下圖,須要對miui版本進行區分。具體的代碼是我直接用的上面那個第三方庫裏的,有須要的能夠去github上拉取直接用。微信



正常的申請流程,也就是6.0以上手機的申請流程是跳到一個本身封裝的空白權限申請界面,而後跳轉到系統自帶的懸浮窗申請界面進行權限申請,無論用戶給不給權限,都關閉當前空頁面。因爲系統不一樣,因此在不一樣手機上看到的權限申請頁面顏值可能就會不同。app


2.如何實現懸浮窗可隨手指拖動

思路很是簡單,監聽懸浮窗那個imageView的onTouchListener便可,在剛點擊的ACTION_DOWN事件中記錄當前的x,y位置,而後在每次移動後獲取到本次移動的位置,兩者相減就是須要移動的位置,這是自定義view的最基本操做了。動畫


3.如何實現懸浮窗左右邊的吸頂效果

思路也很是簡單,監聽到手指擡起的動做後,判斷當前位置是靠近左邊仍是右邊,靠近左邊就以位置動畫的方式平移到左邊,靠近右邊就平移到右邊。ui


4.核心,添加懸浮窗的方法

中規中矩,按照android官方的方式添加便可。即獲取系統的WindowManager,設置好參數,調用windowManager的addView()方法添加。須要注意的是,在隱藏懸浮窗的時候,最好是移除一下,下次須要顯示的時候再添加。



坑點一覽,滿滿的乾貨

坑點一  屢次添加view會致使crash

       這個是不少人都會碰到的,有時候沒辦法保證只添加一次,就算給了flag也會由於系統緣由致使這個flag不許確。因此我在使用的時候就碰到了屢次添加了的狀況,最後的結果就是crash,解決方案就是在addView方法上加一個try...catch捕獲住該異常,妥妥的安全感。


坑點二  oppo r9(5.1.1)上是有權限的,一直給返回沒權限

       這段代碼是處理6.0如下權限申請的,上面紅色部分是原來的代碼,下面綠色部分是改過以後的。因爲oppo在6.0如下每次檢測懸浮窗權限都給false,致使項目中每次都彈框讓用戶去給權限,最後乾脆就oppo 6.0如下直接默認都有權限好了。由於事實也如此,除了小米,其餘品牌6.0如下都是有權限的。


坑點三  如何處理輸入法和懸浮窗的層級關係

       微信裏的懸浮窗是在輸入法之下的,因此交互的同窗也要求我們的懸浮窗也要在輸入法之下。我查看了一下WindowManager源碼,我懸浮窗的優先級TYPE_APPLICATION_OVERLAY,上面大字寫着明明是在輸入法之下的,可是實際表現是在輸入法之上了。


       這個問題也是折騰了半天,在源碼裏找了半天找得是天昏地暗,終於功夫不負有心人,還真讓我找着了,windowManager是有一個flag專門用來設置懸浮窗和輸入法的關係的,可是因爲以前沒設置,因此致使最後默認的輸入法仍是在懸浮窗之下。


既然源頭找到了,設置起來就很簡單了,以下圖,設置好flag_alt_focusable_im這個flag便可。後面發現有一個帖子對flag總結得很是好,這裏也推薦給你們,有想了解其餘flag的同窗能夠去看一下這篇帖子:blog.csdn.net/qq_33275597…


坑點四  如何處理退出app或者按home鍵的時候關閉懸浮窗

       這也是谷歌坑人的地方,都沒地方設置這個懸浮窗是否只用到app內,因此默認在桌面上也會顯示本身的懸浮窗。好比在微信裏顯示其餘app的懸浮窗,這種糟糕的體驗可想而知,用戶不給你卸載就真是奇蹟了。爲了解決這個問題,最初的實現方式是對全部通過的activity進行記錄,顯示就加1,頁面被掛起就減1,若是減到當前計數爲0時說明全部頁面已經關閉了,就能夠隱藏懸浮窗了。


可是實際上這麼作仍是有問題的,在部分手機上若是是在首頁按返回鍵的話仍然不能隱藏,這個又是系統級的兼容性問題。爲了解決這問題,我後面又作了一個處理,經過註冊registerActivityLifecycleCallbacks監聽app的先後臺回調,檢測到若是當前首頁被銷燬時,應該將懸浮窗進行隱藏。


坑點五  屢次點擊懸浮窗之後,打開多個頁面

       若是你的懸浮窗點擊事件是打開頁面的話,這裏須要注意了,別忘了將這個打開的頁面的啓動模式設置爲singleTop或者是singleTask,從而複用同一個,遠離一直按返回的地獄操做。

android:launchMode="singleTop"複製代碼

android:launchMode="singleTask"複製代碼


總結:懸浮窗的坑,只有真正作過的人才懂,不過還好如今已經有不少現成的第三方代碼能夠CV。可是就算是CV了也不表明能夠高枕無憂,應用場景不一樣總仍是會遇到其餘的問題,我這裏總結了本身遇到的部分坑點,之後還有的話會繼續更新,我相信踩的坑越多,成長才會越快。我也但願本身的工做經歷可以幫助到你們少走彎路,就像我借鑑了前輩們的成果同樣。

       最後,我作好了一個最簡單的demo,有需求的小夥伴能夠去github下載,github地址:

github.com/dongrong-fu…

相關文章
相關標籤/搜索