有没有办法链接到我的应用程序的Android通知设置?

117

我是否有办法发起一个意图来进入我的应用程序的Android通知设置屏幕(如下图所示)?或者我可以通过轻松的方法在单击时创建一个PreferenceScreen项,只需前往此处即可?

输入图像描述


1
看起来 Settings.ACTION_APPLICATION_DETAILS_SETTINGS 会带我到主应用信息屏幕,但我想进一步进入应用信息屏幕上的通知设置... - Mohamed Hafez
1
顺便问一下 @mohamed-hafez,你能解释一下你是如何将这个“应用设置”条目固定在这里的吗?我听说是通过清单中的意图过滤器完成的,但我做不到。谢谢! - Gabriel
1
@Gabriel,看起来你已经找到了问题的答案,但是对于其他有兴趣的人,答案在这里:[https://dev59.com/KV4b5IYBdhLWcg3wxURi#28710214]。 - Sam
如何在Orio上打开应用程序通知类别(默认)?我们在哪里可以更改声音、振动和其他设置。 - Sagar
12个回答

181

以下内容适用于 Android 5.0(棒棒糖)及以上版本:

Intent intent = new Intent();
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//for Android 5-7
intent.putExtra("app_package", getPackageName());
intent.putExtra("app_uid", getApplicationInfo().uid);

// for Android 8 and above
intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());

startActivity(intent);

注:虽然在Android 5-7中官方并不支持,但该方法可行。从Android 8开始官方支持该方法。此代码无法向前兼容Android 5.0之前的版本。


@shhp - 谢谢你的回答。在N预览版中也适用。请问你能简要说明一下你是如何找到这个解决方案的吗?在我的调查中,我最远得到的是这个日志消息:“com.android.settings D/SubSettings: Launching fragment com.android.settings.notification.AppNotificationSettings”,当我点击应用设置中的“通知”行时。链接至源代码 - Dev-iL
@Dev-iL 你已经完成了第一步。然后我检查了源代码,看看应该在“意图”中加入哪些额外内容 :-) - shhp
1
这很酷,但用户应该注意以下几点:1)此意图依赖于“设置”应用程序的内部/隐藏代码,因此不能保证在未来“设置”应用程序不会更改并且不再使用相同的字符串操作、组件或意图额外打开特定应用程序的通知屏幕。2)此方法不完全向后兼容。所使用的字符串操作和组件是大约两年前引入的。请参见提交记录 - Tony Chan
刚编辑过,现在可以适用于 Android O 以及 Android 5-7。注意:在 Android O 中官方支持此功能! - Mohamed Hafez
2
只是一点小提示:您也可以像这里所示的那样,访问特定的通知渠道设置:https://dev59.com/DFUM5IYBdhLWcg3wa_y7#48854197 - android developer
显示剩余3条评论

108

我合并了 Sergei 和 Shhp 的解决方案以支持所有情况:

    Intent intent = new Intent();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
        intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
        intent.putExtra("app_package", context.getPackageName());
        intent.putExtra("app_uid", context.getApplicationInfo().uid);
    } else {
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setData(Uri.parse("package:" + context.getPackageName()));
    }
    context.startActivity(intent);

Settings.ACTION_APP_NOTIFICATION_SETTINGS 和 "android.settings.APP_NOTIFICATION_SETTINGS" 字符串值是相同的。那么,为什么会这样? - Parth Anjaria
"android.settings.APP_NOTIFICATION_SETTINGS" 是字面字符串,因为 Settings.ACTION_APP_NOTIFICATION_SETTINGS 只在 API 26 及以上版本中可用。 - Matt Carron

17

我已经附加了适用于Android 8.0 Oreo API 26或更高版本的频道通知设置。对于Android 4.4 KitKat也有一种解决方案。

频道通知设置的使用方法:

// PRIMARY_CHANNEL:
goToNotificationSettings(getString(R.string.PRIMARY_CHANNEL), mContext);
// SECONDARY_CHANNEL:
goToNotificationSettings(getString(R.string.SECONDARY_CHANNEL), mContext);

应用程序通知设置的使用方法:

goToNotificationSettings(null, mContext);

goToNotificationSettings的方法:

public void goToNotificationSettings(String channel, Context context) {
    Intent intent = new Intent();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
        if (channel != null) {
            intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
            intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel);
        } else {
            intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        }
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        if (channel != null) {
            intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
            intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel);
        } else {
            intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        }
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
    } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
    } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
        intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        intent.putExtra("app_package", context.getPackageName());
        intent.putExtra("app_uid", context.getApplicationInfo().uid);
    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setData(Uri.parse("package:" + context.getPackageName()));
    }
    context.startActivity(intent);
}

1
Settings.ACTION_APP_NOTIFICATION_SETTINGS 可在 API >= Build.VERSION_CODES.O 中使用,因此不应在 N_MR1 上使用 https://developer.android.com/reference/android/provider/Settings.html#ACTION_APP_NOTIFICATION_SETTINGS - Ante
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) 中的代码将永远不会被执行,在某些部分中,您正确地使用了 Settings.ACTION_APP_NOTIFICATION_SETTINGS,但在其他一些部分中,您使用了硬编码字符串 "android.settings.APP_NOTIFICATION_SETTINGS" - Hugo Allexis Cardona

13

对于懒惰的人来说,这是@Helix答案的Kotlin版本:

fun openAppNotificationSettings(context: Context) {
    val intent = Intent().apply {
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
                action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
                putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
                action = "android.settings.APP_NOTIFICATION_SETTINGS"
                putExtra("app_package", context.packageName)
                putExtra("app_uid", context.applicationInfo.uid)
            }
            else -> {
                action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                addCategory(Intent.CATEGORY_DEFAULT)
                data = Uri.parse("package:" + context.packageName)
            }
        }
    }
    context.startActivity(intent)
}

1
有没有一种方法可以在应用内部处理推送通知设置而不启动设置活动? - vinay kumar
在另一个答案中编写2023年的更新... - Jose_GD

7

使用 Kotlin 编写的更新版本,包括所有在这里描述的情况。

fun showNotificationSettings(context: Context, channelId: String? = null) {
    val notificationSettingsIntent = when {
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*26*/ -> Intent().apply {
            action = when (channelId) {
                null -> Settings.ACTION_APP_NOTIFICATION_SETTINGS
                else -> Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS
            }
            channelId?.let { putExtra(Settings.EXTRA_CHANNEL_ID, it) }
            putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P /*28*/) {
                flags += Intent.FLAG_ACTIVITY_NEW_TASK
            }
        }
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP /*21*/ -> Intent().apply {
            action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
            putExtra("app_package", context.packageName)
            putExtra("app_uid", context.applicationInfo.uid)
        }
        Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT /*19*/ -> Intent().apply {
            action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
            addCategory(Intent.CATEGORY_DEFAULT)
            data = Uri.parse("package:${context.packageName}")
        }
        else -> null
    }
    notificationSettingsIntent?.let(context::startActivity)
}

你可以这样使用它

showNotificationSettings(context)

或者你可以添加频道ID以显示频道设置

showNotificationSettings(context, channelId = "some_channel_id")

请问您能否澄清一下,为什么在Android P及更高版本中需要使用FLAG_ACTIVITY_NEW_TASK标志? - Fox

5
我使用以下代码(适用于KitKat版本及更高版本):
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    Intent intent = new Intent();
    intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
    intent.putExtra("app_package", getActivity().getPackageName());
    intent.putExtra("app_uid", getActivity().getApplicationInfo().uid);
    startActivity(intent);
} else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
    Intent intent = new Intent();
    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
    startActivity(intent);
}

3

我将一些以上答案的代码合并,并进行了小小的编辑,我已经测试过在Android KitKat、Lollipop、Marshmallow、Nougat、Oreo和Pie上可以正常工作,API等级为19-28。

public void goToNotificationSettings(Context context) {

    String packageName = context.getPackageName();

    try {
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {

            intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
            intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);

        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {

            intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
            intent.putExtra("android.provider.extra.APP_PACKAGE", packageName);

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            intent.putExtra("app_package", packageName);
            intent.putExtra("app_uid", context.getApplicationInfo().uid);

        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {

            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(Uri.parse("package:" + packageName));

        } else {
            return;
        }

        startActivity(intent);

    } catch (Exception e) {
        // log goes here           

    }

}

1
使用 ACTION_APP_NOTIFICATION_SETTINGS 将列出应用程序的所有通道:
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
    .putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
startActivity(intent);

要打开单个频道的设置,您可以使用 ACTION_CHANNEL_NOTIFICATION_SETTINGS
在这里,您可以更改单个频道的声音、振动等设置。
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
 Intent intent = new Intent("android.settings.CHANNEL_NOTIFICATION_SETTINGS");
        intent.putExtra("android.provider.extra.CHANNEL_ID", "ChannelID");
        intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());
        startActivity(intent);
   } 

1
我想呈现一份(在我看来)更简洁的@Helix答案版本:
fun openNotificationsSettings() {
    val intent = Intent()
    when {
        Build.VERSION.SDK_INT > Build.VERSION_CODES.O -> intent.setOpenSettingsForApiLarger25()
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> intent.setOpenSettingsForApiBetween21And25()
        else -> intent.setOpenSettingsForApiLess21()
    }
    app.startActivity(intent)
}

private fun Intent.setOpenSettingsForApiLarger25(){
    action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
    putExtra("android.provider.extra.APP_PACKAGE", app.packageName)
}

private fun Intent.setOpenSettingsForApiBetween21And25(){
    action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
    putExtra("app_package", app.packageName)
    putExtra("app_uid", app.applicationInfo?.uid)
}

private fun Intent.setOpenSettingsForApiLess21(){
    action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
    addCategory(Intent.CATEGORY_DEFAULT)
    data = Uri.parse("package:" + app.packageName)
}

可以进一步将每个when分支提取为一个紧凑的类,并创建一个工厂,其中when会被使用。

"并创建一个工厂..." 这就是如何将简单的代码变得复杂。 - Ridcully
@Ridcully 嗯,回顾一下这个回答,我完全同意。但我不会编辑它,因为它展现了过度工程的美妙讽刺。 - Kirill Starostin

1

这是对@carlol编写的漂亮的Kotlin版本的更新。 在我使用它的项目中,我有minSdk = 21,所以代码可以更加简洁:

private fun openAppNotificationSettings(context: Context) {
    val intent = Intent().apply {
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
                action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
                putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
            }
            else -> {
                action = "android.settings.APP_NOTIFICATION_SETTINGS"
                putExtra("app_package", context.packageName)
                putExtra("app_uid", context.applicationInfo.uid)
            }
        }
    }
    context.startActivity(intent)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接