如何在Android Studio中为WebView开启通知权限
问题描述
我正在使用Android Studio开发一款WebView应用,该应用加载网站https://grillizuae.com。此网站会推送带声音的通知提醒,我需要获取该通知的声音;另外,通常在Chrome等浏览器打开网站时会询问通知权限,但在WebView中该如何开启此权限?
以下是我的实现代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); WebView webView = (WebView) findViewById(R.id.webview); webView.getSettings().setUseWideViewPort(true);//setting wide view webView.getSettings().setLoadWithOverviewMode(true);//setting default zoomed out view webView.setInitialScale(1); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("https://grillizuae.com"); //webView.getSettings().setUserAgentString("Desktop"); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); } private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { return false; } }
解决方案
一、开启WebView的通知权限
WebView不会自动处理通知权限请求,需要通过WebChromeClient拦截并处理:
- 添加Manifest权限(Android 13+)
在AndroidManifest.xml中添加通知权限:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
- 动态申请权限(Android 13+)
因为POST_NOTIFICATIONS是危险权限,需要在代码中动态申请:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { // 可根据权限申请结果做后续处理 }).launch(Manifest.permission.POST_NOTIFICATIONS); } }
- 通过WebChromeClient处理权限请求
为WebView设置自定义WebChromeClient,重写onPermissionRequest方法允许通知权限:
webView.setWebChromeClient(new WebChromeClient() { @Override public void onPermissionRequest(PermissionRequest request) { for (String permission : request.getResources()) { if (PermissionRequest.RESOURCE_NOTIFICATION.equals(permission)) { request.grant(request.getResources()); return; } } request.deny(); } });
二、获取通知声音
网站的通知声音通常通过Web Notification API设置,可通过两种方式获取:
方式1:注入JS拦截通知创建
通过注入JavaScript代码拦截网站的通知构造函数,提取声音URL:
- 创建JS接口类
public class NotificationInterface { @JavascriptInterface public void onNotificationCreated(String soundUrl) { // 这里获取到通知声音的URL,可进行下载或播放操作 Log.d("NotificationSound", "通知声音URL: " + soundUrl); } }
- 添加JS接口并注入拦截代码
在onPageFinished中注入JS代码,替换原生Notification构造函数:
// 添加JS接口 webView.addJavascriptInterface(new NotificationInterface(), "NotificationHandler"); // 设置WebViewClient注入拦截代码 webView.setWebViewClient(new MyWebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); String js = "window.Notification = function(title, options) {" + "if (options && options.sound) {" + "NotificationHandler.onNotificationCreated(options.sound);" + "}" + "return new window.originalNotification(title, options);" + "};" + "window.originalNotification = window.Notification;"; view.evaluateJavascript(js, null); } });
方式2:监听系统通知(针对推送类通知)
如果网站使用FCM等推送服务,通知会以系统通知形式到达,可通过NotificationListenerService监听:
- 创建NotificationListenerService
public class MyNotificationListener extends NotificationListenerService { @Override public void onNotificationPosted(StatusBarNotification sbn) { super.onNotificationPosted(sbn); // 过滤目标应用的通知 if ("你的应用包名".equals(sbn.getPackageName())) { Notification notification = sbn.getNotification(); Uri soundUri = notification.sound; if (soundUri != null) { Log.d("NotificationSound", "系统通知声音URI: " + soundUri.toString()); } } } }
- 注册服务到Manifest
<service android:name=".MyNotificationListener" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> <intent-filter> <action android:name="android.service.notification.NotificationListenerService" /> </intent-filter> </service>
- 引导用户开启监听权限
需要用户在系统设置中开启权限,可通过代码跳转:
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); startActivity(intent);
完整修改后的MainActivity代码
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); WebView webView = findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true); webView.setInitialScale(1); webSettings.setJavaScriptEnabled(true); webSettings.setDomStorageEnabled(true); // 部分网站通知需要开启DOM存储 // 动态申请Android 13+通知权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { // 权限申请结果处理 }).launch(Manifest.permission.POST_NOTIFICATIONS); } } // 设置WebChromeClient处理通知权限请求 webView.setWebChromeClient(new WebChromeClient() { @Override public void onPermissionRequest(PermissionRequest request) { for (String permission : request.getResources()) { if (PermissionRequest.RESOURCE_NOTIFICATION.equals(permission)) { request.grant(request.getResources()); return; } } request.deny(); } }); // 添加JS接口拦截通知声音 webView.addJavascriptInterface(new NotificationInterface(), "NotificationHandler"); // 设置WebViewClient并注入拦截JS webView.setWebViewClient(new MyWebViewClient()); webView.loadUrl("https://grillizuae.com"); } private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { return false; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); String js = "window.Notification = function(title, options) {" + "if (options && options.sound) {" + "NotificationHandler.onNotificationCreated(options.sound);" + "}" + "return new window.originalNotification(title, options);" + "};" + "window.originalNotification = window.Notification;"; view.evaluateJavascript(js, null); } } public class NotificationInterface { @JavascriptInterface public void onNotificationCreated(String soundUrl) { Log.d("NotificationSound", "获取到通知声音URL: " + soundUrl); // 可添加下载或播放声音的逻辑 } } }
内容的提问来源于stack exchange,提问作者G PAC
相关产品推荐
相关产品推荐

