1.原生跳轉實現
- Google提供的原聲路由主要是通過intent,可以分成顯示和隱式兩種。顯示的方案會導致類之間的直接依賴問題,耦合嚴重;隱式intent需要的配置清單中統一聲明,首先有個暴露的問題,另外在多模塊開發中協作也比較困難。只要調用startActivity後面的環節我們就無法控制了,在出現錯誤時無能爲力。
-
傳統跳轉方式
-
第一種,通過intent跳轉
- 第二種,通過aidl跳轉
- 第三種,通過scheme協議跳轉
- 爲何需要路由
- 顯示Intent:項目龐大以後,類依賴耦合太大,不適合組件化拆分
- 隱式Intent:協作困難,調用時候不知道調什麼參數
- 每個註冊了Scheme的Activity都可以直接打開,有安全風險
- AndroidMainfest集中式管理比較臃腫
- 無法動態修改路由,如果頁面出錯,無法動態降級
- 無法動態攔截跳轉,譬如未登錄的情況下,打開登錄頁面,登錄成功後接着打開剛纔想打開的頁面
- H5、Android、iOS地址不一樣,不利於統一跳轉
2.ARouter使用
2.1 ARouter的優勢
- 支持直接解析標準URL進行跳轉,並自動注入參數到目標頁面中
- 支持多模塊工程使用
- 支持添加多個攔截器,自定義攔截順序
- 支持依賴注入,可單獨作爲依賴注入框架使用
- 支持InstantRun
- 支持MultiDex(Google方案)
- 映射關係按組分類、多級管理,按需初始化
- 支持用戶指定全局降級與局部降級策略
- 頁面、攔截器、服務等組件均自動註冊到框架
- 支持多種方式配置轉場動畫
- 支持獲取Fragment
- 完全支持Kotlin以及混編(配置見文末 其他#5)
- 支持第三方 App 加固(使用 arouter-register 實現自動註冊)
- 支持生成路由文檔
- 提供 IDE 插件便捷的關聯路徑和目標類
2.2.ARouter的結構
- ARouter主要由三部分組成,包括對外提供的api調用模塊、註解模塊以及編譯時通過註解生產相關的類模塊。
- arouter-annotation註解的聲明和信息存儲類的模塊
- arouter-compiler編譯期解析註解信息並生成相應類以便進行注入的模塊
- arouter-api核心調用Api功能的模塊
2.3ARouter的典型應用
- 從外部URL映射到內部頁面,以及參數傳遞與解析
- 跨模塊頁面跳轉,模塊間解耦
- 攔截跳轉過程,處理登陸、埋點等邏輯
- 跨模塊API調用,通過控制反轉來做組件解耦
2.4 Arouter引入
以下主要針對下面1.4.1版本使用,不是github最新版本哦。
2.4.1 添加依賴
api "com.alibaba:arouter-api:1.4.1"
annotationProcessor "com.alibaba:arouter-compiler:1.2.2"
2.4.2 添加配置
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
2.4.3 添加註解
// 在支持路由的頁面上添加註解(必選)
// 這裏的路徑需要注意的是至少需要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
2.4.4初始化SDK
if (isDebug()) { // 這兩行必須寫在init之前,否則這些配置在init過程中將無效
ARouter.openLog(); // 打印日誌
ARouter.openDebug(); // 開啓調試模式(如果在InstantRun模式下運行,必須開啓調試模式!線上版本需要關閉,否則有安全風險)
}
ARouter.init(mApplication); // 儘可能早,推薦在Application中初始化
2.4.5發起路由操作
// 1. 應用內簡單的跳轉(通過URL跳轉在'進階用法'中)
ARouter.getInstance().build("/test/activity").navigation();
// 2. 跳轉並攜帶參數
ARouter.getInstance().build("/test/1")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.navigation();
2.4.6 添加混淆規則(如果使用了Proguard)
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式獲取 Service,需添加下面規則,保護接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 單類注入,即不定義接口實現 IProvider,需添加下面規則,保護實現
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
2.4.7 使用 Gradle 插件實現路由表的自動加載 (可選)
apply plugin: 'com.alibaba.arouter'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.alibaba:arouter-register:?"
}
}
可選使用,通過 ARouter 提供的註冊插件進行路由表的自動加載(power by AutoRegister), 默認通過掃描 dex 的方式 進行加載通過 gradle 插件進行自動註冊可以縮短初始化時間解決應用加固導致無法直接訪問 dex 文件,初始化失敗的問題,需要注意的是,該插件必須搭配 api 1.3.0 以上版本使用!
2.4.8 使用 IDE 插件導航到目標類 (可選)
在 Android Studio 插件市場中搜索 ARouter Helper
, 或者直接下載文檔上方 最新版本
中列出的 arouter-idea-plugin
zip 安裝包手動安裝,安裝後 插件無任何設置,可以在跳轉代碼的行首找到一個圖標 () 點擊該圖標,即可跳轉到標識了代碼中路徑的目標類
2.4.9 普通跳轉還可以通過利用Uri方法:
Uri uri=Uri.parse("/path/bactivity");
ARouter.getInstance().build(uri).navigation();
PS: Uri.parse的時候,改爲完整路徑也是支持的,例如改爲val uri = Uri.parse(“tpnet://m.aliyun.com/path/bactivity”),也可以成功跳轉到BActivity
3.進階用法
3.1通過URL跳轉
Url跳轉就是可以根據url來跳轉,可以從網頁跳到Activity
3.1.1 網頁url正常跳轉Activity
首先定義一個Activity作爲中轉,網頁的鏈接都跳到這個Activity,然後再從這個Activity打開網頁需要打開的Activity
public class SchameFilterActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation();
finish();
}
}
該Activity的manifest爲:
<activity android:name=".activity.scheme.SchameFilterActivity">
<!-- 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>
</activity>
然後定義你要跳轉到的Activity,這裏定義一個UrlTargetActivity (記得在Manifest說明):
@Route(path = ARouterConstant.ACTIVITY_test_activity1)
public class UrlTargetActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_target);
TextView tv=findViewById(R.id.textView4);
tv.setText("當前頁面是:"+getLocalClassName());
}
}
然後在手機打開一個網頁,網頁內容爲:
<a href="arouter://m.aliyun.com/test/activity1">arouter://m.aliyun.com/test/activity1</a></p>
點擊了這個網頁鏈接之後,就到根據"arouter://m.aliyun.com(scheme://host)跳轉到SchemeFilterActivity這個Activity,然後在這個Activity利用ARouter 根據path = test/activity1跳轉到UrlTargetActivity
3.2 參數傳遞
3.3聲明攔截器(攔截跳轉過程,面向切面編程)
攔截器的意思是,例如你想在 AActivity跳到BActivity,如果有攔截器,就可以把這個過程攔截下來,做一些處理(禁止跳轉、修改參數)。
攔截器使用和Activity@Route
差不多,只不過攔截器是使用另外一個註解@Interceptor
。有兩個變量,priority是攔截器的優先級,值越小優先級越高,會優先攔截。name是攔截器的名稱,開發也不怎麼用。
添加攔截器的方法是利用Interceptor
註解,實現IInterceptor
接口。例如我添加一個攔截器:
/ 比較經典的應用就是在跳轉過程中處理登陸事件,這樣就不需要在目標頁重複做登陸檢查
// 攔截器會在跳轉之間執行,多個攔截器會按優先級順序依次執行
@Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
@Override
public void init(Context context) {
// 攔截器的初始化,會在sdk初始化的時候調用該方法,僅會調用一次
Log.e("arouterinterceptor", "攔截器初始化");
}
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
if (!TextUtils.isEmpty(postcard.getPath())
&& postcard.getPath().equals("/path/bactivity")) {
postcard.withString("extra", "我是在攔截器中附加的參數");
}
if(callback!=null){
callback.onContinue(postcard);
}
//終止跳轉
//callback.onInterrupt(null)
//拋出異常
// callback.onInterrupt(RuntimeException("我覺得有點異常"))
// onContinue和onInterrupt至少需要調用其中一種,否則不會繼續路由
}
}
在攔截器實現類使用註解@Interceptor
會自動註冊,就是在編譯期間會自動生成映射關係類,使用到的就是APT技術
這裏因爲是自動註冊的,所以可以將不同功能的攔截器放在不同功能的模塊中,只有模塊被打包到整個項目中,因爲自動註冊機制所以攔截器就會生效,如果不將這些攔截器放到模塊並打包到項目中,那就不會生效,這樣就不用去做很多註冊與反註冊的工作,這也是ARouter適用於模塊開發的原因之一。