非侵入式無許可權應用內懸浮窗的實現

Windin發表於2018-08-12

前言

一般的懸浮窗實現方式,需要申請許可權,並還是要對部分機型進行適配才能正常顯示。那麼這裡,我們換一種思路,實現一個不一樣的懸浮窗。

一、應用內懸浮窗實現思路

通常的懸浮窗是通過WindowManager直接新增的,在不同的Android系統上需要做不同的適配,在Android6.0以上的機型上,還需要引導使用者跳轉到設定介面手動開啟懸浮窗許可權。雖然這樣實現懸浮窗有完整的解決方案,但是開啟懸浮窗過程對使用者並不是很友好。下面,我們換一種思路,去使用一個應用內懸浮窗,避免機型適配和許可權申請的坑,讓懸浮窗像普通的View一樣顯示在介面上。

一般懸浮窗的實現方案是向系統window新增typeTYPE_PHONE或者TYPE_TOASTView,從而使懸浮窗可以作為一個獨立的View進行展示。Android對這一行為作了限制,那我們可以考慮從比較常規的途徑新增View:向每一個展示介面,即Activity,新增一個View作為懸浮窗。這樣,我們使用懸浮窗時就可以避免適配和許可權問題。那麼,怎麼樣實現這樣的懸浮窗更好呢?

要實現這樣一個懸浮窗,相當於我們要在Activity載入完後將懸浮窗的View新增的Activity上,我們不想在原有的Activity上插入這段程式碼,這時就可以利用ActivityLifecycleCallbacksfragment的載入特性來完成一個無侵入式的懸浮窗的顯示。

非侵入式無許可權應用內懸浮窗的實現

二、應用內懸浮窗的實現

  1. 首先,我們先自定義一個View用於顯示懸浮窗介面,就叫它FloatingWindow。至於怎麼實現,這個各位可以自由發揮。
  2. 接下來,我們要把FloatingWindow新增到每一個Activity上,這時就利用ActivityLifecycleCallbacksActivity的每個生命週期都能回撥到ActivityLifecycleCallbacks,這時我們只要在onActivityCreated(Activity activity, Bundle savedInstanceState)中加上懸浮窗View。但是,onActivityCreated(Activity activity, Bundle savedInstanceState)方法是在onCreate(Bundle savedInstanceState)時被呼叫的,我們需要保證在setContentView()之後才新增懸浮窗,讓懸浮窗處於上層,所以我們插入一個空Fragment,利用FragmentonActivityCreated(Bundle savedInstanceState)是在ActivityonCreate(Bundle savedInstanceState)之後的特性來加入懸浮窗。
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        super.onActivityCreated(activity, savedInstanceState);

        if (activity instanceof FragmentActivity) {
            FragmentManager fm = ((FragmentActivity) activity).getSupportFragmentManager();
            fm.beginTransaction().add(new SupportFragment(), FRAGMENT_TAG).commitAllowingStateLoss();
        }
    }
    ...
});

public static class SupportFragment extends Fragment {

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Activity activity = getActivity();
        if (activity != null) {
            FloatingWindow fw = new FloatingWindow(activity);
            activity.addContentView(fw, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    }
}
複製程式碼

通過這幾行核心程式碼,我們便完成了一個不需要許可權申請的懸浮窗。細節一點的實現可以參考我的demo:github.com/windinwork/…

三、總結

像我們這樣的懸浮窗,有優點也有缺點。優點顯而易見,它不需要向系統申請特殊的許可權即可正常顯示;缺點的話即是每一個Activity都有一個懸浮窗,相互獨立存在,當然這個是可以優化一下實現方式解決的,這裡不細講,另一個缺點即是這樣的懸浮窗無法在應用退到後臺的時候存在,當然在在合適的應用場景這也不是問題。以上便是一個無侵入式無許可權的懸浮窗實現方式,希望能為小夥伴提供不同的懸浮窗實現思路。

相關文章