Scheme详解( web页面判断是否安装某app,并判断是否打开该应用)
参照页面:
demo实例:http://blog.csdn.net/qq_30740239/article/details/51969660
Scheme详解:http://blog.csdn.net/wangkeke1860/article/details/49850997
参数详解:http://blog.csdn.net/harvic880925/article/details/44679239
web页面判断手机里是否安转应用的原理就是:首先试着打开手机端某个app的本地协议;如果超时就转到app下载页,下载该app。
下面说说
URL scheme 概述
URL scheme 的作用
客户端应用可以向操作系统注册一个 URL scheme,该 scheme 用于从浏览器或其他应用中启动本应用。通过指定的 URL 字段,可以让应用在被调起后直接打开某些特定页面,比如车辆详情页、订单详情页、消息通知页、促销广告页等等。也可以执行某些指定动作,如订单支付等。也可以在应用内通过 html 页来直接调用显示 app 内的某个页面。
URL scheme 的格式
客户端自定义的 URL 作为从一个应用调用另一个的基础,遵循 RFC 1808 (Relative Uniform Resource Locators) 标准。这跟我们常见的网页内容 URL 格式一样。
一个普通的 URL 分为几个部分,scheme
、host
、relativePath
、query
。
比如:http://www.baidu.com/s?rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709
,这个URL中,scheme
为 http
,host
为www.baidu.com
,relativePath
为 /s
,query
为 rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709
。
一个应用中使用的 URL 例子(该 URL 会调起车辆详情页):uumobile://mobile/carDetail?car_id=123456
,其中 scheme
为 uumobile
,host
为mobile
,relativePath
为 /carDetail
,query
为 car_id=123456
。
Scheme定义Activity
1)在androidmanifest.xml中定义scheme
<!-- 启动页 --> <activity android:name="com.qiyuan.congmingtou.activity.SplashActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- 要想在别的App上能成功调起App,必须添加intent过滤器 --> <intent-filter> <!-- 协议部分,随便设置 --> <data android:scheme="cmt" android:host="splash"/> <!-- 下面这几行也必须得设置 --> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <action android:name="android.intent.action.VIEW" /> </intent-filter> </activity>
这样我们便定义了能够接受scheme请求的activity实例,当网页或者是android代码发送这种规则scheme的请求的时候就能够吊起SplashActivity了。
2.网页中Html代码和js代码
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<title>this's a demo</title>
<meta id="viewport" name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui">
</head>
<body>
<div>
<a id="J-call-app" href="JavaScript:;" class="label">立即打开>></a>
<input id="J-download-app" type="hidden" name="storeurl" value="http://m.chanyouji.cn/apk/chanyouji-2.2.0.apk">
</div>
<script>
(function(){
var ua = navigator.userAgent.toLowerCase();
var t;
var config = {
/*scheme:必须*/
scheme_IOS: 'IfInstalledCongMingTou://congmingtou',
scheme_Adr: 'cmt://splash',
download_url: document.getElementById('J-download-app').value,
timeout: 600
};
function openclient() {
var startTime = Date.now();
var ifr = document.createElement('iframe');
ifr.src = ua.indexOf('os') > 0 ? config.scheme_IOS : config.scheme_Adr;
ifr.style.display = 'none';
document.body.appendChild(ifr);
var t = setTimeout(function() {
var endTime = Date.now();
if (!startTime || endTime - startTime < config.timeout + 200) {
window.location = config.download_url;
} else {
}
}, config.timeout);
window.onblur = function() {
clearTimeout(t);
}
}
window.addEventListener("DOMContentLoaded", function(){
document.getElementById("J-call-app").addEventListener('click',openclient,false);
}, false);
})()
</script>
</body>
</html>
如果我们要用于实现对scheme的解析,然后做出相应的动作,比如请求scheme跳转登录页面,要在SplashActivity中做写相应的代码:
public class SplashActivity extends Activity{ public Activity mContext = null; public void onCreate(Bundle b) { super.onCreate(b); mContext = this; Uri uri = getIntent().getData(); if (uri != null) { List<String> pathSegments = uri.getPathSegments(); String uriQuery = uri.getQuery(); Intent intent; if (pathSegments != null && pathSegments.size() > 0) { // 解析SCHEME if (someif) { dosomething(); } else { // 若解析不到SCHEME,则关闭NativeAppActivity; finish(); } } else { finish(); } } else { finish(); } } }
这里简单说一下,我们可以通过Intent对象获取调用的scheme的host等信息
this.getIntent().getScheme();//获得Scheme名称 this.getIntent().getDataString();//获得Uri全部路径
通过服务器下发跳转路径跳转相应页面
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("uumobile://yongche/123123123")));
这里的”uumobile://yongche/123123123”就是服务器下发的跳转路径,当我们执行startActivity的时候就会调起SpalshActivity,然后我们通过在SpalshActivity解析scheme的内容,跳转相应的页面
总结:
Android中的scheme是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;
通过scheme协议,服务器可以定制化告诉App跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
—————————————————————————————————————————————————————————————
---------------------------------------------------------------------------------------------------------------------------------------------------------
一、URI与Uri
大家可能经常会看到在开发时,怎么有的时候是URI,有的时候是Uri,这是怎么回事?
名称如此相像的两个类是有什么区别和联系?
- 1.所属的包不同。URI位置在java.net.URI,显然是Java提供的一个类。而Uri位置在android.net.Uri,是由Android提供的一个类。所以初步可以判断,Uri是URI的“扩展”以适应Android系统的需要。
- 2.作用的不同。URI类代表了一个URI(这个URI不是类,而是其本来的意义:通用资源标志符——Uniform Resource Identifier)实例。Uri类是一个不可改变的URI引用,包括一个URI和一些碎片,URI跟在“#”后面。建立并且转换URI引用。而且Uri类对无效的行为不敏感,对于无效的输入没有定义相应的行为,如果没有另外制定,它将返回垃圾而不是抛出一个异常。
看不懂?没关系,知道这个就可以了:Uri是Android开发的,扩展了Java中URI的一些功能来特定的适用于Android开发,所以大家在开发时,只使用Android 提供的Uri即可;
二、Uri结构
(1)、基本形式:
- [scheme:]scheme-specific-part[#fragment]
这里分为三部分:
scheme、scheme-specific-part、fragment
(2)、进一步划分:
如果进一步划分的话是这样子的
- [scheme:][//authority][path][?query][#fragment]
其中有下面几个规则:
- path可以有多个,每个用/连接,比如
scheme://authority/path1/path2/path3?query#fragment - query参数可以带有对应的值,也可以不带,如果带对应的值用=表示,如:
scheme://authority/path1/path2/path3?id = 1#fragment,这里有一个参数id,它的值是1 - query参数可以有多个,每个用&连接
scheme://authority/path1/path2/path3?id = 1&name = mingming&old#fragment
这里有三个参数:
参数1:id,其值是:1
参数2:name,其值是:mingming
参数3:old,没有对它赋值,所以它的值是null - 在android中,除了scheme、authority是必须要有的,其它的几个path、query、fragment,它们每一个可以选择性的要或不要,但顺序不能变,比如:
其中"path"可不要:scheme://authority?query#fragment
其中"path"和"query"可都不要:scheme://authority#fragment
其中"query"和"fragment"可都不要:scheme://authority/path
"path","query","fragment"都不要:scheme://authority
等等……
(3)、终极划分
其中authority,又可以分为host:port的形式,即再次划分后是这样的:
- [scheme:][//host:port][path][?query][#fragment]
所以这是划分最细的形式,其中host:port用冒号分隔,冒号前的是host,冒号后的port;
三、示例
经过上面的讲解,想必大家的Uri的结构就有所了解了,下面我们就实例看看各部分的识别方式。
- [scheme:]scheme-specific-part[#fragment]
- [scheme:][//authority][path][?query][#fragment]
- [scheme:][//host:port][path][?query][#fragment]
先列出这三种Uri形式,好让大家对比;
针对下面一个Uri字符串来匹配一下各个部分:
- http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
- scheme:匹对上面的两个Uri标准形式,很容易看出在:前的部分是scheme,所以这个Uri字符串的sheme是:http
- scheme-specific-part:很容易看出scheme-specific-part是包含在scheme和fragment之间的部分,也就是包括第二部分的[//authority][path][?query]这几个小部分,所在这个Uri字符串的scheme-specific-part是://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4 ,注意要带上//,因为除了[scheme:]和[#fragment]部分全部都是scheme-specific-part,当然包括最前面的//;
- fragment:这个是更容易看出的,因为在最后用#分隔的部分就是fragment,所以这个Uri的fragment是:harvic
下面就是对scheme-specific-part进行拆分了;
在scheme-specific-part中,最前端的部分就是authority,?后面的部分是query,中间的部分就是path - authority:很容易看出scheme-specific-part最新端的部分是:www.java2s.com:8080
- query:在scheme-specific-part中,?后的部分为:stove=10&path=32&id=4
- path:在**query:**在scheme-specific-part中,除了authority和query其余都是path的部分:/yourpath/fileName.htm
又由于authority又一步可以划分为host:port形式,其中host:port用冒号分隔,冒号前的是host,冒号后的是port,所以: - host:www.java2s.com
- port:8080
四、代码提取
上面我们通过实例讲解了肉眼识别Uri更部分的方式,但在代码中又要怎样提取呢。下面就看看Uri中提取各部分的接口,依然以上面的Uri字符串为例:
- http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
- getScheme() :获取Uri中的scheme字符串部分,在这里即,http
- getSchemeSpecificPart():获取Uri中的scheme-specific-part:部分,这里是://www.java2s.com:8080/yourpath/fileName.htm?
- getFragment():获取Uri中的Fragment部分,即harvic
- getAuthority():获取Uri中Authority部分,即www.java2s.com:8080
- getPath():获取Uri中path部分,即/yourpath/fileName.htm
- getQuery():获取Uri中的query部分,即stove=10&path=32&id=4
- getHost():获取Authority中的Host字符串,即www.java2s.com
- getPost():获取Authority中的Port字符串,即8080
另外还有两个常用的:getPathSegments()、getQueryParameter(String key)
- List< String> getPathSegments():上面我们的getPath()是把path部分整个获取下来:/yourpath/fileName.htm,getPathSegments()的作用就是依次提取出Path的各个部分的字符串,以字符串数组的形式输出。以上面的Uri为例:
- String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic";
- Uri mUri = Uri.parse(mUriStr);
- List<String> pathSegList = mUri.getPathSegments();
- for (String pathItem:pathSegList){
- Log.d("qijian","pathSegItem:"+pathItem);
- }
打出来的列表为:
- getQueryParameter(String key):在上面我们通过getQuery()获取整个query字段:stove=10&path=32&id=4,getQueryParameter(String key)作用就是通过传进去path中某个Key的字符串,返回他对应的值。
- String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id#harvic";
- mUri = Uri.parse(mUriStr);
- Log.d(tag,"getQueryParameter(\"stove\"):"+mUri.getQueryParameter("stove"));
- Log.d(tag,"getQueryParameter(\"id\"):"+mUri.getQueryParameter("id"));
注意注意,我稍微更改了下字符串,把query中id的值去掉了!!!!!然后看看通过getQueryParameter("id")获取它的值会得到什么!
结果如下:
可以看到,在path中,即使针对某一个KEY不对它赋值是允许的,但在利用getQueryParameter()获取该KEY对应的值时,获取到的是null;
五、扩展
1、 绝对URI和相对URI
绝对URI:以scheme组件起始的完整格式,如http://fsjohnhuang.cnblogs.com。表示以对标识出现的环境无依赖的方式引用资源。
相对URI:不以scheme组件起始的非完整格式,如fsjohnhuang.cnblogs.com。表示以对依赖标识出现的环境有依赖的方式引用资源。
2、不透明URI和分层URI
不透明URI:scheme-specific-part组件不是以正斜杠(/)起始的,如mailto:fsjohnhuang@xxx.com。由于不透明URI无需进行分解操作,因此不会对scheme-specific-part组件进行有效性验证。
分层URI:scheme-specific-part组件是以正斜杠(/)起始的,如http://fsjohnhuang.com。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)