从0到1实现一个Android路由(1)——初探路由

Android路由

什么是路由?最初接触路由是在大学计算机网络中,网络层IP报文传输会涉及一个路由表的概念,路由表由源IP、目的IP组成,起始就是一个映射表。Android路由也是一个映射表,映射什么呢? 这里先类比一下,如果把手机类比于浏览器,那么每个app就可以类比于一个个的网站,比如百度、头条等等,那么每个app的一个页面就可以类比于一个个网站里面的页面,浏览器的每个页面由url定义,给不同url传递不同参数,页面的表现形式还稍有不通过,这里的映射关系就是url对应页面,每个app的每个页面也可以类比于网站的页面,那是不是可以采用url的方式来定义每个页面呢?这样是不是也就有了url对应app页面的映射关系,如果有了这样的映射关系,给定一个url,那是不是就可以知道跳转到某一个具体的Activity了?Android路由其实就是解决这样的问题,那么实现一个最基础的Android路由主要有以下几步:

  1. 定义url,分配url给Activity;
  2. 建立路由表,url----->Activity
  3. 处理跳转,给定一个url,能跳转到具体的Activity。

第一个五张俱全的例子

第一个例子呢,很扯淡,但是呢,足以说明Android路由的意义。这里定义了两个Activity,其中SecondActivity用url(/secondActivity)表示,MainActivity启动SecondActivity是通过路由表来启动的,处理跳转的逻辑如下:

val routeMap = mapOf("easyrouter://demo/secondActivity" to SecondActivity::class.java)
fun goToPages(context: Context, url: String) {    for ((key, value) in routeMap) {        if (key == url) {            context.startActivity(Intent(context, value))        }    }}

这里就做了匹配,然后跳转,虽然很扯,但足以说明路由的精髓,后面会一步步地丰满。 这里对应最基本的路由,每一点都有:

  1. "/secondActivity"是url
  2. routeMap是路由表,这里可以理解成一个静态路由,即对应关系是硬编码的
  3. goToPages()方法处理url的跳转

下面一步步地丰满我们的EasyRouter。

外部app打开链接进入app

经常有这样的场景,在浏览器里会出现欢唤醒app的情况,唤醒后如何跳转到指定页面的呢?这里先解决这个问题,这样至少,我们的路由,外部打开内部页面是没有问题的。

清单文件注册scheme

解决这个问题,需要给我们的app里面某个页面添加scheme。这里我们用ProxyActivity进行scheme的设置,清单文件里的配置如下:

<activity android:name=".ProxyActivity">            <intent-filter>                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="easyrouter"                      android:host="demo"/>            </intent-filter>        </activity>

这里,ProxyActivity可以被easyrouter://demo/xxxx这样的url打开。而action/category表示支持打开一些url,类似浏览器,只不过是打开easyrouter这样的scheme,而不是http或https。

Activity实现scheme跳转

再来看ProxyActivity的实现,

override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        intent.data?.apply {            goToPages(this@ProxyActivity, path)            finish()        }    }

intent.data可以获取从外部or其他页面传递的Uri参数,当从浏览器中打开时,链接的信息就会带过来,这里可以看到如果是easyrouter的scheme,那就交给goToPages()进行跳转。

HTML页面

html页面比较简单,就一个点击跳转的链接,

 <a href="easyrouter://demo/secondActivity">点击跳转到App</a></body>

然后用浏览器加载,第一次会提示是否用我们的demo打开,打开后就不再提示了,可以看到上面的链接也能实现从外部打开SecondActivity了。

应用内部打开外部url

所谓外部url,通常是网页,比如是应用的h5页面,Android加载网页需要用到WebView,WebView的定义如下:

override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_web_view)
        webView.apply {            settings.apply {                javaScriptEnabled = true                javaScriptCanOpenWindowsAutomatically = true                setSupportMultipleWindows(true)            }            webViewClient = WebViewClient()            webChromeClient = WebChromeClient()        }
        webView.loadUrl(intent.getStringExtra("external_url"))    }

再回头看goToPages()对url的处理,如下:

fun goToPages(context: Context, url: String) {    for ((key, value) in routeMap) {        if (key == url) {            context.startActivity(Intent(context, value))        } else if (url.startsWith("http")) {            context.startActivity(Intent(context, WebViewActivity::class.java).apply {                putExtra("external_url", url)            })        }    }}

可以看到,针对http开头的url,交由WebViewActivity进行加载。

总结

至此,第一个足以说明路由概念的例子就结束了,主要有静态路由表,控制路由跳转的逻辑,支持了外部应用跳转到应用,也支持应用内跳转原生页面和网页页面。那么一个优秀的路由应该是怎样的呢?或者说这个例子有哪些不足呢?

  1. 静态路由表,如果应用有很多应用,一个个的添加是不是很难维护?
  2. 跳转还不支持传参、不支持拦截
  3. 没有降级策略,比如有人恶意输入一个不存在页面的scheme,那app就显示不正常了。

后面会根据上面的几个不足一步步地完善路由。

关于代码,可以参考first_demo分支的代码。

参考阅读

  • 通过Scheme协议打开APP界面
  • android-Scheme与网页跳转原生的三种方式
  • android webview loadurl弹出系统浏览器问题
  • ARouter
  • 安居客 Android 项目架构演进
  • 大规模团队协同开发利器:阿里Atlas正式开源!
  • Atlas
  • Android Router 从 0 到 1
  • 一文了解Android中路由(Router)的实现
  • 考拉Android客户端路由总线设计
  • WMRouter
  • 美团外卖Android开源路由框架

原文发布于微信公众号 - 每天学点Android知识(android_every_day)

原文发表时间:2019-04-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券