├── .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 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | 1.8
107 |
108 |
109 |
110 |
111 |
112 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
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 |
26 |
27 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DRouter
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/darren/drouter/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.darren.drouter
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/base-core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/base-core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(include: ['*.jar'], dir: 'libs')
28 | compile 'com.android.support:appcompat-v7:26.1.0'
29 | compile project(':drouter-api')
30 | annotationProcessor project(':drouter-compiler')
31 | }
32 |
--------------------------------------------------------------------------------
/base-core/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 |
--------------------------------------------------------------------------------
/base-core/src/androidTest/java/com/base/core/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.base.core;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.base.core.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/base-core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/base-core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | base-core
3 |
4 |
--------------------------------------------------------------------------------
/base-core/src/test/java/com/base/core/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.base.core;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.1.51'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/circle-module/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/circle-module/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 | repositories {
7 | mavenCentral()
8 | }
9 |
10 | defaultConfig {
11 | minSdkVersion 15
12 | targetSdkVersion 26
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
17 |
18 | javaCompileOptions {
19 | annotationProcessorOptions {
20 | arguments = [moduleName: project.getName()]
21 | }
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation 'com.android.support:appcompat-v7:26.1.0'
37 | testImplementation 'junit:junit:4.12'
38 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
39 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
40 | implementation project(':base-core')
41 | annotationProcessor project(':drouter-compiler')
42 | }
43 |
--------------------------------------------------------------------------------
/circle-module/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 |
--------------------------------------------------------------------------------
/circle-module/src/androidTest/java/com/example/circle_module/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.circle_module.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/circle-module/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/circle-module/src/main/java/com/example/circle_module/CircleAction.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.drouter.api.action.IRouterAction;
7 | import com.drouter.api.result.RouterResult;
8 | import com.drouter.base.ThreadMode;
9 | import com.drouter.base.annotation.Action;
10 |
11 | import java.util.Map;
12 |
13 | /**
14 | * description:
15 | * author: Darren on 2018/1/22 10:57
16 | * email: 240336124@qq.com
17 | * version: 1.0
18 | */
19 | @Action(path = "circlemodule/test", threadMode = ThreadMode.MAIN)
20 | public class CircleAction implements IRouterAction {
21 | @Override
22 | public RouterResult invokeAction(Context context, Map requestData) {
23 | Intent intent = new Intent(context, CircleActivity.class);
24 | intent.putExtra("key", (String) requestData.get("key"));
25 | context.startActivity(intent);
26 | return new RouterResult.Builder().success().build();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/circle-module/src/main/java/com/example/circle_module/CircleActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
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 15:08
16 | * email: 240336124@qq.com
17 | * version: 1.0
18 | */
19 | public class CircleActivity extends AppCompatActivity {
20 | @Override
21 | public void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 |
24 | setContentView(R.layout.activity_circle);
25 | }
26 |
27 | public void click(View view) {
28 | DRouter.getInstance()
29 | .action("login/action")
30 | .context(CircleActivity.this)
31 | .param("key", "value")
32 | .invokeAction(new ActionCallback() {
33 | @Override
34 | public void onInterrupt() {
35 | Log.e("TAG", "被拦截了");
36 | }
37 |
38 | @Override
39 | public void onResult(RouterResult result) {
40 | Log.e("TAG", "result = " + result.toString());
41 | }
42 | });
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/circle-module/src/main/java/com/example/circle_module/CircleInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import android.widget.Toast;
4 |
5 | import com.drouter.api.core.DRouter;
6 | import com.drouter.api.interceptor.ActionInterceptor;
7 | import com.drouter.api.thread.ActionPost;
8 | import com.drouter.base.annotation.Interceptor;
9 |
10 | /**
11 | * description:
12 | * author: Darren on 2018/1/24 16:14
13 | * email: 240336124@qq.com
14 | * version: 1.0
15 | */
16 | @Interceptor(priority = 18)
17 | public class CircleInterceptor implements ActionInterceptor {
18 |
19 | @Override
20 | public void intercept(ActionChain chain) {
21 | ActionPost actionPost = chain.action();
22 | if (chain.actionPath().equals("circlemodule/test")) {
23 | Toast.makeText(actionPost.context, "拦截圈子,跳转到登录", Toast.LENGTH_LONG).show();
24 | // 拦截
25 | chain.onInterrupt();
26 | // 跳转到登录页面
27 | DRouter.getInstance()
28 | .action("login/action")
29 | .context(actionPost.context)
30 | .invokeAction();
31 | }
32 | // 继续向下转发
33 | chain.proceed(actionPost);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/circle-module/src/main/java/com/example/circle_module/CircleInterceptor1.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import com.drouter.api.interceptor.ActionInterceptor;
4 | import com.drouter.api.thread.ActionPost;
5 | import com.drouter.base.annotation.Interceptor;
6 |
7 | /**
8 | * description:
9 | * author: Darren on 2018/1/24 16:14
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | @Interceptor(priority = 6)
14 | public class CircleInterceptor1 implements ActionInterceptor {
15 |
16 | @Override
17 | public void intercept(ActionChain chain) {
18 | ActionPost actionPost = chain.action();
19 |
20 | if (chain.actionPath().equals("circlemodule/test")) {
21 |
22 | // 拦截
23 | chain.onInterrupt();
24 | }
25 |
26 | // 继续向下转发
27 | chain.proceed(actionPost);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/circle-module/src/main/java/com/example/circle_module/CircleInterceptor2.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import com.drouter.api.interceptor.ActionInterceptor;
4 | import com.drouter.api.thread.ActionPost;
5 | import com.drouter.base.annotation.Interceptor;
6 |
7 | /**
8 | * description:
9 | * author: Darren on 2018/1/24 16:14
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | @Interceptor(priority = 10)
14 | public class CircleInterceptor2 implements ActionInterceptor {
15 |
16 | @Override
17 | public void intercept(ActionChain chain) {
18 | ActionPost actionPost = chain.action();
19 | if (chain.actionPath().equals("circlemodule/test")) {
20 | // 拦截
21 | chain.onInterrupt();
22 | }
23 |
24 | // 继续向下转发
25 | chain.proceed(actionPost);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/circle-module/src/main/res/layout/activity_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/circle-module/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | circle-module
3 |
4 |
--------------------------------------------------------------------------------
/circle-module/src/test/java/com/example/circle_module/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.circle_module;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/drouter-api/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/drouter-api/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 26
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation 'com.android.support:appcompat-v7:26.1.0'
30 | compile project(':drouter-base')
31 | }
32 |
--------------------------------------------------------------------------------
/drouter-api/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 |
--------------------------------------------------------------------------------
/drouter-api/src/androidTest/java/com/drouter/api/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.drouter.api.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/drouter-api/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/action/IRouterAction.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.action;
2 |
3 | import android.content.Context;
4 |
5 | import com.drouter.api.result.RouterResult;
6 |
7 | import java.util.Map;
8 |
9 | /**
10 | * description:
11 | * author: Darren on 2018/1/22 10:32
12 | * email: 240336124@qq.com
13 | * version: 1.0
14 | */
15 | public interface IRouterAction {
16 | // 执行 Action 方法
17 | RouterResult invokeAction(Context context, Map requestData);
18 | }
19 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/action/IRouterInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.action;
2 |
3 | import com.drouter.api.interceptor.ActionInterceptor;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * description:
9 | * author: Darren on 2018/1/22 11:08
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | public interface IRouterInterceptor {
14 | // 通过 Action 的名称找到 Action
15 | List getInterceptors();
16 | }
17 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/action/IRouterModule.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.action;
2 |
3 | import com.drouter.api.extra.ActionWrapper;
4 |
5 | /**
6 | * description:
7 | * author: Darren on 2018/1/22 11:08
8 | * email: 240336124@qq.com
9 | * version: 1.0
10 | */
11 | public interface IRouterModule {
12 | // 通过 Action 的名称找到 Action
13 | ActionWrapper findAction(String actionName);
14 | }
15 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/core/DRouter.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.core;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import android.text.TextUtils;
7 | import android.widget.Toast;
8 |
9 | import com.drouter.api.action.IRouterAction;
10 | import com.drouter.api.action.IRouterInterceptor;
11 | import com.drouter.api.action.IRouterModule;
12 | import com.drouter.api.exception.InitException;
13 | import com.drouter.api.extra.ActionWrapper;
14 | import com.drouter.api.extra.Consts;
15 | import com.drouter.api.extra.DefaultLogger;
16 | import com.drouter.api.extra.ErrorActionWrapper;
17 | import com.drouter.api.extra.ILogger;
18 | import com.drouter.api.interceptor.ActionInterceptor;
19 | import com.drouter.api.interceptor.CallActionInterceptor;
20 | import com.drouter.api.interceptor.ErrorActionInterceptor;
21 | import com.drouter.api.thread.PosterSupport;
22 | import com.drouter.api.utils.ClassUtils;
23 |
24 | import java.io.IOException;
25 | import java.util.ArrayList;
26 | import java.util.HashMap;
27 | import java.util.List;
28 | import java.util.Map;
29 |
30 | /**
31 | * description:
32 | * author: Darren on 2018/1/22 09:59
33 | * email: 240336124@qq.com
34 | * version: 1.0
35 | */
36 | public class DRouter {
37 | // 是否被初始化
38 | private volatile static boolean hasInit = false;
39 | // 是否是 debugable 状态
40 | private volatile static boolean debuggable = false;
41 | // 日志打印
42 | public volatile static ILogger logger = new DefaultLogger();
43 | // 缓存的 RouterAction
44 | private volatile static Map cacheRouterActions = new HashMap();
45 | // 缓存的 RouterModule
46 | private volatile static Map cacheRouterModules = new HashMap();
47 | // 所有 moudle
48 | private static List mAllModuleClassName;
49 | private Context mApplicationContext;
50 |
51 | private static List interceptors = new ArrayList<>();
52 |
53 | public static synchronized void openDebug() {
54 | debuggable = true;
55 | logger.showLog(true);
56 |
57 | logger.d(Consts.TAG, "DRouter openDebug");
58 | }
59 |
60 | private volatile static DRouter instance = null;
61 |
62 | public static boolean debuggable() {
63 | return debuggable;
64 | }
65 |
66 | private DRouter() {
67 |
68 | }
69 |
70 | /**
71 | * Get instance of router. A
72 | * All feature U use, will be starts here.
73 | */
74 | public static DRouter getInstance() {
75 | if (instance == null) {
76 | synchronized (DRouter.class) {
77 | if (instance == null) {
78 | instance = new DRouter();
79 | }
80 | }
81 | }
82 | return instance;
83 | }
84 |
85 | /**
86 | * 初始化数据
87 | */
88 | public void init(Application context) {
89 | if (hasInit) {
90 | throw new InitException("ARouter already initialized, It can only be initialized once.");
91 | }
92 |
93 | hasInit = true;
94 |
95 | this.mApplicationContext = context;
96 | // 获取 com.drotuer.assist 包名下的所有类名信息
97 | try {
98 | mAllModuleClassName = ClassUtils.getFileNameByPackageName(context, Consts.ROUTER_MODULE_PACK_NAME);
99 | } catch (PackageManager.NameNotFoundException e) {
100 | e.printStackTrace();
101 | } catch (IOException e) {
102 | e.printStackTrace();
103 | }
104 |
105 | for (String className : mAllModuleClassName) {
106 | logger.d(Consts.TAG, "扫描到: " + className);
107 | }
108 | // 添加并且实例化所有拦截器
109 | scanAddInterceptors(context);
110 | }
111 |
112 | // 扫描并且添加拦截器
113 | private void scanAddInterceptors(final Context context) {
114 | PosterSupport.getExecutorService().execute(new Runnable() {
115 | @Override
116 | public void run() {
117 | // 1. 错误拦截器
118 | interceptors.add(new ErrorActionInterceptor());
119 | // 2. module 自定义的拦截器
120 | try {
121 | List interceptorGroups = ClassUtils.getFileNameByPackageName(context, Consts.ROUTER_INTERCEPTOR_PACK_NAME);
122 | // 循环所有的 Group 拦截器
123 | for (String interceptorGroup : interceptorGroups) {
124 | if (interceptorGroup.contains(Consts.ROUTER_INTERCEPTOR_GROUP_PREFIX)) {
125 | IRouterInterceptor routerInterceptor = (IRouterInterceptor) Class.forName(interceptorGroup).newInstance();
126 | List interceptorClasses = routerInterceptor.getInterceptors();
127 | for (int i = interceptorClasses.size() - 1; i >= 0; i--) {
128 | ActionInterceptor interceptor = interceptorClasses.get(i);
129 | // 添加到拦截器链表
130 | interceptors.add(interceptor);
131 | }
132 | }
133 | }
134 | } catch (Exception e) {
135 | e.printStackTrace();
136 | String message = "Instance interceptor error: " + e.getMessage();
137 | logger.e(Consts.TAG, message);
138 | }
139 |
140 | // 3. 最后添加 Action 执行调用的拦截器
141 | interceptors.add(new CallActionInterceptor());
142 | }
143 | });
144 | }
145 |
146 |
147 | public RouterForward action(String actionName) {
148 | // 1. 动态先查找加载 Module
149 | // actionName 的格式必须是 xxx/xxx
150 | if (!actionName.contains("/")) {
151 | String message = "action name format error -> <" + actionName + ">, like: moduleName/actionName";
152 | debugMessage(message);
153 | return new RouterForward(new ErrorActionWrapper(), interceptors);
154 | }
155 |
156 | // 2.获取 moduleName,实例化 Module,并缓存
157 | String moduleName = actionName.split("/")[0];
158 | String moduleClassName = searchModuleClassName(moduleName);
159 | if (TextUtils.isEmpty(moduleClassName)) {
160 | String message = String.format("Please check to the action name is correct: according to the <%s> cannot find module %s.", actionName, moduleName);
161 | debugMessage(message);
162 | return new RouterForward(new ErrorActionWrapper(), interceptors);
163 | }
164 | IRouterModule routerModule = cacheRouterModules.get(moduleClassName);
165 | if (routerModule == null) {
166 | try {
167 | Class extends IRouterModule> moduleClass = (Class extends IRouterModule>) Class.forName(moduleClassName);
168 | routerModule = moduleClass.newInstance();
169 | cacheRouterModules.put(moduleClassName, routerModule);
170 | } catch (Exception e) {
171 | e.printStackTrace();
172 | String message = "instance module error: " + e.getMessage();
173 | debugMessage(message);
174 | return new RouterForward(new ErrorActionWrapper(), interceptors);
175 | }
176 | }
177 |
178 | // 3. 从 Module 中获取 ActionWrapper 类名,然后创建缓存 ActionWrapper
179 | ActionWrapper actionWrapper = cacheRouterActions.get(actionName);
180 | if (actionWrapper == null) {
181 | actionWrapper = routerModule.findAction(actionName);
182 | } else {
183 | return new RouterForward(actionWrapper, interceptors);
184 | }
185 |
186 | if (actionWrapper == null) {
187 | String message = String.format("Please check to the action name is correct: according to the <%s> cannot find action.", actionName);
188 | debugMessage(message);
189 | return new RouterForward(new ErrorActionWrapper(), interceptors);
190 | }
191 |
192 | Class extends IRouterAction> actionClass = actionWrapper.getActionClass();
193 | IRouterAction routerAction = actionWrapper.getRouterAction();
194 | if (routerAction == null) {
195 | try {
196 | if (!IRouterAction.class.isAssignableFrom(actionClass)) {
197 | String message = actionClass.getCanonicalName() + " must be implements IRouterAction.";
198 | debugMessage(message);
199 | return new RouterForward(new ErrorActionWrapper(), interceptors);
200 | }
201 | // 创建 RouterAction 实例,并缓存起来
202 | routerAction = actionClass.newInstance();
203 | actionWrapper.setRouterAction(routerAction);
204 | cacheRouterActions.put(actionName, actionWrapper);
205 | } catch (Exception e) {
206 | String message = "instance action error: " + e.getMessage();
207 | debugMessage(message);
208 | return new RouterForward(new ErrorActionWrapper(), interceptors);
209 | }
210 | }
211 |
212 | return new RouterForward(actionWrapper, interceptors);
213 | }
214 |
215 | /**
216 | * 显示 debug 信息
217 | *
218 | * @param message
219 | */
220 | private void debugMessage(String message) {
221 | if (debuggable) {
222 | logger.e(Consts.TAG, message);
223 | showToast(message);
224 | }
225 | }
226 |
227 | /**
228 | * 打印显示 Toast
229 | *
230 | * @param message
231 | */
232 | private void showToast(String message) {
233 | Toast.makeText(mApplicationContext, message, Toast.LENGTH_LONG).show();
234 | }
235 |
236 | /**
237 | * 根据 moduleName 查询 module 的全类名
238 | *
239 | * @param moduleName
240 | * @return
241 | */
242 | private String searchModuleClassName(String moduleName) {
243 | for (String moduleClassName : mAllModuleClassName) {
244 | if (moduleClassName.contains(moduleName)) {
245 | return moduleClassName;
246 | }
247 | }
248 | return null;
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/core/RouterForward.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.core;
2 |
3 | import android.content.Context;
4 |
5 | import com.drouter.api.extra.ActionWrapper;
6 | import com.drouter.api.interceptor.ActionInterceptor;
7 | import com.drouter.api.interceptor.ActionInterceptorChain;
8 | import com.drouter.api.result.ActionCallback;
9 | import com.drouter.api.thread.ActionPost;
10 | import com.drouter.base.ThreadMode;
11 |
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | /**
17 | * description: 路由转发
18 | * author: Darren on 2018/1/22 11:20
19 | * email: 240336124@qq.com
20 | * version: 1.0
21 | */
22 | public class RouterForward {
23 | private ActionWrapper mActionWrapper;
24 | private Context mContext;
25 | private Map mParams;
26 | private ThreadMode mThreadMode = null;
27 | // 所有拦截器表
28 | private List interceptors;
29 |
30 | /**
31 | * 指定 threadMode 这里指定的优先级高于 Action 注解上的 threadMode
32 | *
33 | * @param threadMode
34 | * @return
35 | */
36 | public RouterForward threadMode(ThreadMode threadMode) {
37 | this.mThreadMode = threadMode;
38 | return this;
39 | }
40 |
41 | RouterForward(ActionWrapper actionWrapper, List interceptors) {
42 | this.mActionWrapper = actionWrapper;
43 | mParams = new HashMap<>();
44 | this.interceptors = interceptors;
45 | }
46 |
47 | /**
48 | * 执行 Action
49 | *
50 | * @return
51 | */
52 | public void invokeAction() {
53 | invokeAction(ActionCallback.DEFAULT_ACTION_CALLBACK);
54 | }
55 |
56 | /**
57 | * 执行 Action
58 | *
59 | * @return
60 | */
61 | public void invokeAction(ActionCallback actionCallback) {
62 | // 先封装 actionPost
63 | mActionWrapper.setThreadMode(getThreadMode());
64 | ActionPost actionPost = ActionPost.obtainActionPost(mActionWrapper, mContext, mParams, actionCallback);
65 | // 开始拦截器的流程
66 | ActionInterceptor.ActionChain chain = new ActionInterceptorChain(interceptors, actionPost, 0);
67 | chain.proceed(actionPost);
68 | }
69 |
70 | /**
71 | * 路由转发方法传递的 threadMode 优先级高于 Action 注解上的 threadMode
72 | *
73 | * @return
74 | */
75 | public ThreadMode getThreadMode() {
76 | return mThreadMode == null ? mActionWrapper.getThreadMode() : mThreadMode;
77 | }
78 |
79 | public RouterForward context(Context context) {
80 | this.mContext = context;
81 | return this;
82 | }
83 |
84 | public RouterForward param(String key, Object value) {
85 | mParams.put(key, value);
86 | return this;
87 | }
88 |
89 | public RouterForward param(Map params) {
90 | mParams.putAll(params);
91 | return this;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/exception/InitException.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.exception;
2 |
3 | /**
4 | * description: 初始化异常类
5 | * author: Darren on 2018/1/22 10:26
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class InitException extends RuntimeException {
10 | public InitException(String message) {
11 | super(message);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/exception/RouterActionException.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.exception;
2 |
3 | /**
4 | * description: Router Action Exception
5 | * author: Darren on 2018/1/22 10:44
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class RouterActionException extends RuntimeException{
10 | public RouterActionException(String message) {
11 | super(message);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/exception/RouterModuleException.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.exception;
2 |
3 | /**
4 | * description: Router Module Exception
5 | * author: Darren on 2018/1/22 10:44
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class RouterModuleException extends RuntimeException{
10 | public RouterModuleException(String message) {
11 | super(message);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/extra/ActionWrapper.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.extra;
2 |
3 | import com.drouter.api.action.IRouterAction;
4 | import com.drouter.base.ThreadMode;
5 |
6 | /**
7 | * description:
8 | * author: Darren on 2018/1/23 14:22
9 | * email: 240336124@qq.com
10 | * version: 1.0
11 | */
12 | public class ActionWrapper {
13 | private Class extends IRouterAction> actionClass;
14 | private String path;
15 | private ThreadMode threadMode;
16 | private boolean extraProcess;
17 | private IRouterAction routerAction;
18 |
19 | ActionWrapper() {
20 |
21 | }
22 |
23 | public void setRouterAction(IRouterAction routerAction) {
24 | this.routerAction = routerAction;
25 | }
26 |
27 | public void setThreadMode(ThreadMode threadMode) {
28 | this.threadMode = threadMode;
29 | }
30 |
31 | public IRouterAction getRouterAction() {
32 | return routerAction;
33 | }
34 |
35 | private ActionWrapper(Class extends IRouterAction> actionClass, String path, boolean extraProcess, ThreadMode threadMode) {
36 | this.actionClass = actionClass;
37 | this.path = path;
38 | this.extraProcess = extraProcess;
39 | this.threadMode = threadMode;
40 | }
41 |
42 | public Class extends IRouterAction> getActionClass() {
43 | return actionClass;
44 | }
45 |
46 | public ThreadMode getThreadMode() {
47 | return threadMode;
48 | }
49 |
50 | public String getPath() {
51 | return path;
52 | }
53 |
54 | public boolean isExtraProcess() {
55 | return extraProcess;
56 | }
57 |
58 | public static ActionWrapper build(Class extends IRouterAction> actionClass, String path, boolean extraProcess, ThreadMode threadMode) {
59 | return new ActionWrapper(actionClass, path, extraProcess, threadMode);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/extra/Consts.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.extra;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/22 10:01
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class Consts {
10 | public static final String SDK_NAME = "DRouter";
11 | public static final String TAG = SDK_NAME;
12 | public static final String SUFFIX_INTERCEPTORS = "Interceptors";
13 | public static final String ROUTER_MODULE_PACK_NAME = "com.drouter.assist.module";
14 | public static final String ROUTER_INTERCEPTOR_PACK_NAME = "com.drouter.assist.interceptor";
15 | public static final String ROUTER_INTERCEPTOR_GROUP_PREFIX = "DRouter$$Interceptor$$";
16 | }
17 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/extra/DefaultLogger.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.extra;
2 |
3 | import android.text.TextUtils;
4 | import android.util.Log;
5 |
6 | /**
7 | * description:
8 | * author: Darren on 2018/1/22 10:05
9 | * email: 240336124@qq.com
10 | * version: 1.0
11 | */
12 | public class DefaultLogger implements ILogger {
13 | boolean isShowLog = false;
14 | private String defaultTag = "DRouter";
15 |
16 | @Override
17 | public void showLog(boolean isShowLog) {
18 | this.isShowLog = isShowLog;
19 | }
20 |
21 | @Override
22 | public void d(String tag, String message) {
23 | if (isShowLog) {
24 | Log.d(TextUtils.isEmpty(tag) ? getDefaultTag() : tag, message);
25 | }
26 | }
27 |
28 | @Override
29 | public void i(String tag, String message) {
30 | if (isShowLog) {
31 | Log.i(TextUtils.isEmpty(tag) ? getDefaultTag() : tag, message);
32 | }
33 | }
34 |
35 | @Override
36 | public void w(String tag, String message) {
37 | if (isShowLog) {
38 | Log.w(TextUtils.isEmpty(tag) ? getDefaultTag() : tag, message);
39 | }
40 | }
41 |
42 | @Override
43 | public void e(String tag, String message) {
44 | if (isShowLog) {
45 | Log.e(TextUtils.isEmpty(tag) ? getDefaultTag() : tag, message);
46 | }
47 | }
48 |
49 |
50 | public String getDefaultTag() {
51 | return defaultTag;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/extra/ErrorActionWrapper.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.extra;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/23 15:45
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class ErrorActionWrapper extends ActionWrapper {
10 | public ErrorActionWrapper() {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/extra/ILogger.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.extra;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/22 10:02
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public interface ILogger {
10 | void showLog(boolean isShowLog);
11 |
12 | void d(String tag, String message);
13 |
14 | void i(String tag, String message);
15 |
16 | void w(String tag, String message);
17 |
18 | void e(String tag, String message);
19 | }
20 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/interceptor/ActionInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.interceptor;
2 |
3 | import com.drouter.api.thread.ActionPost;
4 |
5 | /**
6 | * description: 拦截器
7 | * author: Darren on 2018/1/22 11:59
8 | * email: 240336124@qq.com
9 | * version: 1.0
10 | */
11 | public interface ActionInterceptor {
12 | void intercept(ActionChain chain);
13 |
14 | interface ActionChain {
15 | // 打断拦截
16 | void onInterrupt();
17 |
18 | // 分发给下一个拦截器
19 | void proceed(ActionPost actionPost);
20 |
21 | // 获取 ActionPost
22 | ActionPost action();
23 |
24 | String actionPath();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/interceptor/ActionInterceptorChain.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.interceptor;
2 |
3 | import com.drouter.api.thread.ActionPost;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * description:
9 | * author: Darren on 2018/1/24 09:38
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | public class ActionInterceptorChain implements ActionInterceptor.ActionChain {
14 | // 是否被拦截了
15 | private boolean isInterrupt = false;
16 | private List interceptors;
17 | private ActionPost actionPost;
18 | private int index;
19 |
20 | public ActionInterceptorChain(List interceptors, ActionPost actionPost, int index) {
21 | this.interceptors = interceptors;
22 | this.actionPost = actionPost;
23 | this.index = index;
24 | }
25 |
26 | @Override
27 | public void onInterrupt() {
28 | isInterrupt = true;
29 | actionPost.actionCallback.onInterrupt();
30 | }
31 |
32 | @Override
33 | public void proceed(ActionPost actionPost) { // 0
34 | if (!isInterrupt && index < interceptors.size()) {
35 | // 继续往下分发
36 | ActionInterceptor.ActionChain next = new ActionInterceptorChain(interceptors, actionPost, index + 1);
37 | // 0 拦截器
38 | ActionInterceptor interceptor = interceptors.get(index);
39 | // 执行第一个
40 | interceptor.intercept(next);
41 | }
42 | }
43 |
44 | @Override
45 | public ActionPost action() {
46 | return actionPost;
47 | }
48 |
49 | @Override
50 | public String actionPath() {
51 | return actionPost.actionWrapper.getPath();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/interceptor/CallActionInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.interceptor;
2 |
3 |
4 | import android.os.Looper;
5 |
6 | import com.drouter.api.action.IRouterAction;
7 | import com.drouter.api.extra.ActionWrapper;
8 | import com.drouter.api.result.RouterResult;
9 | import com.drouter.api.thread.ActionPost;
10 | import com.drouter.api.thread.PosterSupport;
11 |
12 | /**
13 | * description: 执行 Action 方法的最后一个拦截器
14 | * author: Darren on 2018/1/24 09:03
15 | * email: 240336124@qq.com
16 | * version: 1.0
17 | */
18 | public class CallActionInterceptor implements ActionInterceptor {
19 | @Override
20 | public void intercept(ActionChain chain) {
21 | // 执行 Action 方法
22 | ActionPost actionPost = chain.action();
23 | invokeAction(actionPost, Looper.myLooper() == Looper.getMainLooper());
24 | }
25 |
26 | /**
27 | * 处理线程切换
28 | *
29 | * @param isMainThread
30 | * @return
31 | */
32 | private void invokeAction(ActionPost actionPost, boolean isMainThread) {
33 | switch (actionPost.actionWrapper.getThreadMode()) {
34 | case POSTING:
35 | invokeAction(actionPost);
36 | case MAIN:
37 | if (isMainThread) {
38 | invokeAction(actionPost);
39 | } else {
40 | PosterSupport.getMainPoster().enqueue(actionPost);
41 | }
42 | break;
43 | case BACKGROUND:
44 | if (isMainThread) {
45 | PosterSupport.getBackgroundPoster().enqueue(actionPost);
46 | } else {
47 | invokeAction(actionPost);
48 | }
49 | break;
50 | case ASYNC:
51 | PosterSupport.getAsyncPoster().enqueue(actionPost);
52 | break;
53 | default:
54 | throw new IllegalStateException("Unknown thread mode: " + actionPost.actionWrapper.getThreadMode());
55 | }
56 | }
57 |
58 | /**
59 | * 执行 Action
60 | *
61 | * @param actionPost
62 | */
63 | private void invokeAction(ActionPost actionPost) {
64 | ActionWrapper actionWrapper = actionPost.actionWrapper;
65 | IRouterAction routerAction = actionWrapper.getRouterAction();
66 | RouterResult routerResult = routerAction.invokeAction(actionPost.context, actionPost.params);
67 | actionPost.actionCallback.onResult(routerResult);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/interceptor/ErrorActionInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.interceptor;
2 |
3 |
4 | import com.drouter.api.extra.ErrorActionWrapper;
5 | import com.drouter.api.thread.ActionPost;
6 |
7 | /**
8 | * description: 错误的 Action 拦截器,放在拦截链的第一个位置
9 | * author: Darren on 2018/1/24 09:03
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | public class ErrorActionInterceptor implements ActionInterceptor {
14 | @Override
15 | public void intercept(ActionChain chain) {
16 | ActionPost actionPost = chain.action();
17 | // 拦截错误
18 | if (actionPost.actionWrapper instanceof ErrorActionWrapper) {
19 | chain.onInterrupt();
20 | }
21 |
22 | // 继续分发
23 | chain.proceed(actionPost);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/result/ActionCallback.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.result;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/24 09:05
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public interface ActionCallback {
10 | // 被拦截了
11 | void onInterrupt();
12 |
13 | // 没被拦截返回结果
14 | void onResult(RouterResult result);
15 |
16 | // 默认的 ActionCallback
17 | ActionCallback DEFAULT_ACTION_CALLBACK = new ActionCallback() {
18 |
19 | @Override
20 | public void onInterrupt() {
21 |
22 | }
23 |
24 | @Override
25 | public void onResult(RouterResult result) {
26 |
27 | }
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/result/RouterResult.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.result;
2 |
3 | /**
4 | * description: 路由的返回结果
5 | * author: Darren on 2018/1/22 10:35
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class RouterResult {
10 | static final int SUCCEED_CODE = 0x000011;
11 | static final int ERROR_CODE = 0x000022;
12 | private String msg;
13 | private int code;
14 | private Object object;
15 |
16 | public int getCode() {
17 | return code;
18 | }
19 |
20 | private RouterResult(Builder builder) {
21 | this.code = builder.code;
22 | this.msg = builder.msg;
23 | this.object = builder.object;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return super.toString() + "{" +
29 | "msg='" + msg + '\'' +
30 | ", code=" + code +
31 | ", object=" + object +
32 | '}';
33 | }
34 |
35 | public String getMsg() {
36 | return msg;
37 | }
38 |
39 | public Object getObject() {
40 | return object;
41 | }
42 |
43 | /**
44 | * 返回是否成功
45 | *
46 | * @return
47 | */
48 | public boolean isSucceed() {
49 | return code == SUCCEED_CODE;
50 | }
51 |
52 |
53 | public static class Builder {
54 | int code = SUCCEED_CODE;
55 | String msg;
56 | Object object;
57 |
58 | public Builder error() {
59 | this.code = ERROR_CODE;
60 | return this;
61 | }
62 |
63 | public Builder success() {
64 | this.code = SUCCEED_CODE;
65 | return this;
66 | }
67 |
68 | public Builder msg(String msg) {
69 | this.msg = msg;
70 | return this;
71 | }
72 |
73 | public Builder object(Object object) {
74 | this.object = object;
75 | return this;
76 | }
77 |
78 | public RouterResult build() {
79 | return new RouterResult(this);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/ActionPost.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | import android.content.Context;
4 |
5 | import com.drouter.api.extra.ActionWrapper;
6 | import com.drouter.api.result.ActionCallback;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | /**
13 | * description:
14 | * author: Darren on 2018/1/23 16:11
15 | * email: 240336124@qq.com
16 | * version: 1.0
17 | */
18 | public final class ActionPost {
19 | private final static List pendingPostPool = new ArrayList();
20 |
21 | public Context context;
22 | public ActionWrapper actionWrapper;
23 | public Map params;
24 | public ActionCallback actionCallback;
25 | ActionPost next;
26 |
27 | private ActionPost(ActionWrapper actionWrapper, Context context, Map params, ActionCallback actionCallback) {
28 | this.context = context;
29 | this.actionWrapper = actionWrapper;
30 | this.params = params;
31 | this.actionCallback = actionCallback;
32 | }
33 |
34 | public static ActionPost obtainActionPost(ActionWrapper actionWrapper, Context context, Map params, ActionCallback actionCallback) {
35 | synchronized (pendingPostPool) {
36 | int size = pendingPostPool.size();
37 | if (size > 0) {
38 | ActionPost actionPost = pendingPostPool.remove(size - 1);
39 | actionPost.context = context;
40 | actionPost.actionWrapper = actionWrapper;
41 | actionPost.params = params;
42 | actionPost.next = null;
43 | actionPost.actionCallback = actionCallback;
44 | return actionPost;
45 | }
46 | }
47 | return new ActionPost(actionWrapper, context, params, actionCallback);
48 | }
49 |
50 | public void releasePendingPost() {
51 | this.context = null;
52 | this.actionWrapper = null;
53 | this.next = null;
54 | this.actionCallback = null;
55 | synchronized (pendingPostPool) {
56 | // Don't let the pool grow indefinitely
57 | if (pendingPostPool.size() < 10000) {
58 | pendingPostPool.add(this);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/ActionPostQueue.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/23 16:13
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class ActionPostQueue {
10 | private ActionPost head;
11 | private ActionPost tail;
12 |
13 | synchronized void enqueue(ActionPost pendingPost) {
14 | if (pendingPost == null) {
15 | throw new NullPointerException("null cannot be enqueued");
16 | }
17 | if (tail != null) {
18 | tail.next = pendingPost;
19 | tail = pendingPost;
20 | } else if (head == null) {
21 | head = tail = pendingPost;
22 | } else {
23 | throw new IllegalStateException("Head present, but no tail");
24 | }
25 | notifyAll();
26 | }
27 |
28 | synchronized ActionPost poll() {
29 | ActionPost pendingPost = head;
30 | if (head != null) {
31 | head = head.next;
32 | if (head == null) {
33 | tail = null;
34 | }
35 | }
36 | return pendingPost;
37 | }
38 |
39 | synchronized ActionPost poll(int maxMillisToWait) throws InterruptedException {
40 | if (head == null) {
41 | wait(maxMillisToWait);
42 | }
43 | return poll();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/AsyncPoster.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | import com.drouter.api.action.IRouterAction;
4 | import com.drouter.api.extra.ActionWrapper;
5 | import com.drouter.api.result.RouterResult;
6 |
7 | /**
8 | * description: 处理异步
9 | * author: Darren on 2018/1/23 16:46
10 | * email: 240336124@qq.com
11 | * version: 1.0
12 | */
13 | public class AsyncPoster implements Runnable, Poster {
14 |
15 | private final ActionPostQueue queue;
16 |
17 | AsyncPoster() {
18 | queue = new ActionPostQueue();
19 | }
20 |
21 | @Override
22 | public void run() {
23 | ActionPost actionPost = queue.poll();
24 | if (actionPost == null) {
25 | throw new IllegalStateException("No pending post available");
26 | }
27 |
28 | ActionWrapper actionWrapper = actionPost.actionWrapper;
29 | IRouterAction routerAction = actionWrapper.getRouterAction();
30 | RouterResult routerResult = routerAction.invokeAction(actionPost.context, actionPost.params);
31 | actionPost.actionCallback.onResult(routerResult);
32 |
33 | actionPost.releasePendingPost();
34 | }
35 |
36 | @Override
37 | public void enqueue(ActionPost actionPost) {
38 | queue.enqueue(actionPost);
39 | PosterSupport.getExecutorService().execute(this);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/BackgroundPoster.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | import com.drouter.api.action.IRouterAction;
4 | import com.drouter.api.core.DRouter;
5 | import com.drouter.api.extra.ActionWrapper;
6 | import com.drouter.api.extra.Consts;
7 | import com.drouter.api.result.RouterResult;
8 |
9 | /**
10 | * description:
11 | * author: Darren on 2018/1/23 17:01
12 | * email: 240336124@qq.com
13 | * version: 1.0
14 | */
15 | final class BackgroundPoster implements Runnable, Poster {
16 |
17 | private final ActionPostQueue queue;
18 |
19 | private volatile boolean executorRunning;
20 |
21 | BackgroundPoster() {
22 | queue = new ActionPostQueue();
23 | }
24 |
25 | @Override
26 | public void enqueue(ActionPost actionPost) {
27 | synchronized (this) {
28 | queue.enqueue(actionPost);
29 | if (!executorRunning) {
30 | executorRunning = true;
31 | PosterSupport.getExecutorService().execute(this);
32 | }
33 | }
34 | }
35 |
36 | @Override
37 | public void run() {
38 | try {
39 | try {
40 | while (true) {
41 | ActionPost actionPost = queue.poll(1000);
42 | if (actionPost == null) {
43 | synchronized (this) {
44 | // Check again, this time in synchronized
45 | actionPost = queue.poll();
46 | if (actionPost == null) {
47 | executorRunning = false;
48 | return;
49 | }
50 | }
51 | }
52 |
53 | ActionWrapper actionWrapper = actionPost.actionWrapper;
54 | IRouterAction routerAction = actionWrapper.getRouterAction();
55 | RouterResult routerResult = routerAction.invokeAction(actionPost.context, actionPost.params);
56 | actionPost.actionCallback.onResult(routerResult);
57 |
58 | actionPost.releasePendingPost();
59 | }
60 | } catch (InterruptedException e) {
61 | DRouter.logger.e(Consts.TAG, Thread.currentThread().getName() + " was interruppted");
62 | }
63 | } finally {
64 | executorRunning = false;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/HandlerPoster.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 | import android.os.SystemClock;
7 |
8 | import com.drouter.api.action.IRouterAction;
9 | import com.drouter.api.extra.ActionWrapper;
10 | import com.drouter.api.result.RouterResult;
11 |
12 | /**
13 | * description: 处理主线程切换
14 | * author: Darren on 2018/1/23 16:10
15 | * email: 240336124@qq.com
16 | * version: 1.0
17 | */
18 | public class HandlerPoster extends Handler implements Poster {
19 | private final ActionPostQueue queue;
20 | private final int maxMillisInsideHandleMessage;
21 | private boolean handlerActive;
22 |
23 | protected HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) {
24 | super(looper);
25 | this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
26 | queue = new ActionPostQueue();
27 | }
28 |
29 | @Override
30 | public void handleMessage(Message msg) {
31 | boolean rescheduled = false;
32 | try {
33 | long started = SystemClock.uptimeMillis();
34 | while (true) {
35 | ActionPost actionPost = queue.poll();
36 | if (actionPost == null) {
37 | synchronized (this) {
38 | // Check again, this time in synchronized
39 | actionPost = queue.poll();
40 | if (actionPost == null) {
41 | handlerActive = false;
42 | return;
43 | }
44 | }
45 | }
46 |
47 | ActionWrapper actionWrapper = actionPost.actionWrapper;
48 | IRouterAction routerAction = actionWrapper.getRouterAction();
49 | RouterResult routerResult = routerAction.invokeAction(actionPost.context, actionPost.params);
50 | actionPost.actionCallback.onResult(routerResult);
51 |
52 | actionPost.releasePendingPost();
53 |
54 | long timeInMethod = SystemClock.uptimeMillis() - started;
55 | if (timeInMethod >= maxMillisInsideHandleMessage) {
56 | if (!sendMessage(obtainMessage())) {
57 | throw new RuntimeException("Could not send handler message");
58 | }
59 | rescheduled = true;
60 | return;
61 | }
62 | }
63 | } finally {
64 | handlerActive = rescheduled;
65 | }
66 | }
67 |
68 | @Override
69 | public void enqueue(ActionPost actionPost) {
70 | synchronized (this) {
71 | queue.enqueue(actionPost);
72 | if (!handlerActive) {
73 | handlerActive = true;
74 | if (!sendMessage(obtainMessage())) {
75 | throw new RuntimeException("Could not send handler message");
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/Poster.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/23 16:05
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public interface Poster {
10 | void enqueue(ActionPost actionPost);
11 | }
12 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/thread/PosterSupport.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.thread;
2 |
3 | import android.os.Looper;
4 |
5 | import java.util.concurrent.ExecutorService;
6 | import java.util.concurrent.Executors;
7 |
8 | /**
9 | * description:
10 | * author: Darren on 2018/1/23 16:08
11 | * email: 240336124@qq.com
12 | * version: 1.0
13 | */
14 | public class PosterSupport {
15 | private static volatile Poster mainPoster, backgroundPoster, asyncPoster;
16 | private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
17 |
18 |
19 | public static Poster getMainPoster() {
20 | if (mainPoster == null) {
21 | synchronized (PosterSupport.class) {
22 | if (mainPoster == null) {
23 | mainPoster = new HandlerPoster(Looper.getMainLooper(), 10);
24 | }
25 | }
26 | }
27 | return mainPoster;
28 | }
29 |
30 | public static ExecutorService getExecutorService() {
31 | return DEFAULT_EXECUTOR_SERVICE;
32 | }
33 |
34 | public static Poster getBackgroundPoster() {
35 | if (backgroundPoster == null) {
36 | synchronized (PosterSupport.class) {
37 | if (backgroundPoster == null) {
38 | backgroundPoster = new BackgroundPoster();
39 | }
40 | }
41 | }
42 | return backgroundPoster;
43 | }
44 |
45 | public static Poster getAsyncPoster() {
46 | if (asyncPoster == null) {
47 | synchronized (PosterSupport.class) {
48 | if (asyncPoster == null) {
49 | asyncPoster = new AsyncPoster();
50 | }
51 | }
52 | }
53 | return asyncPoster;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/utils/ClassUtils.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.pm.ApplicationInfo;
6 | import android.content.pm.PackageManager;
7 | import android.os.Build;
8 |
9 | import com.drouter.api.core.DRouter;
10 | import com.drouter.api.extra.Consts;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 | import java.util.ArrayList;
15 | import java.util.Enumeration;
16 | import java.util.List;
17 | import java.util.regex.Matcher;
18 | import java.util.regex.Pattern;
19 |
20 | import dalvik.system.DexFile;
21 |
22 | /**
23 | * description: thanks alibaba ARouter
24 | * author: Darren on 2018/1/23 09:24
25 | * email: 240336124@qq.com
26 | * version: 1.0
27 | */
28 | public class ClassUtils {
29 | private static final String EXTRACTED_NAME_EXT = ".classes";
30 | private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2;
31 | private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1;
32 | private static final String PREFS_FILE = "multidex.version";
33 | private static final String KEY_DEX_NUMBER = "dex.number";
34 | private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.separator + "secondary-dexes";
35 | private static final String EXTRACTED_SUFFIX = ".zip";
36 |
37 | private static SharedPreferences getMultiDexPreferences(Context context) {
38 | return context.getSharedPreferences(PREFS_FILE, Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? Context.MODE_PRIVATE : Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
39 | }
40 |
41 | /**
42 | * 通过指定包名,扫描包下面包含的所有的ClassName
43 | */
44 | public static List getFileNameByPackageName(Context context, String packageName) throws PackageManager.NameNotFoundException, IOException {
45 | List classNames = new ArrayList<>();
46 | for (String path : getSourcePaths(context)) {
47 | DexFile dexfile;
48 | if (path.endsWith(EXTRACTED_SUFFIX)) {
49 | //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
50 | dexfile = DexFile.loadDex(path, path + ".tmp", 0);
51 | } else {
52 | dexfile = new DexFile(path);
53 | }
54 | Enumeration dexEntries = dexfile.entries();
55 | while (dexEntries.hasMoreElements()) {
56 | String className = dexEntries.nextElement();
57 | if (className.contains(packageName)) {
58 | classNames.add(className);
59 | }
60 | }
61 | }
62 |
63 | DRouter.logger.d(Consts.TAG, "Scan " + classNames.size() + " classes by packageName <" + packageName + ">");
64 | return classNames;
65 | }
66 |
67 | /**
68 | * get all the dex path
69 | *
70 | * @param context the application context
71 | * @return all the dex path
72 | * @throws PackageManager.NameNotFoundException
73 | * @throws IOException
74 | */
75 | public static List getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException {
76 | ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
77 | File sourceApk = new File(applicationInfo.sourceDir);
78 |
79 | List sourcePaths = new ArrayList<>();
80 | sourcePaths.add(applicationInfo.sourceDir); //add the default apk path
81 |
82 | //the prefix of extracted file, ie: test.classes
83 | String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
84 |
85 | if (!isVMMultidexCapable()) {
86 | //the total dex numbers
87 | int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1);
88 | File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);
89 |
90 | for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
91 | //for each dex file, ie: test.classes2.zip, test.classes3.zip...
92 | String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
93 | File extractedFile = new File(dexDir, fileName);
94 | if (extractedFile.isFile()) {
95 | sourcePaths.add(extractedFile.getAbsolutePath());
96 | //we ignore the verify zip part
97 | } else {
98 | throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'");
99 | }
100 | }
101 | }
102 |
103 | return sourcePaths;
104 | }
105 |
106 | /**
107 | * Identifies if the current VM has a native support for multidex, meaning there is no need for
108 | * additional installation by this library.
109 | *
110 | * @return true if the VM handles multidex
111 | */
112 | private static boolean isVMMultidexCapable() {
113 | boolean isMultidexCapable = false;
114 | String vmName = null;
115 |
116 | try {
117 | if (isYunOS()) {
118 | vmName = "'YunOS'";
119 | isMultidexCapable = Integer.valueOf(System.getProperty("ro.build.version.sdk")) >= 21;
120 | } else {
121 | vmName = "'Android'";
122 | String versionString = System.getProperty("java.vm.version");
123 | if (versionString != null) {
124 | Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString);
125 | if (matcher.matches()) {
126 | try {
127 | int major = Integer.parseInt(matcher.group(1));
128 | int minor = Integer.parseInt(matcher.group(2));
129 | isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR)
130 | || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR)
131 | && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR));
132 | } catch (NumberFormatException ignore) {
133 | // let isMultidexCapable be false
134 | }
135 | }
136 | }
137 | }
138 | } catch (Exception ignore) {
139 |
140 | }
141 | return isMultidexCapable;
142 | }
143 |
144 | /**
145 | * 判断系统是否为YunOS系统
146 | */
147 | private static boolean isYunOS() {
148 | try {
149 | String version = System.getProperty("ro.yunos.version");
150 | String vmName = System.getProperty("java.vm.name");
151 | return (vmName != null && vmName.toLowerCase().contains("lemur"))
152 | || (version != null && version.trim().length() > 0);
153 | } catch (Exception ignore) {
154 | return false;
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/drouter-api/src/main/java/com/drouter/api/utils/MapUtils.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api.utils;
2 |
3 | import com.drouter.api.interceptor.ActionInterceptor;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | /**
10 | * description:
11 | * author: Darren on 2018/1/24 16:57
12 | * email: 240336124@qq.com
13 | * version: 1.0
14 | */
15 | public class MapUtils {
16 |
17 | public static List getInterceptorClasses(Map map) {
18 | List list = new ArrayList();
19 |
20 | for (Object key : map.keySet()) {
21 | list.add(map.get(key));
22 | }
23 |
24 | return list;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/drouter-api/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | drouter-api
3 |
4 |
--------------------------------------------------------------------------------
/drouter-api/src/test/java/com/drouter/api/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.drouter.api;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/drouter-base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/drouter-base/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 |
3 | dependencies {
4 | implementation fileTree(dir: 'libs', include: ['*.jar'])
5 | }
6 |
7 | sourceCompatibility = "1.7"
8 | targetCompatibility = "1.7"
9 |
--------------------------------------------------------------------------------
/drouter-base/src/main/java/com/drouter/base/ThreadMode.java:
--------------------------------------------------------------------------------
1 | package com.drouter.base;
2 |
3 | /**
4 | * description: thanks EventBus
5 | * author: Darren on 2018/1/23 08:57
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public enum ThreadMode {
10 | /**
11 | * Action will be called directly in the same thread, which is posting the event. This is the default. Event delivery
12 | * implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for
13 | * simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers
14 | * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
15 | */
16 | POSTING,
17 |
18 | /**
19 | * On Android, action will be called in Android's main thread (UI thread). If the posting thread is
20 | * the main thread, action methods will be called directly, blocking the posting thread. Otherwise the event
21 | * is queued for delivery (non-blocking). Action using this mode must return quickly to avoid blocking the main thread.
22 | * If not on Android, behaves the same as {@link #POSTING}.
23 | */
24 | MAIN,
25 |
26 | /**
27 | * On Android, action will be called in a background thread. If posting thread is not the main thread, action methods
28 | * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
29 | * background thread, that will deliver all its events sequentially. Action using this mode should try to
30 | * return quickly to avoid blocking the background thread. If not on Android, always uses a background thread.
31 | */
32 | BACKGROUND,
33 |
34 | /**
35 | * Action will be called in a separate thread. This is always independent from the posting thread and the
36 | * main thread. Posting events never wait for action methods using this mode. Action methods should
37 | * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number
38 | * of long running asynchronous action methods at the same time to limit the number of concurrent threads. EventBus
39 | * uses a thread pool to efficiently reuse threads from completed asynchronous action notifications.
40 | */
41 | ASYNC
42 | }
43 |
--------------------------------------------------------------------------------
/drouter-base/src/main/java/com/drouter/base/annotation/Action.java:
--------------------------------------------------------------------------------
1 | package com.drouter.base.annotation;
2 |
3 | import com.drouter.base.ThreadMode;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * description: 模块注册 apt
12 | * author: Darren on 2018/1/22 12:32
13 | * email: 240336124@qq.com
14 | * version: 1.0
15 | */
16 | @Target({ElementType.TYPE})
17 | @Retention(RetentionPolicy.CLASS)
18 | public @interface Action {
19 | /**
20 | * thread mode
21 | */
22 | ThreadMode threadMode() default ThreadMode.POSTING;
23 |
24 | /**
25 | * Path of route
26 | */
27 | String path();
28 |
29 | /**
30 | * extra process
31 | */
32 | boolean extraProcess() default false;
33 | }
34 |
--------------------------------------------------------------------------------
/drouter-base/src/main/java/com/drouter/base/annotation/Interceptor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.base.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * description:
10 | * author: Darren on 2018/1/24 16:10
11 | * email: 240336124@qq.com
12 | * version: 1.0
13 | */
14 | @Target({ElementType.TYPE})
15 | @Retention(RetentionPolicy.CLASS)
16 | public @interface Interceptor {
17 | int priority();
18 | }
19 |
--------------------------------------------------------------------------------
/drouter-compiler/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/drouter-compiler/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 |
3 | dependencies {
4 | implementation fileTree(include: ['*.jar'], dir: 'libs')
5 | implementation project(':drouter-base')
6 | implementation 'com.google.auto.service:auto-service:1.0-rc2'
7 | implementation 'com.squareup:javapoet:1.7.0'
8 | }
9 |
10 | tasks.withType(JavaCompile){
11 | options.encoding='UTF-8'
12 | }
13 |
14 | sourceCompatibility = "1.7"
15 | targetCompatibility = "1.7"
--------------------------------------------------------------------------------
/drouter-compiler/src/main/java/com/drouter/compiler/Consts.java:
--------------------------------------------------------------------------------
1 | package com.drouter.compiler;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/22 10:01
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class Consts {
10 | public static final String SDK_NAME = "DRouter";
11 | public static final String TAG = SDK_NAME;
12 | public static final String SUFFIX_INTERCEPTORS = "Interceptors";
13 | public static final String ROUTER_MODULE_PACK_NAME = "com.drouter.assist.module";
14 | public static final String ROUTER_INTERCEPTOR_PACK_NAME = "com.drouter.assist.interceptor";
15 | public static final String ACTIONINTERCEPTOR = "com.drouter.api.interceptor.ActionInterceptor";
16 | public static final String ROUTERACTION = "com.drouter.api.action.IRouterAction";
17 | }
18 |
--------------------------------------------------------------------------------
/drouter-compiler/src/main/java/com/drouter/compiler/InterceptorProcessor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.compiler;
2 |
3 | import com.drouter.base.annotation.Interceptor;
4 | import com.drouter.compiler.util.TextUtils;
5 | import com.google.auto.service.AutoService;
6 | import com.squareup.javapoet.ClassName;
7 | import com.squareup.javapoet.JavaFile;
8 | import com.squareup.javapoet.MethodSpec;
9 | import com.squareup.javapoet.TypeSpec;
10 |
11 | import java.io.IOException;
12 | import java.lang.annotation.Annotation;
13 | import java.util.HashMap;
14 | import java.util.LinkedHashSet;
15 | import java.util.List;
16 | import java.util.Map;
17 | import java.util.Set;
18 |
19 | import javax.annotation.processing.AbstractProcessor;
20 | import javax.annotation.processing.Filer;
21 | import javax.annotation.processing.ProcessingEnvironment;
22 | import javax.annotation.processing.Processor;
23 | import javax.annotation.processing.RoundEnvironment;
24 | import javax.lang.model.SourceVersion;
25 | import javax.lang.model.element.Element;
26 | import javax.lang.model.element.Modifier;
27 | import javax.lang.model.element.TypeElement;
28 | import javax.lang.model.type.TypeMirror;
29 | import javax.lang.model.util.Elements;
30 | import javax.tools.Diagnostic;
31 |
32 | /**
33 | * description:
34 | * author: Darren on 2018/1/22 12:29
35 | * email: 240336124@qq.com
36 | * version: 1.0
37 | */
38 | @AutoService(Processor.class)
39 | public class InterceptorProcessor extends AbstractProcessor {
40 | private Elements mElementUtils;
41 | private Filer mFiler;
42 | private final String KEY_MODULE_NAME = "moduleName";
43 | private TypeMirror iInterceptor = null;
44 | private String moduleName = null;
45 |
46 | @Override
47 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
48 | super.init(processingEnvironment);
49 | mFiler = processingEnvironment.getFiler();
50 | mElementUtils = processingEnvironment.getElementUtils();
51 | iInterceptor = mElementUtils.getTypeElement(Consts.ACTIONINTERCEPTOR).asType();
52 | }
53 |
54 | @Override
55 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
56 |
57 | // 1. 有没配置 modelName 防止 class 类冲突
58 | String moduleName = "";
59 |
60 | Map options = processingEnv.getOptions();
61 | if (isNotEmpty(options)) {
62 | moduleName = options.get(KEY_MODULE_NAME);
63 | }
64 |
65 | if (!TextUtils.isEmpty(moduleName)) {
66 | moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");
67 | } else {
68 | String errorMessage = "These no module name, at 'build.gradle', like :\n" +
69 | "apt {\n" +
70 | " arguments {\n" +
71 | " moduleName project.getName();\n" +
72 | " }\n" +
73 | "}\n";
74 | throw new RuntimeException("DRouter::Compiler >>> No module name, for more information, look at gradle log.\n" + errorMessage);
75 | }
76 |
77 | // 生成类继承和实现接口
78 | ClassName routerAssistClassName = ClassName.get("com.drouter.api.action", "IRouterInterceptor");
79 | ClassName mapClassName = ClassName.get("java.util", "Map");
80 | TypeSpec.Builder classBuilder = TypeSpec.classBuilder("DRouter$$Interceptor$$" + moduleName)
81 | .addModifiers(Modifier.FINAL, Modifier.PUBLIC)
82 | .addSuperinterface(routerAssistClassName)
83 | .addField(mapClassName, "interceptors", Modifier.PRIVATE);
84 |
85 | // 构造函数
86 | MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
87 | constructorMethodBuilder.addStatement("interceptors = new $T<>()", ClassName.get("java.util", "TreeMap"));
88 |
89 | // 2. 解析到所有的 Action 信息
90 | Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Interceptor.class);
91 | Map interceptors = new HashMap<>(elements.size());
92 |
93 | for (Element element : elements) {
94 |
95 | // 获取注解上面的 priority
96 | Interceptor interceptorAnnotation = element.getAnnotation(Interceptor.class);
97 | int priority = interceptorAnnotation.priority();
98 |
99 | // 获取 Interceptor 的 ClassName
100 | Element enclosingElement = element.getEnclosingElement();
101 | String packageName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
102 | String interceptorClassName = packageName + "." + element.getSimpleName();
103 |
104 | // 判断 Interceptor 注解类是否实现了 ActionInterceptor
105 | if (!((TypeElement) element).getInterfaces().contains(iInterceptor)) {
106 | error(element, "%s verify failed, @Interceptor must be implements %s", element.getSimpleName().toString(), Consts.ACTIONINTERCEPTOR);
107 | }
108 |
109 | if (interceptors.containsKey(priority)) {
110 | // 输出错误,拦截器优先级 冲突重复了
111 | error(element, "More than one interceptors use same priority <%s> , The last interceptor was <%s>", String.valueOf(priority), interceptors.get(priority));
112 | }
113 | // 添加到集合
114 | interceptors.put(priority, interceptorClassName);
115 |
116 | constructorMethodBuilder.addStatement("this.interceptors.put(" + priority + ",new $T())", ClassName.bestGuess(interceptorClassName));
117 | }
118 |
119 | // 实现方法
120 | MethodSpec.Builder unbindMethodBuilder = MethodSpec.methodBuilder("getInterceptors")
121 | .addAnnotation(Override.class)
122 | .returns(List.class)
123 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
124 | unbindMethodBuilder.addStatement("return $T.getInterceptorClasses(interceptors)", ClassName.get("com.drouter.api.utils", "MapUtils"));
125 |
126 | classBuilder.addMethod(constructorMethodBuilder.build());
127 | classBuilder.addMethod(unbindMethodBuilder.build());
128 |
129 | // 生成类,看下效果
130 | try {
131 | JavaFile.builder(Consts.ROUTER_INTERCEPTOR_PACK_NAME, classBuilder.build())
132 | .addFileComment("DRouter 自动生成")
133 | .build().writeTo(mFiler);
134 | } catch (IOException e) {
135 | e.printStackTrace();
136 | System.out.println("翻车了!");
137 | }
138 |
139 | return false;
140 | }
141 |
142 |
143 | private boolean isNotEmpty(Map options) {
144 | return options != null && !options.isEmpty();
145 | }
146 |
147 | private void error(Element element, String message, String... args) {
148 | printMessage(Diagnostic.Kind.ERROR, element, message, args);
149 | }
150 |
151 | private void printMessage(Diagnostic.Kind kind, Element element, String message, Object[] args) {
152 | if (args.length > 0) {
153 | message = String.format(message, args);
154 | }
155 |
156 | processingEnv.getMessager().printMessage(kind, message, element);
157 | }
158 |
159 |
160 | // 1. 指定处理的版本
161 | @Override
162 | public SourceVersion getSupportedSourceVersion() {
163 | return SourceVersion.latestSupported();
164 | }
165 |
166 | // 2. 给到需要处理的注解
167 | @Override
168 | public Set getSupportedAnnotationTypes() {
169 | Set types = new LinkedHashSet<>();
170 | for (Class extends Annotation> annotation : getSupportedAnnotations()) {
171 | types.add(annotation.getCanonicalName());
172 | }
173 | return types;
174 | }
175 |
176 | private Set> getSupportedAnnotations() {
177 | Set> annotations = new LinkedHashSet<>();
178 | // 需要解析的自定义注解 BindView OnClick
179 | annotations.add(Interceptor.class);
180 | return annotations;
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/drouter-compiler/src/main/java/com/drouter/compiler/ModuleProcessor.java:
--------------------------------------------------------------------------------
1 | package com.drouter.compiler;
2 |
3 | import com.drouter.base.annotation.Action;
4 | import com.drouter.compiler.util.TextUtils;
5 | import com.google.auto.service.AutoService;
6 | import com.squareup.javapoet.ClassName;
7 | import com.squareup.javapoet.JavaFile;
8 | import com.squareup.javapoet.MethodSpec;
9 | import com.squareup.javapoet.TypeSpec;
10 |
11 | import java.io.IOException;
12 | import java.lang.annotation.Annotation;
13 | import java.util.HashMap;
14 | import java.util.LinkedHashSet;
15 | import java.util.Map;
16 | import java.util.Set;
17 |
18 | import javax.annotation.processing.AbstractProcessor;
19 | import javax.annotation.processing.Filer;
20 | import javax.annotation.processing.ProcessingEnvironment;
21 | import javax.annotation.processing.Processor;
22 | import javax.annotation.processing.RoundEnvironment;
23 | import javax.lang.model.SourceVersion;
24 | import javax.lang.model.element.Element;
25 | import javax.lang.model.element.Modifier;
26 | import javax.lang.model.element.TypeElement;
27 | import javax.lang.model.type.TypeMirror;
28 | import javax.lang.model.util.Elements;
29 | import javax.tools.Diagnostic;
30 |
31 | /**
32 | * description:
33 | * author: Darren on 2018/1/22 12:29
34 | * email: 240336124@qq.com
35 | * version: 1.0
36 | */
37 | @AutoService(Processor.class)
38 | public class ModuleProcessor extends AbstractProcessor {
39 | private Elements mElementUtils;
40 | private Filer mFiler;
41 | private final String KEY_MODULE_NAME = "moduleName";
42 | private TypeMirror iRouterAction = null;
43 |
44 | @Override
45 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
46 | super.init(processingEnvironment);
47 | mFiler = processingEnvironment.getFiler();
48 | mElementUtils = processingEnvironment.getElementUtils();
49 | iRouterAction = mElementUtils.getTypeElement(Consts.ROUTERACTION).asType();
50 | }
51 |
52 | @Override
53 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
54 |
55 | // 1. 有没配置 modelName 防止 class 类冲突
56 | String moduleName = "";
57 |
58 | Map options = processingEnv.getOptions();
59 | if (isNotEmpty(options)) {
60 | moduleName = options.get(KEY_MODULE_NAME);
61 | }
62 |
63 | System.out.println("moduleName = " + moduleName);
64 |
65 | if (!TextUtils.isEmpty(moduleName)) {
66 | moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");
67 | } else {
68 | String errorMessage = "These no module name, at 'build.gradle', like :\n" +
69 | "apt {\n" +
70 | " arguments {\n" +
71 | " moduleName project.getName();\n" +
72 | " }\n" +
73 | "}\n";
74 | throw new RuntimeException("DRouter::Compiler >>> No module name, for more information, look at gradle log.\n" + errorMessage);
75 | }
76 |
77 | // 3. 生成 Java 类,效果如下
78 | /*public class DRouter$$Assist implements IRouterAssist {
79 |
80 | Map modules = new HashMap<>();
81 |
82 | public DRouter$$Assist() {
83 | modules.put("login/module", "com.login.module.LoginModule");
84 | }
85 |
86 | @Override
87 | public String findModuleClassName(String moduleName) {
88 | return modules.get(moduleName);
89 | }
90 | }*/
91 | // 生成类继承和实现接口
92 | ClassName routerAssistClassName = ClassName.get("com.drouter.api.action", "IRouterModule");
93 | ClassName mapClassName = ClassName.get("java.util", "Map");
94 | TypeSpec.Builder classBuilder = TypeSpec.classBuilder("DRouter$$Module$$" + moduleName)
95 | .addModifiers(Modifier.FINAL, Modifier.PUBLIC)
96 | .addSuperinterface(routerAssistClassName)
97 | .addField(mapClassName, "actions", Modifier.PRIVATE);
98 |
99 | // 构造函数
100 | MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
101 | constructorMethodBuilder.addStatement("actions = new $T<>()", ClassName.bestGuess("java.util.HashMap"));
102 |
103 | // 2. 解析到所有的 Action 信息
104 | Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Action.class);
105 | Map modules = new HashMap<>(elements.size());
106 |
107 | ClassName actionWrapperClassName = ClassName.get("com.drouter.api.extra", "ActionWrapper");
108 | ClassName threadModeClassName = ClassName.get("com.drouter.base", "ThreadMode");
109 | for (Element element : elements) {
110 |
111 | // 获取注解上面的 action
112 | Action actionAnnotation = element.getAnnotation(Action.class);
113 | String actionName = actionAnnotation.path();
114 |
115 | // 必须以配置的 gradle 包名开头
116 | if (!actionName.startsWith(moduleName + "/")) {
117 | error(element, "Path name of the action must begin with %s%s", moduleName, "/");
118 | }
119 | // 获取 Action 的 ClassName
120 | Element enclosingElement = element.getEnclosingElement();
121 | String packageName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
122 | String actionClassName = packageName + "." + element.getSimpleName();
123 |
124 | // 判断 Interceptor 注解类是否实现了 ActionInterceptor
125 | if (!((TypeElement) element).getInterfaces().contains(iRouterAction)) {
126 | error(element, "%s verify failed, @Action must be implements %s", element.getSimpleName().toString(), Consts.ROUTERACTION);
127 | }
128 |
129 | if (modules.containsKey(actionName)) {
130 | // 输出错误,Action 名称冲突重复了
131 | error(element, "%s module name already exists", actionName);
132 | }
133 | // 添加到集合
134 | modules.put(actionName, actionClassName);
135 |
136 | constructorMethodBuilder.addStatement("this.actions.put($S,$T.build($T.class, $S, "
137 | + actionAnnotation.extraProcess() + ", $T." + actionAnnotation.threadMode() + "))",
138 | actionName, actionWrapperClassName, ClassName.bestGuess(actionClassName), actionName, threadModeClassName);
139 | }
140 |
141 | // 实现方法
142 |
143 | MethodSpec.Builder unbindMethodBuilder = MethodSpec.methodBuilder("findAction")
144 | .addParameter(String.class, "actionName")
145 | .addAnnotation(Override.class)
146 | .returns(actionWrapperClassName)
147 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
148 | unbindMethodBuilder.addStatement("return (ActionWrapper)actions.get(actionName)");
149 |
150 | classBuilder.addMethod(constructorMethodBuilder.build());
151 | classBuilder.addMethod(unbindMethodBuilder.build());
152 |
153 | // 生成类,看下效果
154 | try {
155 | JavaFile.builder(Consts.ROUTER_MODULE_PACK_NAME, classBuilder.build())
156 | .addFileComment("DRouter 自动生成")
157 | .build().writeTo(mFiler);
158 | } catch (IOException e) {
159 | e.printStackTrace();
160 | System.out.println("翻车了!");
161 | }
162 |
163 | return false;
164 | }
165 |
166 |
167 | private boolean isNotEmpty(Map options) {
168 | return options != null && !options.isEmpty();
169 | }
170 |
171 | private void error(Element element, String message, String... args) {
172 | printMessage(Diagnostic.Kind.ERROR, element, message, args);
173 | }
174 |
175 | private void printMessage(Diagnostic.Kind kind, Element element, String message, Object[] args) {
176 | if (args.length > 0) {
177 | message = String.format(message, args);
178 | }
179 |
180 | processingEnv.getMessager().printMessage(kind, message, element);
181 | }
182 |
183 |
184 | // 1. 指定处理的版本
185 | @Override
186 | public SourceVersion getSupportedSourceVersion() {
187 | return SourceVersion.latestSupported();
188 | }
189 |
190 | // 2. 给到需要处理的注解
191 | @Override
192 | public Set getSupportedAnnotationTypes() {
193 | Set types = new LinkedHashSet<>();
194 | for (Class extends Annotation> annotation : getSupportedAnnotations()) {
195 | types.add(annotation.getCanonicalName());
196 | }
197 | return types;
198 | }
199 |
200 | private Set> getSupportedAnnotations() {
201 | Set> annotations = new LinkedHashSet<>();
202 | // 需要解析的自定义注解 BindView OnClick
203 | annotations.add(Action.class);
204 | return annotations;
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/drouter-compiler/src/main/java/com/drouter/compiler/util/TextUtils.java:
--------------------------------------------------------------------------------
1 | package com.drouter.compiler.util;
2 |
3 | /**
4 | * description:
5 | * author: Darren on 2018/1/22 17:45
6 | * email: 240336124@qq.com
7 | * version: 1.0
8 | */
9 | public class TextUtils {
10 | public static boolean isEmpty(String moduleName) {
11 | return moduleName == null || moduleName.isEmpty();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HCDarren/DRouter/a2b02ee109775b8b719b57857f1c4819c7b35111/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jan 22 09:42:50 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/login-module/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/login-module/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 | repositories {
7 | mavenCentral()
8 | }
9 |
10 | defaultConfig {
11 | minSdkVersion 15
12 | targetSdkVersion 26
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
17 |
18 | javaCompileOptions {
19 | annotationProcessorOptions {
20 | arguments = [moduleName: "login"]
21 | }
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation 'com.android.support:appcompat-v7:26.1.0'
37 | testImplementation 'junit:junit:4.12'
38 | compile project(':base-core')
39 | annotationProcessor project(':drouter-compiler')
40 | }
41 |
--------------------------------------------------------------------------------
/login-module/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 |
--------------------------------------------------------------------------------
/login-module/src/androidTest/java/com/login/module/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.login.module;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.login.module.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/login-module/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/login-module/src/main/java/com/login/module/LoginAction.java:
--------------------------------------------------------------------------------
1 | package com.login.module;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.drouter.api.action.IRouterAction;
7 | import com.drouter.api.result.RouterResult;
8 | import com.drouter.base.ThreadMode;
9 | import com.drouter.base.annotation.Action;
10 |
11 | import java.util.Map;
12 |
13 | /**
14 | * description:
15 | * author: Darren on 2018/1/22 10:57
16 | * email: 240336124@qq.com
17 | * version: 1.0
18 | */
19 | @Action(path = "login/action", threadMode = ThreadMode.MAIN)
20 | public class LoginAction implements IRouterAction {
21 |
22 | @Override
23 | public RouterResult invokeAction(Context context, Map requestData) {
24 | Intent intent = new Intent(context, LoginActivity.class);
25 | intent.putExtra("key", (String) requestData.get("key"));
26 | context.startActivity(intent);
27 | return new RouterResult.Builder().success().object(100).build();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/login-module/src/main/java/com/login/module/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.login.module;
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 | import android.widget.Toast;
9 |
10 | import com.drouter.api.core.DRouter;
11 | import com.drouter.api.result.ActionCallback;
12 | import com.drouter.api.result.RouterResult;
13 |
14 | /**
15 | * description:
16 | * author: Darren on 2018/1/22 15:08
17 | * email: 240336124@qq.com
18 | * version: 1.0
19 | */
20 | public class LoginActivity extends AppCompatActivity {
21 | @Override
22 | public void onCreate(@Nullable Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_login);
25 |
26 | String key = getIntent().getStringExtra("key");
27 | Toast.makeText(this, key, Toast.LENGTH_LONG).show();
28 | }
29 |
30 | public void click(View view){
31 | DRouter.getInstance()
32 | .action("circlemodule/test")
33 | .context(this)
34 | .param("key", "value")
35 | .invokeAction(new ActionCallback() {
36 | @Override
37 | public void onInterrupt() {
38 | Log.e("TAG", "被拦截了");
39 | }
40 |
41 | @Override
42 | public void onResult(RouterResult result) {
43 | Log.e("TAG", "result = " + result.toString());
44 | }
45 | });
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/login-module/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/login-module/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | login-module
3 |
4 |
--------------------------------------------------------------------------------
/login-module/src/test/java/com/login/module/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.login.module;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':drouter-api', ':login-module', ':base-core', ':drouter-compiler', ':drouter-base', ':circle-module'
2 |
--------------------------------------------------------------------------------