Android:檢查通知權(quán)限并跳轉(zhuǎn)到通知設(shè)置界面

聲明:該方案只對(duì)API19及以上版本有效

一、目標(biāo)需求

最近項(xiàng)目中在完善推送功能,需要進(jìn)入APP時(shí)檢測(cè)一下是否開啟了推送權(quán)限,如果沒有開啟彈窗提醒,當(dāng)用戶點(diǎn)擊彈窗時(shí)直接跳轉(zhuǎn)到APP的通知設(shè)置界面,就像下面這種:

就是這種效果

二、需求實(shí)現(xiàn)

1、檢測(cè)是否開啟通知權(quán)限

接到需求時(shí)一臉懵,不知道咋實(shí)現(xiàn),先是一番搜索,搜索后得知可以通過NotificationManagerCompat 中的 areNotificationsEnabled()來判斷是否開啟通知權(quán)限。

查閱官方文檔可知 NotificationManagerCompatandroid.support.v4.app包中,是API 22.1.0 中加入的。而 areNotificationsEnabled()則是在 API 24.1.0之后加入的。

注意:

areNotificationsEnabled 只對(duì) API 19 及以上版本有效,低于API 19 會(huì)一直返回true

2、跳轉(zhuǎn)到通知設(shè)置界面

假設(shè)沒有開啟通知權(quán)限,點(diǎn)擊之后就需要跳轉(zhuǎn)到 APP的通知設(shè)置界面,對(duì)應(yīng)的Action是:Settings.ACTION_APP_NOTIFICATION_SETTINGS, 這個(gè)Action是 API 26 后增加的。APP的通知設(shè)置界面如下圖:

APP的通知設(shè)置界面

如果在部分手機(jī)中無法精確的跳轉(zhuǎn)到 APP對(duì)應(yīng)的通知設(shè)置界面,那么我們就考慮直接跳轉(zhuǎn)到 APP信息界面,對(duì)應(yīng)的Action是:Settings.ACTION_APPLICATION_DETAILS_SETTINGS。APP信息界面如下圖:

APP信息界面

3、代碼實(shí)現(xiàn):

不多說了,代碼其實(shí)很簡(jiǎn)單,注釋也很明了,直接上代碼:

(1)、java版(使用了DataBinding-數(shù)據(jù)綁定)


/**
 * 作者:CnPeng
 * 時(shí)間:2018/7/11
 * 功用:檢測(cè)在設(shè)置中是否開啟了APP的推送
 * 其他:
 *
 * 參考鏈接:
 * https://stackoverflow.com/questions/32366649/any-way-to-link-to-the-android-notification-settings-for-my-app
 * https://blog.csdn.net/ysy950803/article/details/71910806
 * https://juejin.im/post/5a2508656fb9a0450407b638
 */
public class CheckNotifyActivity extends AppCompatActivity {
    ActivityCheckNotifyBinding mBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_check_notify);
        initClickListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkNotifySetting();
    }

    /**
     * 作者:CnPeng
     * 時(shí)間:2018/7/12 上午8:02
     * 功用:初始化點(diǎn)擊事件
     * 說明:
     */
    private void initClickListener() {
        //CnPeng 2018/7/12 上午7:08 跳轉(zhuǎn)到通知設(shè)置界面
        mBinding.tvMsg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    // 根據(jù)isOpened結(jié)果,判斷是否需要提醒用戶跳轉(zhuǎn)AppInfo頁面,去打開App通知權(quán)限
                    Intent intent = new Intent();
                    intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
                    //這種方案適用于 API 26, 即8.0(含8.0)以上可以用
                    intent.putExtra(EXTRA_APP_PACKAGE, getPackageName());
                    intent.putExtra(EXTRA_CHANNEL_ID, getApplicationInfo().uid);

                    //這種方案適用于 API21——25,即 5.0——7.1 之間的版本可以使用
                    intent.putExtra("app_package", getPackageName());
                    intent.putExtra("app_uid", getApplicationInfo().uid);

                    // 小米6 -MIUI9.6-8.0.0系統(tǒng),是個(gè)特例,通知設(shè)置界面只能控制"允許使用通知圓點(diǎn)"——然而這個(gè)玩意并沒有卵用,我想對(duì)雷布斯說:I'm not ok!!!
                    //  if ("MI 6".equals(Build.MODEL)) {
                    //      intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    //      Uri uri = Uri.fromParts("package", getPackageName(), null);
                    //      intent.setData(uri);
                    //      // intent.setAction("com.android.settings/.SubSettings");
                    //  }
                    startActivity(intent);
                } catch (Exception e) {
                    e.printStackTrace();
                    // 出現(xiàn)異常則跳轉(zhuǎn)到應(yīng)用設(shè)置界面:錘子堅(jiān)果3——OC105 API25
                    Intent intent = new Intent();

                    //下面這種方案是直接跳轉(zhuǎn)到當(dāng)前應(yīng)用的設(shè)置界面。
                    //https://blog.csdn.net/ysy950803/article/details/71910806
                    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    Uri uri = Uri.fromParts("package", getPackageName(), null);
                    intent.setData(uri);
                    startActivity(intent);
                }
            }
        });
    }

    /**
     * 作者:CnPeng
     * 時(shí)間:2018/7/12 上午9:02
     * 功用:檢查是否已經(jīng)開啟了通知權(quán)限
     * 說明:
     */
    private void checkNotifySetting() {
        NotificationManagerCompat manager = NotificationManagerCompat.from(this);
        // areNotificationsEnabled方法的有效性官方只最低支持到API 19,低于19的仍可調(diào)用此方法不過只會(huì)返回true,即默認(rèn)為用戶已經(jīng)開啟了通知。
        boolean isOpened = manager.areNotificationsEnabled();

        if (isOpened) {
            mBinding.tvMsg.setText("通知權(quán)限已經(jīng)被打開" +
                    "\n手機(jī)型號(hào):" + android.os.Build.MODEL +
                    "\nSDK版本:" + android.os.Build.VERSION.SDK +
                    "\n系統(tǒng)版本:" + android.os.Build.VERSION.RELEASE +
                    "\n軟件包名:" + getPackageName());

        } else {
            mBinding.tvMsg.setText("還沒有開啟通知權(quán)限,點(diǎn)擊去開啟");
        }
    }
}

(2)、kotlin版

/**
 * 作者:CnPeng
 * 時(shí)間:2018/7/12
 * 功用:檢查通知推送是否已經(jīng)被打開
 * 其他:
 */
public class PushCheckActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_push_check)

        initClickListener()
    }

    override fun onResume() {
        super.onResume()
        checkPushSwitchStatus()
    }

    /**
     * 作者:CnPeng
     * 時(shí)間:2018/7/12 下午3:43
     * 功用:檢查通知推送的開關(guān)狀態(tài)
     * 說明:
     */
    private fun checkPushSwitchStatus() {
        val notificationManager: NotificationManagerCompat = NotificationManagerCompat.from(this);
        val isOpend = notificationManager.areNotificationsEnabled()
        if (isOpend) {
            tv_msg.text = "通知權(quán)限已經(jīng)被打開" +
                    "\n手機(jī)型號(hào):${android.os.Build.MODEL}" +
                    "\nSDK版本:${android.os.Build.VERSION.SDK_INT}" +
                    "\n系統(tǒng)版本:${android.os.Build.VERSION.RELEASE}" +
                    "\n軟件包名:${getPackageName()}"
        } else {
            tv_msg.text = "通知權(quán)限沒有被開啟,點(diǎn)擊去開啟"
        }

    }

    private fun initClickListener() {
        tv_msg.setOnClickListener {
            val intent: Intent = Intent()
            try {
                intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS

                //8.0及以后版本使用這兩個(gè)extra.  >=API 26
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
                intent.putExtra(Settings.EXTRA_CHANNEL_ID, applicationInfo.uid)

                //5.0-7.1 使用這兩個(gè)extra.  <= API 25, >=API 21
                intent.putExtra("app_package", packageName)
                intent.putExtra("app_uid", applicationInfo.uid)

                startActivity(intent)
            } catch (e: Exception) {
                e.printStackTrace()

                //其他低版本或者異常情況,走該節(jié)點(diǎn)。進(jìn)入APP設(shè)置界面
                intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                intent.putExtra("package", packageName)

                //val uri = Uri.fromParts("package", packageName, null)
                //intent.data = uri
                startActivity(intent)
            }
        }
    }
}

4、踩坑記錄

A: com.android.support包的版本

因?yàn)?NotificationManagerCompat 是 22.1.0才有的,其中的 areNotificaitonEnabled() 是 24.1.0 才有的,Settings.ACTION_APP_NOTIFICATION_SETTINGS 是 26 才有的,所以,為了保證這些內(nèi)容在不同版本中生效,最好在 gradle文件中 support 的版本升級(jí)到最新。如:

implementation 'com.android.support:appcompat-v7:27.1.1'

B: 部分國(guó)產(chǎn)手機(jī)中沒有APP通知設(shè)置頁面

在部分國(guó)產(chǎn)手機(jī)系統(tǒng)中,Settings.ACTION_APPLICATION_DETAILS_SETTINGS對(duì)應(yīng)的Activity是不存在的,比如:錘子堅(jiān)果3——OC105 API25。

所以,在堅(jiān)果3手機(jī)上,最終會(huì)走我們代碼中的 catch 節(jié)點(diǎn),然后進(jìn)入到 應(yīng)用信息界面。

下面兩張圖分別是 錘子堅(jiān)果3 手機(jī)的截圖。第一張是 設(shè)置--通知中心的界面,點(diǎn)擊之后只是一個(gè)開關(guān)的開啟和關(guān)閉,并沒有再進(jìn)入詳細(xì)的通知設(shè)置界面。第二張是 應(yīng)用管理--應(yīng)用程序管理--應(yīng)用信息界面, 點(diǎn)擊其中的 允許推送通知時(shí)也只是開關(guān)的開啟和關(guān)閉。

設(shè)置--通知中心
應(yīng)用信息
C: 部分國(guó)產(chǎn)手機(jī) APP通知設(shè)置界面中沒有開啟和關(guān)閉的操作

部分國(guó)產(chǎn)手機(jī)中 Settings.ACTION_APPLICATION_DETAILS_SETTINGS對(duì)應(yīng)的Activity并不是我們期望的通知設(shè)置界面。比如,小米6。小米6中 Settings.ACTION_APPLICATION_DETAILS_SETTINGS對(duì)應(yīng)的通知設(shè)置界面如下:


這完全不是我們需要的界面啊。。。里面并沒有我們想要的開關(guān)啊。而且,在小米6中 Settings.ACTION_APPLICATION_DETAILS_SETTINGS 對(duì)應(yīng)的應(yīng)用信息界面中,點(diǎn)擊其中的 通知管理 之后跳轉(zhuǎn)的也是上面圖中的樣子。

但是,如果我們手動(dòng)的從 設(shè)置--通知和狀態(tài)欄--通知管理 進(jìn)入我們應(yīng)用的通知設(shè)置界面時(shí),就可以正常的看到 允許通知的開關(guān),如下圖:

對(duì)于小米6手機(jī)的這個(gè)情況,分析了一陣子之后還是沒找到解決辦法。本來想著通過log確認(rèn)一下上圖中的界面到底是哪個(gè)Activity,但非常郁悶的是Log中只得到了com.android.settings/.SubSettings 這么一個(gè)地址,之前沒見過這個(gè)地址,然后繼續(xù)搜索。

在看完 https://www.cnblogs.com/Lefter/archive/2013/04/27/3048010.htmlhttps://blog.csdn.net/hfreeman2008/article/details/52778992 之后,明白了 .SubSettings 是干啥的了。也大致推斷出為啥在小米6上得不到我們想要的界面了——他們?cè)诙ㄖ葡到y(tǒng)時(shí)更改了通知設(shè)置界面對(duì)應(yīng)的Fragment!!!!

此時(shí),真想對(duì)雷布斯說一句:I'm not ok!!!!

三、附錄

1、測(cè)試結(jié)果說明

手機(jī)型號(hào) 系統(tǒng)版本 測(cè)試結(jié)果
Vivo X9s 7.1.2 正常跳轉(zhuǎn)到通知設(shè)置界面
榮耀10 8.1.0 正常跳轉(zhuǎn)到通知設(shè)置界面
紅米note4x 7.0 正常跳轉(zhuǎn)到通知設(shè)置界面
Oppo R7 plus 5.0 正常跳轉(zhuǎn)到通知設(shè)置界面
ZTE BA910 5.1 正常跳轉(zhuǎn)到通知設(shè)置界面
Oppo R15 8.1.0 正常跳轉(zhuǎn)到通知設(shè)置界面
三星蓋樂世On5 7.1.1 正常跳轉(zhuǎn)到通知設(shè)置界面
360Vizza 7.1.1 正常跳轉(zhuǎn)到通知設(shè)置界面
魅族Mx3 4.4 進(jìn)入APP設(shè)置界面
華為榮耀4X 4.4 進(jìn)入APP設(shè)置界面
錘子堅(jiān)果3 7.1.2 進(jìn)入APP設(shè)置界面
小米6 8.0.0 進(jìn)入的頁面中沒有通知開關(guān)!!!!

2、參考鏈接

(1)通知設(shè)置的參考鏈接

(2)SubSettings 和 Settings 的參考鏈接

3、文中代碼的GitHub地址

文中代碼分別對(duì)應(yīng)下列倉庫中的:b_34_checkNotify、b_34_pushcheck
Java版:https://github.com/CnPeng/CnPengAndroid.git
Kotlin版:https://github.com/CnPeng/CnPengKotlin.git


本文到此結(jié)束,謝謝觀看!
如有不足,敬請(qǐng)指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容