URI分发流程与配置

概述

DefaultRootUriHandler在接收到UriRequest后,会依次尝试分发给PageAnnotationHandler、UriAnnotationHandler、RegexAnnotationHandler、StartUriHandler,如图所示。

  1. PageAnnotationHandler处理所有wm_router://page/*形式的URI跳转,根据path匹配由RouterPage注解配置的节点。

  2. UriAnnotationHandler根据URI的scheme+host,寻找并分发给对应的PathHandler,之后PathHandler再根据path匹配RouterUri注解配置的节点。

  3. RegexAnnotationHandler根据优先级和正则匹配尝试将URI分发给RouterRegex配置的每个节点。

  4. StartUriHandler尝试直接使用Android原生的隐式跳转启动URI,用于处理其他类型的URI,例如tel:*mailto:*

URI分发流程与配置 - 图1

RouterUri注解

RouterUri注解可用于Activity或UriHandler的非抽象子类。Activity也会被转化成UriHandler,在Activity中可以通过Intent.getData()获取到URI。

参数如下:

  • path:跳转URI要用的path,必填。path应该以”/“开头,支持配置多个path。
  • scheme、host:跳转URI的scheme和host,可选。
  • exported:是否允许外部跳转,可选,默认为false。
  • interceptors:要添加的Interceptor,可选,支持配置多个。

说明:

  1. WMRouter支持多scheme+host+path的跳转,也支持只有path的跳转。如果RouterUri中配置了scheme、host、path,则跳转时应使用scheme+host+path的完整路径;如果RouterUri中只配置了path,则跳转应直接使用path。

  2. 由于多数场景下往往只需要一个固定的scheme+host,不想在每个RouterUri注解上都写一遍scheme、host,这种场景可以在初始化时用new DefaultRootUriHandler("scheme", "host")指定默认的scheme、host,RouterUri没有配置的字段会使用这个默认值。

举例

1、用户账户页面只配置path;跳转前要先登录,因此添加了一个LoginInterceptor。

  1. @RouterUri(path = "/account", interceptors = LoginInterceptor.class)
  2. public class UserAccountActivity extends Activity {
  3. }
  1. Router.startUri(context, "/account");

2、一个页面配置多个path。

  1. @RouterUri(scheme = "demo_scheme", host = "demo_host", path = {"/path1" "/path2"})
  2. public class TestActivity extends Activity {
  3. }
  1. Router.startUri(context, "demo_scheme://demo_host/path1");
  2. Router.startUri(context, "demo_scheme://demo_host/path2");

3、根据后台下发的ABTest策略,同一个链接跳转不同的Activity。其中AbsActivityHandler是WMRouter提供的用于跳转Activity的UriHandler通用基类。

  1. @RouterUri(path = "/home")
  2. public class HomeABTestHandler extends AbsActivityHandler {
  3. @NonNull
  4. @Override
  5. protected Intent createIntent(@NonNull UriRequest request) {
  6. if (FakeABTestService.getHomeABStrategy().equals("A")) {
  7. return new Intent(request.getContext(), HomeActivityA.class);
  8. } else {
  9. return new Intent(request.getContext(), HomeActivityB.class);
  10. }
  11. }
  12. }
  1. Router.startUri(context, "/home");

RouterRegex注解

RouterRegex注解也可以用于Activity和UriHandler,通过正则进行URI匹配。

参数如下:

  • regex:正则表达式,必填。用于匹配完整的URI字符串。
  • priority:优先级,数字越大越先匹配,可选,默认为0。优先级相同时,不保证先后顺序。
  • exported:是否允许外部跳转,可选,默认为false。
  • interceptors:要添加的Interceptor,可选,支持配置多个。

举例

1、对于指定域名的http(s)链接,使用特定的WebViewActivity打开。

  1. @RouterRegex(regex = "http(s)?://(.*\\.)?(meituan|sankuai|dianping)\\.(com|info|cn).*", priority = 2)
  2. public class WebViewActivity extends BaseActivity {
  3. }

2、对于其他http(s)链接,使用系统浏览器打开。

  1. @RouterRegex(regex = "http(s)?://.*", priority = 1)
  2. public class SystemBrowserHandler extends UriHandler {
  3. @Override
  4. protected boolean shouldHandle(@NonNull UriRequest request) {
  5. return true;
  6. }
  7. @Override
  8. protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
  9. try {
  10. Intent intent = new Intent();
  11. intent.setAction(Intent.ACTION_VIEW);
  12. intent.setData(request.getUri());
  13. request.getContext().startActivity(intent);
  14. callback.onComplete(UriResult.CODE_SUCCESS);
  15. } catch (Exception e) {
  16. callback.onComplete(UriResult.CODE_ERROR);
  17. }
  18. }
  19. }

RouterPage注解

实际项目开发过程中,URI跳转常有两种需求:一种是运营后台配置和下发链接让客户端跳转,跳转协议需要和各端保持一致;另一种是App拆分多个工程,需要在工程之间跳转页面,使用路由组件代替显式跳转,实现解耦。

由于种种历史原因,这两套URI可能会出现不兼容的问题,因此需要对两套URI分别做实现。RouterPage注解就是用于实现内部页面跳转而设计的。

RouterPage注解用于指定内部页面跳转,和RouterUri注解相比,RouterPage注解对应的scheme和host为固定的wm_router://page,不可配置,exported为false也不可配置。

参数如下:

  • path:跳转URI要用的path,必填。path应该以”/“开头,支持配置多个path。
  • interceptors:要添加的Interceptor,可选,支持配置多个。

举例

  1. // demo://demo/account
  2. @RouterUri(path = "/account", scheme = "demo", host = "demo")
  3. // wm_router://page/account
  4. @RouterPage(path = "/account")
  5. public class AccountActivity {
  6. @Override
  7. protected void onCreate(@Nullable Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. if (PageAnnotationHandler.isPageJump(getIntent())) {
  10. // ...
  11. } else {
  12. // ...
  13. }
  14. }
  15. }
  1. // 对应RouterUri的配置
  2. Router.startUri(context, "demo://demo/account");
  1. // 对应RouterPage的配置
  2. Router.startUri(context, PageAnnotationHandler.SCHEME_HOST + "/account");
  3. // 或直接用常量的值
  4. Router.startUri(context, "wm_router://page/account");