URI分发流程与配置
概述
DefaultRootUriHandler在接收到UriRequest后,会依次尝试分发给PageAnnotationHandler、UriAnnotationHandler、RegexAnnotationHandler、StartUriHandler,如图所示。
PageAnnotationHandler处理所有
wm_router://page/*
形式的URI跳转,根据path匹配由RouterPage
注解配置的节点。UriAnnotationHandler根据URI的scheme+host,寻找并分发给对应的PathHandler,之后PathHandler再根据path匹配
RouterUri
注解配置的节点。RegexAnnotationHandler根据优先级和正则匹配尝试将URI分发给
RouterRegex
配置的每个节点。StartUriHandler尝试直接使用Android原生的隐式跳转启动URI,用于处理其他类型的URI,例如
tel:*
、mailto:*
。
RouterUri注解
RouterUri注解可用于Activity或UriHandler的非抽象子类。Activity也会被转化成UriHandler,在Activity中可以通过Intent.getData()
获取到URI。
参数如下:
- path:跳转URI要用的path,必填。path应该以”/“开头,支持配置多个path。
- scheme、host:跳转URI的scheme和host,可选。
- exported:是否允许外部跳转,可选,默认为false。
- interceptors:要添加的Interceptor,可选,支持配置多个。
说明:
WMRouter支持多scheme+host+path的跳转,也支持只有path的跳转。如果RouterUri中配置了scheme、host、path,则跳转时应使用scheme+host+path的完整路径;如果RouterUri中只配置了path,则跳转应直接使用path。
由于多数场景下往往只需要一个固定的scheme+host,不想在每个RouterUri注解上都写一遍scheme、host,这种场景可以在初始化时用
new DefaultRootUriHandler("scheme", "host")
指定默认的scheme、host,RouterUri没有配置的字段会使用这个默认值。
举例
1、用户账户页面只配置path;跳转前要先登录,因此添加了一个LoginInterceptor。
@RouterUri(path = "/account", interceptors = LoginInterceptor.class)
public class UserAccountActivity extends Activity {
}
Router.startUri(context, "/account");
2、一个页面配置多个path。
@RouterUri(scheme = "demo_scheme", host = "demo_host", path = {"/path1", "/path2"})
public class TestActivity extends Activity {
}
Router.startUri(context, "demo_scheme://demo_host/path1");
Router.startUri(context, "demo_scheme://demo_host/path2");
3、根据后台下发的ABTest策略,同一个链接跳转不同的Activity。其中AbsActivityHandler是WMRouter提供的用于跳转Activity的UriHandler通用基类。
@RouterUri(path = "/home")
public class HomeABTestHandler extends AbsActivityHandler {
@NonNull
@Override
protected Intent createIntent(@NonNull UriRequest request) {
if (FakeABTestService.getHomeABStrategy().equals("A")) {
return new Intent(request.getContext(), HomeActivityA.class);
} else {
return new Intent(request.getContext(), HomeActivityB.class);
}
}
}
Router.startUri(context, "/home");
RouterRegex注解
RouterRegex注解也可以用于Activity和UriHandler,通过正则进行URI匹配。
参数如下:
- regex:正则表达式,必填。用于匹配完整的URI字符串。
- priority:优先级,数字越大越先匹配,可选,默认为0。优先级相同时,不保证先后顺序。
- exported:是否允许外部跳转,可选,默认为false。
- interceptors:要添加的Interceptor,可选,支持配置多个。
举例
1、对于指定域名的http(s)链接,使用特定的WebViewActivity打开。
@RouterRegex(regex = "http(s)?://(.*\\.)?(meituan|sankuai|dianping)\\.(com|info|cn).*", priority = 2)
public class WebViewActivity extends BaseActivity {
}
2、对于其他http(s)链接,使用系统浏览器打开。
@RouterRegex(regex = "http(s)?://.*", priority = 1)
public class SystemBrowserHandler extends UriHandler {
@Override
protected boolean shouldHandle(@NonNull UriRequest request) {
return true;
}
@Override
protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(request.getUri());
request.getContext().startActivity(intent);
callback.onComplete(UriResult.CODE_SUCCESS);
} catch (Exception e) {
callback.onComplete(UriResult.CODE_ERROR);
}
}
}
RouterPage注解
实际项目开发过程中,URI跳转常有两种需求:一种是运营后台配置和下发链接让客户端跳转,跳转协议需要和各端保持一致;另一种是App拆分多个工程,需要在工程之间跳转页面,使用路由组件代替显式跳转,实现解耦。
由于种种历史原因,这两套URI可能会出现不兼容的问题,因此需要对两套URI分别做实现。RouterPage注解就是用于实现内部页面跳转而设计的。
RouterPage注解用于指定内部页面跳转,和RouterUri注解相比,RouterPage注解对应的scheme和host为固定的wm_router://page
,不可配置,exported为false也不可配置。
参数如下:
- path:跳转URI要用的path,必填。path应该以”/“开头,支持配置多个path。
- interceptors:要添加的Interceptor,可选,支持配置多个。
举例
// demo://demo/account
@RouterUri(path = "/account", scheme = "demo", host = "demo")
// wm_router://page/account
@RouterPage(path = "/account")
public class AccountActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PageAnnotationHandler.isPageJump(getIntent())) {
// ...
} else {
// ...
}
}
}
// 对应RouterUri的配置
Router.startUri(context, "demo://demo/account");
// 对应RouterPage的配置
Router.startUri(context, PageAnnotationHandler.SCHEME_HOST + "/account");
// 或直接用常量的值
Router.startUri(context, "wm_router://page/account");