郭霖大神的文章:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650235949&idx=1&sn=0f7eded67f834d38b02f8872768cb68a&scene=0#wechat_redirect
今天周二,又該跟大家分享由我執筆的文章了。從之前我寫的deep links、通知欄微技巧這兩篇文章中,大家應該能明顯體會出什么叫短小精煉,但又很有技術價值的文章。后面我還會堅持分享這種類型的文章,盡量讓大家十分鐘內就可以讀完,并且還能有所收獲。
在Android上創建系統懸浮窗并不是什么新鮮技術,我的人生第一篇博客就是寫的關于如何實現類似于360手機衛士懸浮窗的功能,大家有興趣的可以到 http://guolin.tech 去翻翻歷史。不過如果你將項目的targetSdkVersion指定成23或者更高,你會發現之前創建懸浮窗的方式在Android 6.0系統上是無法運行的。不信的話我們就來試試。
首先建立一個非常非常簡單的自定義View:
public class FloatView extends Button { ? ?public FloatView(Context context) {super(context);setBackgroundResource(R.drawable.logo);}
}
然后在程序中調用如下代碼就可以創建出系統懸浮窗了:
public void showFloatView() {WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);FloatView floatView = new FloatView(getApplicationContext());WindowManager.LayoutParams params = new WindowManager.LayoutParams();params.type = WindowManager.LayoutParams.TYPE_PHONE;params.format = PixelFormat.RGBA_8888;params.gravity = Gravity.LEFT | Gravity.TOP;params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;params.width = 150;params.height = 150;params.x = 0;params.y = 0;windowManager.addView(floatView, params);
}
上面的代碼簡單易懂,就不再進行解釋了,如果對這部分代碼還不理解的朋友請去參考我的歷史第一篇博文好好學習一下。
最后還需要在AndroidManifest.xml中添加一個權限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
沒錯,就是這么簡單,現在這段代碼就已經可以成功創建出一個系統懸浮窗了,不過是在Android 6.0系統之前。
如果我們在6.0系統中運行上述代碼(注意targetSdkVersion要指定顧23),程序就會直接崩潰,錯誤日志如下圖所示:
咦?報了個權限被拒絕的錯誤,可是我們已經在AndroidManifest.xml中申請權限了,并且SYSTEM_ALERT_WINDOW權限也不是危險權限,并不需要進行運行時權限申請。
那么為什么在6.0系統上就會崩潰呢,我們來查看一下官方文檔的描述吧:
Note: If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen. The app requests the user's approval by sending an intent with action ACTION_MANAGE_OVERLAY_PERMISSION. The app can check whether it has this authorization by calling Settings.canDrawOverlays().
能夠熟練閱讀各類英文文檔也是一門非常重要的技能。上面的描述大概意思就是說,如果我們的targetSdkVersion指定成了23或者更高,在使用SYSTEM_ALERT_WINDOW權限時,需要先調用Settings.canDrawOverlays()來判斷一下是否允許創建懸浮窗,如果允許的話就可以創建了,不允許的話還要發送一個action值為ACTION_MANAGE_OVERLAY_PERMISSION的Intent來讓用戶同意創建懸浮窗。
針對文檔的描述,我們需要將代碼改成下面這個樣子:
public void buttonClick(View view) {if (Build.VERSION.SDK_INT >= 23) {if (Settings.canDrawOverlays(context)) {showFloatView();} else {Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);startActivity(intent);}} else {showFloatView();}
}
首先最外層先判斷當前的系統版本,如果低于6.0的話那就直接創建懸浮窗就可以了。當系統是6.0或者更高的時候,我們就使用剛才文檔中描述的流程來進行邏輯實現,現在運行一下代碼,效果如下圖所示: