ARouter 路由 組件 跳轉 MD

Markdown版本筆記 個人GitHub首頁 個人博客 個人微信 個人郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

ARouter 路由 組件 跳轉 MD
***
目錄
===android

簡介

一個用於幫助 Android App 進行組件化改造的框架 —— 支持模塊間的路由、通訊、解耦git

ARouter官網
Demo下載github

模塊 arouter-api arouter-compiler arouter-register arouter-idea-plugin
2018-12-15 最新版本 Download Download Download as plugin

支持的功能

  • 支持直接解析標準URL進行跳轉,並自動注入參數到目標頁面中
  • 支持多模塊工程使用
  • 支持添加多個攔截器,自定義攔截順序
  • 支持依賴注入,可單獨做爲依賴注入框架使用
  • 支持InstantRun
  • 支持MultiDex
  • 映射關係按組分類、多級管理,按需初始化
  • 支持用戶指定全局降級與局部降級策略
  • 頁面、攔截器、服務等組件均自動註冊到框架
  • 支持多種方式配置轉場動畫
  • 支持獲取Fragment
  • 徹底支持Kotlin以及混編
  • 支持第三方 App 加固(使用 arouter-register 實現自動註冊)
  • 支持生成路由文檔
  • 提供IDE 插件便捷的關聯路徑和目標類

典型應用

  • 外部URL映射到內部頁面,以及參數傳遞與解析
  • 跨模塊頁面跳轉,模塊間解耦
  • 攔截跳轉過程,處理登錄、埋點等邏輯
  • 跨模塊API調用,經過控制反轉來作組件解耦

簡單使用

一、添加依賴和配置編程

android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
}

dependencies {
    api 'com.alibaba:arouter-api:x.x.x' // 須要注意的是api
    annotationProcessor 'com.alibaba:arouter-compiler:x.x.x' // 要與compiler匹配使用
}

二、添加註解json

// 在支持路由的頁面上添加註解(必選),這裏的路徑須要注意的是至少須要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity { ... }

三、初始化SDKapi

if (isDebug()) {
    ARouter.openLog();     // 打印日誌,這兩行必須寫在init以前,不然這些配置在init過程當中將無效
    ARouter.openDebug();   // 開啓調試模式(若是在InstantRun模式下運行,必須開啓調試模式!線上版本須要關閉,不然有安全風險)
}
ARouter.init(mApplication);

四、發起路由操做緩存

ARouter.getInstance().build("/test/activity").navigation(); // 應用內簡單的跳轉
ARouter.getInstance().build("/test/1")
            .withLong("key1", 666L) // 跳轉並攜帶參數
            .withString("key3", "888")
            .withObject("key4", new Test("Jack", "Rose"))
            .navigation();

五、添加混淆規則安全

-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

六、使用 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 以上版本使用!

七、使用 IDE 插件導航到目標類
在 Android Studio 插件市場中搜索 ARouter Helper, 或者直接下載文檔上方 最新版本 中列出的 arouter-idea-plugin zip 安裝包手動安裝,安裝後,插件無任何設置,能夠在跳轉代碼的行首找到一個圖標,點擊該圖標,便可跳轉到標識了代碼中路徑的目標類。

進階使用

一、經過URL跳轉
新建一個Activity用於監聽Schame事件,以後直接把url傳遞給ARouter便可

public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Uri uri = getIntent().getData();
        ARouter.getInstance().build(uri).navigation();
        finish();
    }
}

AndroidManifest.xml 中的配置

<activity android:name=".activity.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>

二、解析URL中的參數
URL中不能傳遞Parcelable類型數據,經過ARouter api能夠傳遞Parcelable對象

@Route(path = "/test/activity")
public class Test1Activity extends Activity {
    @Autowired public String name; // 爲每個參數聲明一個字段,並使用 @Autowired 標註
    @Autowired int age;
    @Autowired(name = "girl") boolean boy; // 經過name來映射URL中的不一樣參數
    @Autowired TestObj obj; // 支持解析自定義對象,URL中使用json傳遞

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ARouter.getInstance().inject(this); //注入
        Log.d("param", name + age + boy); // ARouter會自動對字段進行賦值,無需主動獲取
    }
}

若是須要傳遞自定義對象,新建一個類(並不是自定義對象類),而後實現 SerializationService,並使用@Route註解標註(方便用戶自行選擇序列化方式),例如:

@Route(path = "/yourservicegroupname/json")
public class JsonServiceImpl implements SerializationService {
    @Override
    public void init(Context context) {
        //可選,用於對序列化框架初始化
    }

    @Override
    public <T> T json2Object(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz); //自行選擇反序列化方式,好比Gson、fastjson
    }

    @Override
    public String object2Json(Object instance) {
        return JSON.toJSONString(instance); //自行選擇序列化方式,好比Gson、fastjson
    }
}

三、聲明攔截器
攔截跳轉過程,面向切面編程
比較經典的應用就是在跳轉過程當中處理登錄事件,這樣就不須要在目標頁重複作登錄檢查
攔截器會在跳轉之間執行,多個攔截器會按優先級順序依次執行。

@Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        //...條件判斷
        callback.onContinue(postcard);  // 處理完成,交還控制權
        // callback.onInterrupt(new RuntimeException("我以爲有點異常")); // 以爲有問題,中斷路由流程
        // 以上兩種至少須要調用其中一種,不然不會繼續路由
    }

    @Override
    public void init(Context context) {
        // 攔截器的初始化,會在sdk初始化的時候調用該方法,僅會調用一次
    }
}

四、處理跳轉結果
使用兩個參數的navigation方法,能夠獲取單次跳轉的結果。

ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
    @Override
    public void onFound(Postcard postcard) {
        //...
    }

    @Override
    public void onLost(Postcard postcard) {
        //...
    }
});

五、自定義全局降級策略
實現DegradeService接口,並加上一個Path內容任意的註解便可

@Route(path = "/xxx/xxx")
public class DegradeServiceImpl implements DegradeService {
    @Override
    public void onLost(Context context, Postcard postcard) {
        // do something.
    }

    @Override
    public void init(Context context) {

    }
}

六、爲目標頁面聲明更多信息
咱們常常須要在目標頁面中配置一些屬性,比方說"是否須要登錄"之類的,能夠經過 Route 註解中的 extras 屬性進行擴展。
這個屬性是一個 int 值,也就是32位,能夠配置32個開關。
剩下的能夠自行發揮,經過字節操做能夠標識32個開關,經過開關標記目標頁面的一些屬性,在攔截器中能夠拿到這個標記進行業務邏輯判斷

@Route(path = "/test/activity", extras = Consts.XXXX)

七、經過依賴注入解耦
服務管理(一) 暴露服務

public interface HelloService extends IProvider {
    String sayHello(String name); // 聲明接口,其餘組件經過接口來調用服務
}

實現接口

@Route(path = "/yourservicegroupname/hello", name = "測試服務")
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        return "hello, " + name;
    }

    @Override
    public void init(Context context) {

    }
}

服務管理(二) 發現服務

public class Test {
    @Autowired HelloService helloService;
    @Autowired(name = "/yourservicegroupname/hello") HelloService helloService2;
    HelloService helloService3;
    HelloService helloService4;

    public Test() {
        ARouter.getInstance().inject(this);
    }

    public void testService() {
        // 一、(推薦)使用依賴注入的方式發現服務,經過註解標註字段便可使用,無需主動獲取
        // Autowired註解中標註name以後,將會使用byName的方式注入對應的字段,不設置name屬性,會默認使用byType的方式發現服務(當同一接口有多個實現的時候,必須使用byName的方式發現服務)
        helloService.sayHello("Vergil");
        helloService2.sayHello("Vergil");

        // 二、使用依賴查找的方式發現服務,主動去發現服務並使用,下面兩種方式分別是byName和byType
        helloService3 = ARouter.getInstance().navigation(HelloService.class);
        helloService4 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation();
        helloService3.sayHello("Vergil");
        helloService4.sayHello("Vergil");
    }
}

更多功能

一、初始化中的其餘設置

ARouter.openLog(); // 開啓日誌
ARouter.openDebug(); // 使用InstantRun的時候,須要打開該開關,上線以後關閉,不然有安全風險
ARouter.printStackTrace(); // 打印日誌的時候打印線程堆棧

二、詳細的API說明

ARouter.getInstance().build("/home/main").navigation(); // 構建標準的路由請求
ARouter.getInstance().build("/home/main", "ap").navigation(); // 構建標準的路由請求,並指定分組
ARouter.getInstance().build(uri).navigation(); // 構建標準的路由請求,經過Uri直接解析
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5); // startActivityForResult 形式跳轉
ARouter.getInstance().build("/home/main").with(params).navigation(); // 直接傳遞Bundle
ARouter.getInstance().build("/home/main").withFlags().navigation(); // 指定Flag
ARouter.getInstance().withObject("key", new TestObj("Jack", "Rose")).navigation(); // 對象傳遞
ARouter.getInstance().build("/home/main").getExtra(); // 以爲接口不夠多,能夠直接拿出Bundle賦值
ARouter.getInstance().build("/home/main").greenChannel().navigation();// 使用綠色通道(跳過全部的攔截器)
ARouter.setLogger();// 使用本身的日誌工具打印日誌
ARouter.setExecutor();// 使用本身提供的線程池

Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation(); //獲取Fragment

ARouter.getInstance().build("/test/activity2")
    .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom).navigation(this); //轉場動畫
ARouter.getInstance().build("/test/activity2")
    .withOptionsCompat(compat).navigation(this); // 轉場動畫(API16+)

三、獲取原始的URI

String uriStr = getIntent().getStringExtra(ARouter.RAW_URI);

四、重寫跳轉URL
實現 PathReplaceService 接口,並加上一個 Path 內容任意的註解便可

@Route(path = "/xxx/xxx") // 必須標明註解
public class PathReplaceServiceImpl implements PathReplaceService {
    /**
    * For normal path.
    *
    * @param path raw path
    */
    String forString(String path) {
        return path;    // 按照必定的規則處理以後返回處理後的結果
    }

    /**
    * For uri type.
    *
    * @param uri raw uri
    */
    Uri forUri(Uri uri) {
        return url; // 按照必定的規則處理以後返回處理後的結果
    }
}

五、生成路由文檔
生成的文檔路徑:build/generated/source/apt/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]
            }
        }
    }
}

其餘

一、路由中的分組概念

  • SDK中針對全部的路徑進行分組,只有在分組中的某一個路徑第一次被訪問的時候,該分組纔會被初始化
  • 能夠經過 @Route 註解主動指定分組,不然使用路徑中第一段字符串/*/做爲分組
  • 注意:一旦主動指定分組以後,應用內路由須要使用 ARouter.getInstance().build(path, group) 進行跳轉,手動指定分組,不然沒法找到
@Route(path = "/test/1", group = "app")

二、攔截器和服務的異同

  • 攔截器和服務所須要實現的接口不一樣,可是結構相似,都存在 init(Context) 方法,可是二者的調用時機不一樣
  • 攔截器由於其特殊性,會被任何一次路由所觸發,攔截器會在ARouter初始化的時候異步初始化,若是第一次路由的時候攔截器尚未初始化結束,路由會等待,直到初始化完成。
  • 服務沒有該限制,某一服務可能在App整個生命週期中都不會用到,因此服務只有被調用的時候纔會觸發初始化操做

三、Kotlin項目中的配置方式
能夠參考 module-kotlin 模塊中的寫法

apply plugin: 'kotlin-kapt'

kapt {
    arguments {
        arg("AROUTER_MODULE_NAME", project.getName())
    }
}

dependencies {
    compile 'com.alibaba:arouter-api:x.x.x'
    kapt 'com.alibaba:arouter-compiler:x.x.x'
}

Q&A

一、"W/ARouter::: ARouter::No postcard[ ]"

二、"W/ARouter::: ARouter::There is no route match the path [/xxx/xxx], in group [xxx][ ]"

三、開啓InstantRun以後沒法跳轉(高版本Gradle插件下沒法跳轉)?
由於開啓InstantRun以後,不少類文件不會放在本來的dex中,須要單獨去加載,ARouter默認不會去加載這些文件,由於安全緣由,只有在開啓了openDebug以後,ARouter纔回去加載InstantRun產生的文件,因此在以上的狀況下,須要在init以前調用openDebug。

四、TransformException:java.util.zip.ZipException: duplicate entry ....
ARouter有按組加載的機制,ARouter容許一個module中存在多個分組,可是不容許多個module中存在相同的分組,會致使映射文件衝突。

五、Kotlin類中的字段沒法注入如何解決?
首先,Kotlin中的字段是能夠自動注入的,可是注入代碼爲了減小反射,使用的字段賦值的方式來注入的,Kotlin默認會生成set/get方法,並把屬性設置爲private,因此只要保證Kotlin中字段可見性不是private便可,簡單解決能夠在字段上添加 @JvmField

六、經過URL跳轉以後,在intent中拿不到參數如何解決?
須要注意的是,若是不使用自動注入,那麼能夠不寫 ARouter.getInstance().inject(this),可是須要取值的字段仍然須要標上 @Autowired 註解,由於只有標上註解以後,ARouter才能知道以哪種數據類型提取URL中的參數並放入Intent中,這樣您才能在intent中獲取到對應的參數。

七、新增頁面以後,沒法跳轉?
ARouter加載Dex中的映射文件會有必定耗時,因此ARouter會緩存映射文件,直到新版本升級(版本號或者versionCode變化),而若是是開發版本,ARouter 每次啓動都會從新加載映射文件,開發階段必定要打開 Debug 功能。

2018-12-15

相關文章
相關標籤/搜索