Android配置scheme/host intent filter的BroadcastReceiver点击链接不触发怎么办
根本原因
系统浏览器或WebView处理自定义scheme的链接点击时,默认构造的是Intent.ACTION_VIEW类型的Intent,调用startActivity()匹配对应的Intent Filter,不会主动发送广播,因此即便广播接收器配置了相同的data规则,也无法接收到事件。
解决方案
根据HTML的加载场景不同,可选择以下两种实现方案:
场景1:HTML在自有App的WebView中加载
直接在WebView的加载回调中拦截目标scheme链接,手动构造并发送广播:
- 给WebView设置自定义WebViewClient,重写url加载拦截方法:
webView.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { val uri = request?.url ?: return super.shouldOverrideUrlLoading(view, request) // 匹配自定义scheme和host if (uri.scheme == "tisseo.main" && uri.host == "login") { // 构造显式广播Intent,避免8.0+静态注册广播的隐式匹配限制 val broadcastIntent = Intent(context, ConnectionReceiver::class.java).apply { data = uri // 可按需添加extra参数 } context?.sendBroadcast(broadcastIntent) // 拦截本次url加载,避免WebView默认处理 return true } return super.shouldOverrideUrlLoading(view, request) } }
- 若需使用隐式广播,需给广播接收器的Intent Filter添加自定义Action配置:
<receiver android:name=".receiver.ConnectionReceiver" android:exported="true"> <intent-filter> <!-- 自定义Action,需和发送广播时设置的Action保持一致 --> <action android:name="com.yourpackage.action.SCHEME_LOGIN" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="login" android:scheme="tisseo.main" /> </intent-filter> </receiver>
发送广播时对应设置Action即可:
val broadcastIntent = Intent("com.yourpackage.action.SCHEME_LOGIN").apply { data = uri setPackage(context.packageName) // 8.0+隐式广播需要指定包名才能匹配静态注册接收器 } context?.sendBroadcast(broadcastIntent)
场景2:HTML在外部系统浏览器中加载
无法直接控制浏览器的行为,可通过透明无界面的中转Activity转接事件:
- 新增完全透明的中转Activity,配置原有的scheme Intent Filter:
<activity android:name=".SchemeTransferActivity" android:exported="true" <!-- 配置透明无动画主题,避免用户感知到页面跳转 --> android:theme="@style/Theme.Transparent.NoAnimation"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="login" android:scheme="tisseo.main" /> </intent-filter> </activity>
- 中转Activity的逻辑实现,接收到Intent后直接转发为广播并销毁自身:
class SchemeTransferActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 无需设置布局 intent?.data?.let { uri -> val broadcastIntent = Intent(this, ConnectionReceiver::class.java).apply { data = uri } sendBroadcast(broadcastIntent) } finish() // 去掉Activity切换动画,避免闪屏 overridePendingTransition(0, 0) } }
- 在res/values/styles.xml中添加透明主题配置:
<style name="Theme.Transparent.NoAnimation" parent="Theme.MaterialComponents.Light.NoActionBar"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowActionBar">false</item> <item name="android:windowContentOverlay">@null</item> </style>
注意事项
- Android 8.0及以上系统对静态注册的隐式广播做了限制,优先使用显式广播,或发送隐式广播时调用
setPackage()指定应用包名,确保接收器能正常匹配。 - 若使用全局广播,可按需添加自定义权限,避免信息泄露或被恶意应用拦截。
内容的提问来源于stack exchange,提问作者Kevin ABRIOUX
相关产品推荐
相关产品推荐

