├── .gitignore ├── .idea ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── darren │ │ └── drouter │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── darren │ │ │ └── drouter │ │ │ ├── BaseApplication.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── darren │ └── drouter │ └── ExampleUnitTest.kt ├── base-core ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── base │ │ └── core │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── base │ └── core │ └── ExampleUnitTest.java ├── build.gradle ├── circle-module ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── circle_module │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── circle_module │ │ │ ├── CircleAction.java │ │ │ ├── CircleActivity.java │ │ │ ├── CircleInterceptor.java │ │ │ ├── CircleInterceptor1.java │ │ │ └── CircleInterceptor2.java │ └── res │ │ ├── layout │ │ └── activity_circle.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── example │ └── circle_module │ └── ExampleUnitTest.java ├── drouter-api ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── drouter │ │ └── api │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── drouter │ │ │ └── api │ │ │ ├── action │ │ │ ├── IRouterAction.java │ │ │ ├── IRouterInterceptor.java │ │ │ └── IRouterModule.java │ │ │ ├── core │ │ │ ├── DRouter.java │ │ │ └── RouterForward.java │ │ │ ├── exception │ │ │ ├── InitException.java │ │ │ ├── RouterActionException.java │ │ │ └── RouterModuleException.java │ │ │ ├── extra │ │ │ ├── ActionWrapper.java │ │ │ ├── Consts.java │ │ │ ├── DefaultLogger.java │ │ │ ├── ErrorActionWrapper.java │ │ │ └── ILogger.java │ │ │ ├── interceptor │ │ │ ├── ActionInterceptor.java │ │ │ ├── ActionInterceptorChain.java │ │ │ ├── CallActionInterceptor.java │ │ │ └── ErrorActionInterceptor.java │ │ │ ├── result │ │ │ ├── ActionCallback.java │ │ │ └── RouterResult.java │ │ │ ├── thread │ │ │ ├── ActionPost.java │ │ │ ├── ActionPostQueue.java │ │ │ ├── AsyncPoster.java │ │ │ ├── BackgroundPoster.java │ │ │ ├── HandlerPoster.java │ │ │ ├── Poster.java │ │ │ └── PosterSupport.java │ │ │ └── utils │ │ │ ├── ClassUtils.java │ │ │ └── MapUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── drouter │ └── api │ └── ExampleUnitTest.java ├── drouter-base ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── drouter │ └── base │ ├── ThreadMode.java │ └── annotation │ ├── Action.java │ └── Interceptor.java ├── drouter-compiler ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── drouter │ └── compiler │ ├── Consts.java │ ├── InterceptorProcessor.java │ ├── ModuleProcessor.java │ └── util │ └── TextUtils.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── login-module ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── login │ │ └── module │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── login │ │ │ └── module │ │ │ ├── LoginAction.java │ │ │ └── LoginActivity.java │ └── res │ │ ├── layout │ │ └── activity_login.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── login │ └── module │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 85 | 95 | 96 | 97 | 98 | 99 | 100 | 102 | 103 | 104 | 105 | 106 | 1.8 107 | 108 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android 平台多模块多组件开发的路由库 2 | 3 | 4 | ### **一. DRouter 基本介绍** 5 | 6 | **1.** 该库所涉及到的类大概在 30 个左右,源码并不多相信我们都能读懂里面的内容,这里罗列一下源码中所涉及到的一些知识点: 7 | 8 |   (1) 编译时注解自动生成 Module、Action 和 Intercepter 9 | 10 |   (2) 线程、线程池、线程同步异步和 Handler 11 | 12 |   (3) 责任链模式、享元模式、策略模式、模板模式 ... 13 | 14 | **2.** 作为一个多模块的路由通信库,相信它已支持了所有跨模块通信的使用场景,功能介绍如下: 15 | 16 |   (1) 支持依赖注入,可单独作为依赖注入框架使用 17 | 18 |   (2) 支持线程切换和调度(原始线程,主线程,同步,异步) 19 | 20 |   (3) 支持多模块工程下的所有跨模块通信使用场景 21 | 22 |   (4) 支持添加多个拦截器,可根据优先级自定义拦截顺序 23 | 24 |   (5) 支持权限和网络检测、登录拦截跳转和数据埋点等功能 25 | 26 | **3.** 笔者阅读了大量的开源库源码,本库的所有代码思想都来自其中,很感激这些大牛的开源和分享精神: 27 | 28 |   [(1) ARouter](https://github.com/alibaba/ARouter) 29 | 30 |   [(2) butterknife](https://github.com/JakeWharton/butterknife) 31 | 32 |   [(3) okhttp](https://github.com/square/okhttp) 33 | 34 |   [(4) EventBus](https://github.com/greenrobot/EventBus) 35 | 36 |   [(5) RxJava](https://github.com/ReactiveX/RxJava) 37 | 38 |   [(6) retrofit](https://github.com/square/retrofit) 39 | 40 | ### **二. DRouter 基本使用** 41 | 1. 在需要跨模块通信的Module中添加依赖和配置 42 | ``` 43 | defaultConfig { 44 | ...... 45 | javaCompileOptions { 46 | annotationProcessorOptions { 47 | arguments = [moduleName: project.getName()] 48 | } 49 | } 50 | } 51 | 52 | dependencies { 53 | ....... 54 | annotationProcessor project(':drouter-compiler') 55 | } 56 | ``` 57 | 2. 初始化 SDK 58 | ``` 59 | public class BaseApplication extends Application{ 60 | @Override 61 | public void onCreate() { 62 | super.onCreate(); 63 | // 开启 debug 64 | DRouter.openDebug(); 65 | // 初始化且只能初始化一次,参数必须是 Application 66 | DRouter.getInstance().init(this); 67 | } 68 | } 69 | ``` 70 | 3. 在 Module 中创建需要执行的 Action 71 | ``` 72 | // path 必须是以在 gradle 中配置的 moduleName + "/" 开头,否则编译通不过。 73 | // threadMode 支持 POSTING 、MAIN、BACKGROUND、ASYNC 默认情况下是 POSTING(原始线程) 74 | @Action(path = "login/action", threadMode = ThreadMode.MAIN) 75 | public class LoginAction implements IRouterAction { 76 | 77 | @Override 78 | public RouterResult invokeAction(Context context, Map requestData) { 79 | // 通信执行方法支持所有场景,启动 Activity,Service,Provider,弹框,缓存数据,获取 Fragment 等等等等 80 | Intent intent = new Intent(context, LoginActivity.class); 81 | intent.putExtra("key", (String) requestData.get("key")); 82 | context.startActivity(intent); 83 | return new RouterResult.Builder().success().object(100).build(); 84 | } 85 | } 86 | ``` 87 | 4. 可在任意 Module 中执行跳转 88 | ``` 89 | // 根据 action 查询只执行对应方法,不处理返回回调,参数携带随意 90 | DRouter.getInstance() 91 | .action("login/action") 92 | .context(this) 93 | .param("key", "value") 94 | .invokeAction(); 95 | 96 | // 根据 action 查询执行对应方法,并处理返回回调 97 | DRouter.getInstance() 98 | .action("circlemodule/test") 99 | .context(this) 100 | .invokeAction(new ActionCallback() { 101 | @Override 102 | public void onInterrupt() { 103 | Log.e("TAG", "被拦截了"); 104 | } 105 | 106 | @Override 107 | public void onResult(RouterResult result) { 108 | // 注意该方法的执行线程是由 Action 的 threadMode 决定的,也就是说和 Action 在同一个线程 109 | Log.e("TAG", "result = " + result.toString()); 110 | } 111 | }); 112 | ``` 113 | 5. 在任意模块下都可添加拦截 114 | ``` 115 | // priority 优先级越高,拦截器执行越优先 116 | @Interceptor(priority = 18) 117 | public class CircleInterceptor implements ActionInterceptor { 118 | 119 | @Override 120 | public void intercept(ActionChain chain) { 121 | ActionPost actionPost = chain.action(); 122 | // 圈子详情页必须是要登录,如果没有登录即可拦截跳转到登录页面,否则继续往下执行。 123 | if (chain.actionPath().equals("circlemodule/test")) { 124 | Toast.makeText(actionPost.context, "拦截圈子,跳转到登录", Toast.LENGTH_LONG).show(); 125 | // 跳转到登录页面 126 | DRouter.getInstance() 127 | .action("login/action") 128 | .context(actionPost.context) 129 | .invokeAction(); 130 | 131 | // 这个方法调用后便会拦截整条链 132 | chain.onInterrupt(); 133 | } 134 | // 继续向下转发 135 | chain.proceed(actionPost); 136 | } 137 | } 138 | ``` 139 | 6.混淆配置 140 | ``` 141 | -keep public class com.drouter.assist.**{*;} 142 | ``` 143 | 144 | ### **三. 其他** 145 | 1. 简书详细介绍地址:https://www.jianshu.com/p/d0e1320704e4 146 | 2. 视频详细讲解地址:https://pan.baidu.com/s/1kWoIA95 147 | 148 | 149 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 26 7 | defaultConfig { 8 | applicationId "com.darren.drouter" 9 | minSdkVersion 15 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | javaCompileOptions { 16 | annotationProcessorOptions { 17 | arguments = [ moduleName : project.getName() ] 18 | } 19 | } 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(include: ['*.jar'], dir: 'libs') 31 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 32 | implementation 'com.android.support:appcompat-v7:26.1.0' 33 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 37 | /*compile 'com.alibaba:arouter-api:1.2.1.1' 38 | annotationProcessor 'com.alibaba:arouter-compiler:1.0.3'*/ 39 | implementation project(':login-module') 40 | implementation project(':circle-module') 41 | } 42 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/darren/drouter/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.darren.drouter 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.darren.drouter", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/darren/drouter/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.darren.drouter; 2 | 3 | import android.app.Application; 4 | import com.drouter.api.core.DRouter; 5 | 6 | /** 7 | * description: 8 | * author: Darren on 2018/1/22 11:27 9 | * email: 240336124@qq.com 10 | * version: 1.0 11 | */ 12 | public class BaseApplication extends Application{ 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | DRouter.openDebug(); 17 | DRouter.getInstance().init(this); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/darren/drouter/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.darren.drouter; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.View; 8 | 9 | import com.drouter.api.core.DRouter; 10 | import com.drouter.api.result.ActionCallback; 11 | import com.drouter.api.result.RouterResult; 12 | 13 | /** 14 | * description: 15 | * author: Darren on 2018/1/22 09:43 16 | * email: 240336124@qq.com 17 | * version: 1.0 18 | */ 19 | public class MainActivity extends AppCompatActivity { 20 | 21 | @Override 22 | protected void onCreate(@Nullable Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_main); 25 | } 26 | 27 | public void jumpLogin(View view) { 28 | DRouter.getInstance() 29 | .action("login/action") 30 | .context(this) 31 | .param("key", "value") 32 | .invokeAction(); 33 | } 34 | 35 | public void jumpCircle(View view) { 36 | DRouter.getInstance() 37 | .action("circlemodule/test") 38 | .context(this) 39 | .param("key", "value") 40 | .invokeAction(new ActionCallback() { 41 | @Override 42 | public void onInterrupt() { 43 | Log.e("TAG", "被拦截了"); 44 | } 45 | 46 | @Override 47 | public void onResult(RouterResult result) { 48 | Log.e("TAG", "result = " + result.toString()); 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 |