Android Activity URL Scheme的介绍与应用

有可能说到URL Scheme,很多还不太了解,甚至根本就不知道是什么东西。下面我们来好好认识一下它。

什么是URL Scheme

URL Scheme 是Android中一种页面内跳转的协议; 也可以被称为 URLRouter。它可以通过匹配 URI 去打开对应的Activity。就类似网页中,我们打开网页的方式去打开一个Activity。当然这是一种通过Intent隐式打开Activity的方式。现在模块化开发时,遇到特别复杂的模块组合,也有可能会用的它。

URL Scheme 协议格式

我们通过Scheme启动Activity时,是通过Intent.setData(Uri uri)启动Activity的。它需要的参数是一个URI。所以URL Scheme的协议的格式其实就是 URI的格式。

一个完整的Scheme的协议格式由 scheme、userInfo、host、port、path、query和fragment 组成。结构如下:

scheme://userInfo@host:port/path?query#fragment

其中 scheme://是固定的格式。userInfo@ 可以省略,host 是必须的。port 、query 和 fragment 也是可以省略的。

其中scheme既可以是Android已经定义好的协议,也可使用我们自定义的。Android 常见的scheme 协议有:content 、file、http 等。如果我们自定义协议就可以随意使用一些字符串来限定协议。当然最好是有一定含义的字符串。如下面的协议:

xieyi://[email protected]:8080/userDetails?param1=参数1¶m2=参数2#片段"
  • xieyi : 即为 Scheme ,即我们自定义的Scheme 协议名称
  • ricky :即为用户信息,注意它跟host 之间一定要跟上 @ 符号
  • me.ricky.sample : 即为 host ;这里我用了一个包名
  • 8080 : 即为 port ;自定义协议的端口号
  • userDetails: 即为path ,路径;代表scheme的指定的页面,我们匹配页面的时候,这里就是匹配的重点
  • param1 和 param2:即为 query ,代表我们跳转到指定界面后传递的参数
  • 片段:即为fragment,也可以把它看成跳转到指定界面后传递的参数,只不过它只能传递一个,而query 可以传递多个它会把 #后的所有的内容都看成一个片段。

Activity中Scheme的使用方式

首先我们可以确定的是,通过 scheme启动Activity 是通过Intent 隐式启动的;隐式调用需要在 AndroidManifest 里的标签下添加 来设置;使用scheme的时候需要在 标签里面设置 我们需要的 URL Scheme 信息。

Scheme相关标签介绍

接下来我们介绍一下 里的关于scheme的各个标签的含义:

常用的几个

//对应的就是我们上面提到 host
android:host="me.ricky.sample"
//路径,必须以 / 开头
android:path="/path"
//端口
android:port="8080"
//协议
android:scheme="xieyi"

不太常用的几个

//路径的前缀,必须以 /  开头
android:pathPrefix="/path"
//匹配路径的正则
android:pathPattern=".*path"

了解上面的这些,那scheme到底应该怎么用呢?

简单使用Scheme

首先我们新建一个Activity,命名为 SchemeActivity;然后在AndroidManifest里作如下配置:

<activity android:name=".SchemeActivity">
    <intent-filter>
        <action android:name="me.ricky.sample.action"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data
            android:host="me.ricky.sample"
            android:scheme="xieyi"
            />
    intent-filter>
activity>

这里我们设置最简单的Scheme设置。如果我们要启动该Activity,应该怎么办呢?

intent.setAction("me.ricky.sample.action");
startActivity(intent);

上面的代码是通过隐式的Action去启动Activity,如果你只是这样简单去启动Activity,一定是不行的,因为我们设置标签,系统无法匹配到特定的Activity,那它就会报出以下的异常:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=me.ricky.sample.action }

如果我们想完全匹配那么就需要给设置该action的Activity,指定data数据:

Uri uri = Uri.parse("xieyi://me.ricky.sample");
intent.setAction("me.ricky.sample.action");
intent.setData(uri);
startActivity(intent);  

xieyi://me.ricky.sample 其中的scheme就是 xieyi对应的是我们在 AndroidManifest中设定的android:scheme="xieyi";;me.ricky.sample对应的是我们在 AndroidManifest中设定的 android:host="me.ricky.sample"

这样就能匹配我们设定Activity了。

当然这是最简单的Scheme的使用。没有什么难度。我们启动Activity时,完全匹配了我们在AndroidManifest里设置的scheme信息。

通过SchemeURL 传递参数

xieyi://[email protected]:8080/userDetails?param1=参数1¶m2=参数2#片段"

这URI 几乎包含了URI的所有的组成。其中包含了一些参数。那么我们如何在被启动的Activity中获取这些参数呢?它的用法跟通过Intent获取额外的参数是一样的。只不过我们是通过解析URI 来获取。

如果我们将这个URI作为参数启动Activity,

Intent intent = new Intent();
Uri uri = Uri.parse("xieyi://[email protected]:8080/userDetails?param1=参数1¶m2=参数2#片段");
intent.setAction("me.ricky.sample.action");
intent.setData(uri);
startActivity(intent);

那我们可以在被启动的SchemeActivity的onCreate()方法中通过下面的方法获取URI的各个部分。

Uri uri = getIntent().getData();

String host = uri.getHost();
String authority = uri.getAuthority();//authority包括host和port两部分
String scheme = uri.getScheme();
String query = uri.getQuery();//获取的是 “param1=参数1¶m2=参数2”
String path = uri.getPath();
int port = uri.getPort();
String frag = uri.getFragment();
String userInfo = uri.getUserInfo();
String param1 = uri.getQueryParameter("param1");
String param2 = uri.getQueryParameter("param2");

这样我们就可以通过scheme 来进行Activity之间的 信息传递了。

Scheme 的匹配规则

除了上提到的 AndroidManifest中的设置数据和我们在Intent.setData(Uri uri);设定的一一对应之外。还有几个简单的依赖规则。

  • 如果没有指定scheme ,那么URI所有的参数都会无效的。也就是说它忽略data里设置其它关于Scheme的信息;而且在AndroidStudio会有报错。
  • 如果没有指定host,也是可以的;但是port参数会被忽略;

当我们通过Intent将URI参数与中的标签中指定的URI对比时,系统会只对比标签指定的部分。

  • 如果你指定了,那么所有带有该的URI 都能匹配到该。
  • 如果你指定了和authority(authority包括host和port两部分),那么所有具有相同scheme和authority的URI都能匹配到该intent-filter,而不用考虑path为何值。
  • 如果你指定了、、和 ,那么只有具有相同scheme、authority和path的URI才能匹配到该intent-filter。

需要注意,这里path设定时还可以通过 下面的属性设置

//路径的前缀,必须以 /  开头
android:pathPrefix="/path"
//匹配路径的正则
android:pathPattern=".*path"

pathPrefix指定是前缀,只要我们设定的path的前缀pathPrefix设置一致就可以通过path打开特定的Activity;同理下面的pathPattern;是通过正则来匹配path,只要能匹配通过就可以通过path打开特定的Activity。

通过Scheme跨应用启动Activity

如果要通过scheme跨应用启动Activity,其实也很简单:

Intent intent = new Intent();
Uri uri = Uri.parse("xieyi://[email protected]:8080/userDetails?param1=参数1¶m2=参数2#片段");
intent.setAction("me.ricky.sample.action");
intent.setData(uri);
startActivity(intent);

跟上面同一个应用中启动Activity时一样的,这里需要注意的是:如果不希望启动的Activity跟当前的Activity在同一个栈了,需要加上下面的代码:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

在网页中启动Activity

<a href="xieyi://[email protected]:8080/userDetails">查看用户详情a>

注意: 在网页中启动Activity 未经本人验证,只是从其它地方看到的。

另:一般隐式启动Activity,需要我们去验证一下我们的Intent指定的Activity是否存在。如果存在就可以放心的去启动相应的Activity了。

private boolean checkIntent(Intent intent) {
    PackageManager manager = getPackageManager();
    List resolveInfos = manager.queryIntentActivities(intent, PackageManager.MATCH_ALL);
    System.out.println(resolveInfos);
    return !resolveInfos.isEmpty();
}

你可能感兴趣的:(Android)