ARouter解析之URL跳转

ARouter解析

ARouter解析之URL跳转

在ARouter Demo中,点击通过URL跳转,会通过WebView加载html

1
2
3
4
ARouter.getInstance()
.build("/test/webview")
.withString("url", "file:///android_asset/schame-test.html")
.navigation();

方案设计

通常webview上的url跳转会给webview设置一个webviewClient,然后通过shouldOverrideUrlLoading方法,在方法中构造intent进行跳转,简单示意如下:

1
2
3
4
5
6
7
8
9
10
11
webview.setWebViewClient(new WebViewClient(){    
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url != null && url.contains("arouter")){
Intent intent = new Intent(TestWebview.this, Test1Activity.class);
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
});

这种做法往往会有很多缺陷

  1. 硬编码,业务复杂时候webview变得很臃肿,耦合严重不利于维护
  2. 当外不应用打开链接需要跳转到我们的App某个Activity中时候,此时就不在自己App的webview环境中,这样就无法满足跳转需求的,因此这种方式也不够强大

ARouter就是通过注册一个没有UI的界面作为跳板来统一处理,scheme是arouter的跳转请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<activity android:name=".SchemeFilterActivity">
<!-- Schame -->
<intent-filter>
<data
android:host="m.aliyun.com"
android:scheme="arouter"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
<!-- App Links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="m.aliyun.com"
android:scheme="http"/>
<data
android:host="m.aliyun.com"
android:scheme="https"/>
</intent-filter>
</activity>

在清单文件中注册了SchemeFilterActivity这个activity

  • scheme就是arouter,
  • host就是m.aliyun.com,
  • 其中有个category是 android.intent.category.BROWSABLE,

其中 android.intent.category.BROWSABLE就是让浏览器可以打这个Actvity,当然要符合host和scheme,这样就可以在WebView中跳转SchemeFilterActivity这个界面了。

这种方式的优点:

  1. 首先是页面跳转的灵活性,
    比如需要和H5中进行通信,H5需要跳转到App本地的页面,Native和H5只需要统一一个path文档即可,H5可以通过path构造一个url就可以实现跳转到对应页面的功能,很类似浏览器,实现很好的解耦

  2. 更加的安全
    相比较于隐式的intent,每一个从外面跳转进来的页面都需要注册上intent-filter,每个页面都需要设置export=true,也就是需要让每一个页面都可以导出,在外部可以访问到。这样做会带来非常严重的安全风险,就像是一个房子有十个门还是只有一个门,看门的成本是不同的。而现在使用的这种场景只需要对外暴露出一个activity,然后在这个activity中注册一个intent-filter,这样之后所有的外部路由请求都会经过这唯一的门,然后在这个activity中获取到URL并将其交给ARouter,剩下的就由路由框架做分发了。

  3. 携带参数注入
    另外一个好处就是隐式intent跳转无法将参数自动注入,ARouter可以在url中携带参数然后自动注入

这里也需要H5链接需要按照约定的scheme来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>

<body>

<h2>跳转测试</h2>

<h2>自定义Scheme[通常来说都是这样的]</h2>
<p><a href="arouter://m.aliyun.com/test/activity1">arouter://m.aliyun.com/test/activity1</a></p>
<p><a href="arouter://m.aliyun.com/test/activity1?url=https%3a%2f%2fm.abc.com%3fa%3db%26c%3dd">测试URL Encode情况</a></p>
<p><a href="arouter://m.aliyun.com/test/activity1?name=alex&age=18&boy=true&high=180&obj=%7b%22name%22%3a%22jack%22%2c%22id%22%3a666%7d">arouter://m.aliyun.com/test/activity1?name=alex&age=18&boy=true&high=180&obj={"name":"jack","id":"666"}</a></p>
<p><a href="arouter://m.aliyun.com/test/activity2">arouter://m.aliyun.com/test/activity2</a></p>
<p><a href="arouter://m.aliyun.com/test/activity2?key1=value1">arouter://m.aliyun.com/test/activity2?key1=value1</a></p>
<p><a href="arouter://m.aliyun.com/test/activity3?name=alex&age=18&boy=true&high=180">arouter://m.aliyun.com/test/activity3?name=alex&age=18&boy=true&high=180</a></p>

<h2>App Links[防止被App屏蔽]</h2>
<p><a href="http://m.aliyun.com/test/activity1">http://m.aliyun.com/test/activity1</a></p>
<p><a href="http://m.aliyun.com/test/activity2">http://m.aliyun.com/test/activity2</a></p>

</body>
</html>

URL中转SchemeFilterActivity

点击url之后通过清单文件的匹配intent-filter中的data, action, category的标签,其中category匹配任意一个即可。接着就来到SchemeFilterActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SchemeFilterActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// 直接通过ARouter处理外部Uri
Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
finish();
}
});
}
}

后续处理就跟之前路由逻辑一致了,这里就不赘述了

0%