android广播唤醒app,Android scheme呼起App

一.自定义Scheme

Android应用/组件间通信有一种方式是intent,应用可以注册intent filter声明自己对什么样的intent感兴趣,其它应用发送intent时通过系统级广播传递过来,如果与预先注册的intent filter匹配,应用将收到该intent(无论应用是否正在运行,都会被“唤醒”,也就是隐式启动Activity),取出intent携带的数据,做进一步处理

就是这样,通过系统广播拿到一次起来的机会,例如在manifest里静态注册intent filter声明自定义scheme:

action、category、data都必须完全匹配才能获得intent,这里声明了2个category,只有在intent同时含有这2个category时才算匹配,而android.intent.category.DEFAULT是默认的,有实际意义的是android.intent.category.BROWSABLE,表示允许通过浏览器启动该activity(呼起App)。后续的data限定了触发条件,当scheme为hoho时才匹配,例如浏览器访问hoho://abc,能够匹配成功,App就起来了

二.取出数据

在onCreate里拿到intent,取出uri:

@Override

protected void onCreate(Bundle savedInstanceState) {

//...

// 获取uri参数

Intent intent = getIntent();

String scheme = intent.getScheme();

Uri uri = intent.getData();

String str = "";

if (uri != null) {

String host = uri.getHost();

String dataString = intent.getDataString();

String from = uri.getQueryParameter("from");

String path = uri.getPath();

String encodedPath = uri.getEncodedPath();

String queryString = uri.getQuery();

//...根据uri判断打开哪个页,或者打开哪个功能

}

}

这里的URI就是标准的URI,有协议、主机名、端口号、路径、查询字符串等等,但一般自定义scheme不需要这么麻烦,只用path/query做简单区分就行,比如:

// 通过path区分

hoho://toFeature/login

// 通过query区分

hoho://open?feature=login

当然,也可以通过端口号等区分,没什么区别

三.在线页面呼起App

浏览器先发出自定义scheme请求,系统广播收到后再分发给各应用,那么页面发送请求的方式就多了:

location.href

iframe.src

a.href

img.src

...其它能发出请求的方式

这些方式在强弱上有区别,比如location.href是强的,而img.src很弱,至少要强到浏览器决定把这个请求交给系统广播才行,比如img请求自定义scheme,浏览器认为没有必要交给系统广播。一般只用前2种最强的方式:location.href和iframe.src,隐藏iframe偷偷请求自定义scheme相对用得更多,因为不会有未知的副作用(location方式或许可能被记入历史栈或者unload当前页,但iframe绝对没有太严重的副作用)

但无论哪种方式,都无法得知App被呼起了没,可能没安装App,也可能intent没匹配成功,但页面肯定没有办法得知。所以一般呼起App的页面都会延迟自动跳转下载页,无论有没有成功呼起App,这也是迫不得已

除了页面发出请求,还有一种更强的方式:通过应用发出请求,例如:

// 通过webview发出请求

webview.loadUrl(mySchemeUri);

这个起点就是应用级,比WebView中页面请求要强一些。所以一般Hybrid App中,客户端会提供这样的接口,用来跳转第三方,比页面请求更强

四.Intent Scheme URL攻击

自定义Scheme存在安全风险,比如:

注册优先级更高的相同intent filter,窃取scheme uri

如果知道跳转的自定义scheme格式,可以跳向钓鱼页面(确实是在App里打开的页面,但它是第三方做的假的)

…其它风险

一般自定义scheme都是不公开的,但难免会泄漏出去(反编译App等方式),scheme接口本身要做好防范,接收intent时可以这样做:

// forbid launching activities without BROWSABLE category

intent.addCategory("android.intent.category.BROWSABLE");

// forbid explicit call

intent.setComponent(null);

// forbid intent with selector intent

intent.setSelector(null);

不信任所有来自自定义scheme的输入,对于跳转接口,还要有白名单限制

五.WebView Scheme白名单

WebView作为页面容器,可以过滤/拦截页面请求:

class MyWebClient extends WebViewClient {

@Override

public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

if (url.startsWith("hoho://")) {

return null;

}

return super.shouldInterceptRequest(view, url);

}

@Override

public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

String scheme = request.getUrl().getScheme();

if (scheme.equals("hoho")) {

return null;

}

return super.shouldInterceptRequest(view, request);

}

}

上面的用于API[11-20],21弃用String url,新增了WebResourceRequest request,在API21+只触发WebResourceRequest request形式的,所以兼容考虑,两个都要重写一遍

对于满足过滤条件的,拦截掉,所以在微信里无法呼起App,因为不在白名单里,被拦截下来,没有交给系统广播

在被拦截的情况下,iframe方式的优势就体现出来了,a.href和location.href都会导致页面跳转,显示“网页无法打开…因为net::ERR_UNKNOWN_URL_SCHEME”,而iframe方式不影响当前页

六.Demo

写在最后

Android Studio实在太慢了,怀念eclipse,另外,感谢@旭

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值