最近在一个技术公众号里看见Scheme,由于之前没有接触过。触及到了我的知识盲点,于是花了些功夫去了解这个协议。
URL Scheme 有什么用?使用场景
Scheme 用于从浏览器或其他应用中启动本应用。也就是说要从其他应用中跳转本应用的界面或者网页跳转本应用打开特定的界面。
如何定义Scheme协议
首先我们来看看URL Scheme 的格式
客户端自定义的 URL 作为从一个应用调用另一个的基础,遵循 RFC 1808 (Relative Uniform Resource Locators) 标准。这跟我们常见的网页内容 URL 格式一样。
一个普通的 URL 分为几个部分,scheme、host、port、relativePath、query、fragment(定义一个url包含了你定义的scheme,主机名或者域名,端口(可选)路径,查询条件等)
URL的一般语法格式为:
(带方括号[]的为可选项):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
protocol: 协议也就是你定义的scheme
hostname: 地址域
port:端口
path:路径
params:参数
在Android中的用法
在AndroidManifest.xml中定义intent-filter,这里我给出部分代码
<activity
android:name=".SchemeTargetActivity"
android:launchMode="singleTask">
<!-- 要想在别的App上能成功调起App,必须添加intent过滤器 -->
<intent-filter>
<!-- 协议部分 可以随便设置 还可以加一些host port path 等,协议规则越详细定位界面更精确,-->
<!--<data android:scheme="bruce"></data>-->
<data android:scheme="bruce"
android:host="baidu"
android:port="8080"
android:path="/tieba"
></data>
<!-- 必须设置 -->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 如果需要外部网页打开本页面,还需要设置这个 -->
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
为什么设置singleTask就是为了防止生成多个实例多次启动这个页面。如果有传参,我们可以重写onNewIntent获取参数
下面我给出两个activity的代码,注意这里两个activity来自不同的应用。我姑且定为C应用,D应用。 C调用D
C应用的activity代码
/**
* DATE:2018/3/21
* USER: liuzj
* DESC:
* email:liuzj@hi-board.com
*/
public class BActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
}
public void scheme(View view) {
if (hasApplication()) {
Toast.makeText(this, "有目标界面", Toast.LENGTH_SHORT).show();
Uri uri = Uri.parse("bruce://baidu:8080/tieba");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}else {
Toast.makeText(this, "没有目标界面", Toast.LENGTH_SHORT).show();
}
}
/**
* 判断是否安装了应用
* @return true 为已经安装
*/
private boolean hasApplication() {
PackageManager manager = getPackageManager();
Intent action = new Intent(Intent.ACTION_VIEW);
action.setData(Uri.parse("bruce://baidu:8080/tieba"));
List list = manager.queryIntentActivities(action, PackageManager.GET_RESOLVED_FILTER);
return list != null && list.size() > 0;
}
}
D应用的activit代码如下:
/**
* DATE:2018/3/22
* USER: liuzj
* DESC:
* email:liuzj@hi-board.com
*/
public class SchemeTargetActivity extends AppCompatActivity {
private static final String TAG = "SchemeTargetActivity";
private TextView text;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scheme);
text = (TextView) findViewById(R.id.tv);
Uri uri = getIntent().getData();
if (uri != null) {
dispatchUri(uri);
} else {
Log.e(TAG, "Uri is null");
}
}
/**
* 这里可以做一些获取你从uri中设置的信息
*
* @param uri
*/
private void dispatchUri(Uri uri) {
String uriStr = uri.toString();
Log.e(TAG, "dispatchUri: 39---" + uriStr);
Log.e(TAG, "dispatchUri: 40---" + uri.getScheme());
text.setText(uri.getScheme());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
Log.e(TAG, "onNewIntent: 48--------" + uri.toString());
text.setText(uri.toString());
}
}
你以为到了这里就要结束了吗?怎么可能。我们来玩一玩通过短信链接来打开应用
把协议改一改
<activity
android:name=".SchemeTargetActivity"
android:launchMode="singleTask">
<!-- 要想在别的App上能成功调起App,必须添加intent过滤器 -->
<intent-filter>
<!-- 协议部分 可以随便设置 还可以加一些host port path 等,协议规则越详细定位界面更精确,-->
<!--<data android:scheme="bruce"></data>-->
<data
android:scheme="bruce"
android:host="mytest.com"
android:path="/get"
>
</data>
<!-- 必须设置 -->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 如果需要外部网页打开本页面,还需要设置这个 -->
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
其实scheme设置成http也是可以的但是怕用户会通过浏览器去打开,所以为了避免这种问题这里的scheme我们自己写一个
写个html
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="Refresh" content="0;url=bruce://mytest.com/get" />
<title>Android测试</title>
</head>
<body>
</body>
</html>
即只要点击网址我们就会重定向去打开app,前端代码写的不好,多见谅。实际开发中前端代码还可通过超时判断用户是否安装了app,没有安装就去下载页面,安装了app就可以打开app跳转到该页面。