map = new HashMap<>();
13 | //
14 | // static {
15 | // RouteBean.createBean(map, "/home", "com.seeker.tony.myapplication.IntentActivity");
16 | // RouteBean.createBean(map, "/home/action", "com.seeker.tony.myapplication.action.TestAction");
17 | // }
18 | //
19 | //
20 | //}
21 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/data/RouterTableSample.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.data;
2 |
3 | /**
4 | * 生成的代码
5 | *
6 | * @author zhengxiaobin
7 | * @since 17/7/14
8 | */
9 |
10 | //public class RouterTableSample {
11 | //
12 | // public static void register() {
13 | // RouterBean bean = new RouterBean("/action", "com.seeker.tony.myapplication.action.TestAction");
14 | // RouterTable.registerRouter(bean.uri, bean);
15 | //
16 | // RouterBean.createBean("/home", "com.seeker.tony.myapplication.IntentActivity");
17 | // RouterTable.registerRouter(bean.uri, bean);
18 | // }
19 | //}
20 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/RouterCenterActivity.java:
--------------------------------------------------------------------------------
1 | package com.jet.router;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.os.PersistableBundle;
6 |
7 | /**
8 | * 路由中心页面
9 | *
10 | * @author zhengxiaobin
11 | * @since 17/7/17
12 | */
13 | public class RouterCenterActivity extends Activity {
14 | @Override
15 | public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
16 | super.onCreate(savedInstanceState, persistentState);
17 | }
18 |
19 | @Override
20 | protected void onPause() {
21 | super.onPause();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.jet.router.Router;
7 |
8 |
9 | /**
10 | * @author zhengxiaobin
11 | * @since 17/7/13
12 | */
13 |
14 | public class MyApplication extends Application {
15 | private static Context context;
16 |
17 | @Override
18 | public void onCreate() {
19 | super.onCreate();
20 | context = this.getApplicationContext();
21 | Router.getInstance().init(this);
22 | }
23 |
24 | public static Context getContext() {
25 | return context;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/module_b/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/jet_annotation/src/main/java/com.meiyou.annotation/JUri.java:
--------------------------------------------------------------------------------
1 | package com.jet.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 | /**
10 | * URI实现:
11 | *
12 | * http://git.meiyou.im/Android/Route
13 | *
14 | * @author zhengxiaobin
15 | * @since 17/5/18
16 | */
17 | @Target(ElementType.TYPE) // 代表在类级别上才能使用该注解
18 | @Retention(RetentionPolicy.SOURCE) // 代表该注解只存在源代码中,编译后的字节码中不存在
19 | public @interface JUri {
20 |
21 | String value() default "";
22 |
23 | /**
24 | * 设置Default, 就可以不用初始化
25 | *
26 | * @return
27 | */
28 | String[] array() default {};
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/meiyou/UriMeiyou.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.meiyou;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | /**
6 | * 美柚特定的Path;
7 | *
8 | * @author zhengxiaobin
9 | * @since 17/7/25
10 | */
11 |
12 | public class UriMeiyou {
13 |
14 | public static UriMeiyou HOME = new UriMeiyou("/home");
15 |
16 |
17 | String path = "";
18 |
19 | /**
20 | * 构造方法,传入Path: "/home"
21 | *
22 | * @param path
23 | */
24 | public UriMeiyou(@NonNull String path) {
25 | this.path = path;
26 | }
27 |
28 | /**
29 | * 获取Meiyou Path;
30 | *
31 | * @return
32 | */
33 | public String getPath() {
34 | return "meiyou://" + path;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
18 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/intercept/UriInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.intercept;
2 |
3 | /**
4 | * 抽象拦截器
5 | *
6 | * @param
7 | */
8 | public abstract class UriInterceptor {
9 |
10 | public static final int LEVEL_LOW = 0;
11 | public static final int LEVEL_NORMAL = 1;
12 | public static final int LEVEL_HIGH = 2;
13 |
14 |
15 | /**
16 | * @param data 入参
17 | * @return data
18 | */
19 | public InterceptorData beforeExecute(InterceptorData data) {
20 | return data;
21 | }
22 |
23 | // /**
24 | // *
25 | // * @param data data
26 | // * @param httpResult result
27 | // * @return result
28 | // */
29 | // public Result afterExecute(final InterceptorData data ,Result result) {
30 | // return httpResult;
31 | // }
32 | //
33 | }
--------------------------------------------------------------------------------
/jet_compiler/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 | dependencies {
5 | compile fileTree(include: ['*.jar'], dir: 'libs')
6 | compile project(':jet_annotation')
7 | compile 'com.squareup:javapoet:1.8.0'
8 | compile 'com.google.auto.service:auto-service:1.0-rc2'
9 | compile 'com.google.code.gson:gson:2.2.4'
10 | }
11 |
12 | sourceCompatibility = "1.7"
13 | targetCompatibility = "1.7"
14 |
15 | apply from:rootProject.file("mvn_java.gradle")
16 |
17 | publish {
18 | userOrg = 'gybin02' //bintray注册的用户名
19 | groupId = 'com.meiyou.framework' //compile引用时的第1部分groupId
20 | artifactId = 'router-compiler' //compile引用时的第2部分项目名
21 | publishVersion = '1.0.0' //compile引用时的第3部分版本号
22 | desc = '美柚路由库;Android平台对页面、服务的路由框架。自动化且易用'
23 | website = 'https://github.com/gybin02/RouterKit'
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/action/TestAction.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication.action;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 | import com.jet.annotation.JUri;
7 | import com.jet.router.action.Action;
8 | import com.seeker.tony.myapplication.MyApplication;
9 |
10 | import java.util.Map;
11 |
12 | /**
13 | * 测试URI 使用Action
14 | *
15 | * @author zhengxiaobin
16 | * @since 17/7/13
17 | */
18 |
19 | @JUri("/action")
20 | public class TestAction extends Action {
21 | Context context = MyApplication.getContext();
22 |
23 | @Override
24 | public void run(Map queryMap) {
25 | super.run(queryMap);
26 | //Uri 里面的参数通过Map传递进来
27 | String result = (String) queryMap.get("param");
28 | Toast.makeText(context, "Test Action: " + result, Toast.LENGTH_SHORT).show();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/module_b/src/androidTest/java/com/meiyou/jet/module_b/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.jet.jet.module_b;
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 | * Instrumentation 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.jet.jet.module_b.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/jet_router/src/androidTest/java/com/meiyou/jet/jet_router/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.jet.jet.jet_router;
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 | * Instrumentation 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.jet.jet.jet_router.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/seeker/tony/myapplication/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication;
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 | * Instrumentation 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.seeker.tony.myapplication", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/jet_annotation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 | dependencies {
5 | compile fileTree(dir: 'libs', include: ['*.jar'])
6 | }
7 |
8 | sourceCompatibility = "1.7"
9 | targetCompatibility = "1.7"
10 |
11 | apply from:rootProject.file("mvn_java.gradle")
12 |
13 | publish {
14 | userOrg = 'gybin02' //bintray注册的用户名
15 | groupId = 'com.meiyou.framework' //compile引用时的第1部分groupId
16 | artifactId = 'router-annotation' //compile引用时的第2部分项目名
17 | publishVersion = '1.0.0' //compile引用时的第3部分版本号
18 | desc = '美柚路由库;Android平台对页面、服务的路由框架。自动化且易用'
19 | website = 'https://github.com/gybin02/RouterKit'
20 | }
21 |
22 | //task javadoc(type: Javadoc) {
23 | // source = android.sourceSets.main.java.srcDirs
24 | // classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
25 | // failOnError false
26 | // options.encoding "UTF-8"
27 | // options.charSet 'UTF-8'
28 | //}
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_fragment_blank.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
19 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/tony/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/util/AssetUtil.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.util;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 |
8 | /**
9 | * Asset 帮助类
10 | * @author zhengxiaobin
11 | * @since 2016/3/31
12 | */
13 | public class AssetUtil {
14 | /**
15 | * 从Asset 中读出String
16 | * 如: "door/h5Resource.json"
17 | *
18 | * @param mContext
19 | * @param jsonFile
20 | * @return
21 | */
22 | public static String getStringFromAsset(Context mContext, String jsonFile) {
23 | String result = "";
24 | try {
25 | //读取文件数据
26 | InputStream is = mContext.getResources().getAssets().open(jsonFile);
27 | byte[] buffer = new byte[is.available()];
28 | is.read(buffer);//输出流
29 | result = new String(buffer, "utf-8");
30 | is.close();
31 | } catch (IOException e) {
32 | e.printStackTrace();
33 | }
34 | return result;
35 | }
36 | }
--------------------------------------------------------------------------------
/jet_router/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/tony/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/module_b/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/tony/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/module_b/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 |
30 | compile project(':jet_router')
31 |
32 | // compile "com.jet.framework:router:${DEPEND_VERSION}"
33 |
34 | compile 'com.android.support:appcompat-v7:25.3.1'
35 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
36 | testCompile 'junit:junit:4.12'
37 |
38 |
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/mvn_java.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven'
2 | //apply plugin: 'com.github.dcendents.android-maven'
3 | repositories {
4 | mavenCentral()
5 | }
6 |
7 | //for project dependency
8 | project.group = GROUP_ID
9 | project.version = COMPONENT_VERSION
10 | task deploy <<{
11 | }
12 | deploy.dependsOn uploadArchives
13 |
14 | uploadArchives {
15 | def typePattern = ~"[0-9]\\.[0-9]\\.[0-9]\$"
16 | def depolyTypeUrl
17 | if(typePattern.matcher(COMPONENT_VERSION)){
18 | println "warn ! find release version! will deploy release aar! version is $COMPONENT_VERSION "
19 | depolyTypeUrl= deployUrl.replace("snapshots","releases")
20 | }else {
21 | depolyTypeUrl = deployUrl
22 | }
23 | // depolyTypeUrl= deployUrl.replace("snapshots","releases")
24 | //println "depolyTypeUrl " + depolyTypeUrl
25 |
26 | repositories.mavenDeployer {
27 | repository(url: depolyTypeUrl) {
28 | authentication(userName: deployUserName, password: deployPassword)
29 | }
30 | pom.project {
31 | groupId GROUP_ID
32 | artifactId POM_ARTIFACT_ID
33 | packaging PACKAGE_FORMAT
34 | version COMPONENT_VERSION
35 |
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/routable/RouteContext.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.routable;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 |
6 | import java.util.Map;
7 |
8 | /**
9 | * The class supplied to custom callbacks to describe the route route
10 | */
11 | public class RouteContext {
12 | Map _params;
13 | Bundle _extras;
14 | Context _context;
15 |
16 | public RouteContext(Map params, Bundle extras, Context context) {
17 | _params = params;
18 | _extras = extras;
19 | _context = context;
20 | }
21 |
22 | /**
23 | * Returns the route parameters as specified by the configured route
24 | */
25 | public Map getParams() {
26 | return _params;
27 | }
28 |
29 | /**
30 | * Returns the extras supplied with the route
31 | */
32 | public Bundle getExtras() {
33 | return _extras;
34 | }
35 |
36 | /**
37 | * Returns the Android Context that should be used to open the route
38 | */
39 | public Context getContext() {
40 | return _context;
41 | }
42 | }
--------------------------------------------------------------------------------
/mvn.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven'
2 | //apply plugin: 'com.github.dcendents.android-maven'
3 | repositories {
4 | mavenCentral()
5 | }
6 |
7 | //for project dependency
8 | project.group = GROUP_ID
9 | project.version = COMPONENT_VERSION
10 | task deploy <<{
11 | }
12 | deploy.dependsOn uploadArchives
13 |
14 | uploadArchives {
15 | def typePattern = ~"[0-9]\\.[0-9]\\.[0-9]\$"
16 | def depolyTypeUrl
17 | if(typePattern.matcher(COMPONENT_VERSION)){
18 | println "warn ! find release version! will deploy release aar! version is $COMPONENT_VERSION "
19 | depolyTypeUrl= deployUrl.replace("snapshots","releases")
20 | }else {
21 | depolyTypeUrl = deployUrl
22 | }
23 | // depolyTypeUrl= deployUrl.replace("snapshots","releases")
24 | //println "depolyTypeUrl " + depolyTypeUrl
25 |
26 | repositories.mavenDeployer {
27 | repository(url: depolyTypeUrl) {
28 | authentication(userName: deployUserName, password: deployPassword)
29 | }
30 | pom.project {
31 | groupId GROUP_ID
32 | artifactId POM_ARTIFACT_ID
33 | packaging PACKAGE_FORMAT
34 | version COMPONENT_VERSION
35 |
36 | }
37 | }
38 | }
39 |
40 | task androidSourcesJar(type: Jar) {
41 | classifier = 'sources'
42 | from android.sourceSets.main.java.sourceFiles
43 | }
44 |
45 | artifacts {
46 | archives androidSourcesJar
47 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_blank.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
13 |
14 |
18 |
19 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | #org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | #服务器地址
15 | deployUrl=http\://192.168.10.230\:8081/nexus/content/repositories/snapshots/
16 | deployReleaseUrl=http\://192.168.10.230\:8081/nexus/content/repositories/releases/
17 | thirdpartyUrl=http\://192.168.10.230\:8081/nexus/content/repositories/thirdparty/
18 | #账号密码
19 | deployUserName=admin
20 | deployPassword=admin123
21 | #打包格式
22 | PACKAGE_FORMAT=aar
23 | doPackage=True
24 |
25 | #测试APT,避免代码没变化,APT不执行
26 | android.enableBuildCache=false
27 |
28 | org.gradle.daemon=true
29 | org.gradle.jvmargs=-Xmx1536m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
30 |
31 | #依赖底层版本
32 | DEPEND_VERSION=0.0.1-SNAPSHOT
33 | #DEPEND_VERSION=1.0.0
34 |
35 | #打包发布版本
36 | COMPONENT_VERSION=0.0.1-SNAPSHOT
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_intent.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
26 |
27 |
35 |
36 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/model/RouterBean.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.model;
2 |
3 | import android.support.annotation.IntDef;
4 |
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 |
8 | /**
9 | * 数据
10 | *
11 | * @author zhengxiaobin
12 | * @since 17/7/13
13 | */
14 |
15 | public class RouterBean {
16 | /**
17 | * 需要处理的URI
18 | */
19 | public String uri;
20 | /**
21 | * 处理的类名: 需要 Java规范命名: com.test.action.TestAction
22 | */
23 | public String target;
24 | /**
25 | * target类型:
26 | */
27 |
28 | public static final int TYPE_UI = 1;
29 | public static final int TYPE_METHOD = 2;
30 |
31 | public
32 | @RouterType
33 | int type;
34 |
35 | @IntDef({TYPE_UI, TYPE_METHOD})
36 | @Retention(RetentionPolicy.SOURCE)
37 | public @interface RouterType {
38 |
39 | }
40 |
41 |
42 | // private RouterBean(String uri, String target, RouterType type) {
43 | // this.uri = uri;
44 | // this.target = target;
45 | // this.type = type;
46 | // }
47 |
48 | /**
49 | * 初始化
50 | *
51 | * @param uri
52 | * @param target
53 | */
54 | public RouterBean(String uri, String target) {
55 | int type = getType(target);
56 | this.uri = uri;
57 | this.target = target;
58 | this.type = type;
59 | }
60 |
61 | /**
62 | * 获取URI类型
63 | *
64 | * @param target
65 | * @return
66 | */
67 | public static
68 | @RouterBean.RouterType
69 | int getType(String target) {
70 | int type = RouterBean.TYPE_METHOD;
71 | // TODO: 17/7/14 需要更严格的判断
72 | if (target.contains("Activity")) {
73 | type = RouterBean.TYPE_UI;
74 | }
75 | return type;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/jet_compiler/src/main/java/com/meiyou/compiler/MethodInfoProcessor.java:
--------------------------------------------------------------------------------
1 | package com.jet.compiler;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.jet.annotation.MethodInfo;
5 |
6 | import java.util.HashMap;
7 | import java.util.Set;
8 |
9 | import javax.annotation.processing.AbstractProcessor;
10 | import javax.annotation.processing.ProcessingEnvironment;
11 | import javax.annotation.processing.Processor;
12 | import javax.annotation.processing.RoundEnvironment;
13 | import javax.annotation.processing.SupportedAnnotationTypes;
14 | import javax.annotation.processing.SupportedSourceVersion;
15 | import javax.lang.model.SourceVersion;
16 | import javax.lang.model.element.Element;
17 | import javax.lang.model.element.TypeElement;
18 | import javax.lang.model.util.Elements;
19 |
20 | @Deprecated
21 | @AutoService(Processor.class)
22 | //对应getSupportedSourceVersion方法
23 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
24 | //对应getSupportedAnnotationTypes方法
25 | @SupportedAnnotationTypes({ "com.jet.annotation.MethodInfo" })
26 | public class MethodInfoProcessor extends AbstractProcessor {
27 | @Override
28 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment env) {
29 | HashMap map = new HashMap();
30 | for (TypeElement te : annotations) {
31 | for (Element element : env.getElementsAnnotatedWith(te)) {
32 | MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
33 | map.put(element.getEnclosingElement().toString(), methodInfo.author());
34 | }
35 | }
36 | return false;
37 | }
38 |
39 | @Override
40 | public synchronized void init(ProcessingEnvironment processingEnv) {
41 | super.init(processingEnv);
42 | Elements elementUtils = processingEnv.getElementUtils();
43 | }
44 | }
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/routable/RouterOptions.java:
--------------------------------------------------------------------------------
1 | package com.jet.router.routable;
2 |
3 | import android.app.Activity;
4 |
5 | import java.util.Map;
6 |
7 | /**
8 | * The class used to determine behavior when opening a URL.
9 | * If you want to extend Routable to handle things like transition
10 | * animations or fragments, this class should be augmented.
11 | */
12 | public class RouterOptions {
13 | Class extends Activity> _klass;
14 | RouterCallback _callback;
15 | Map _defaultParams;
16 |
17 | public RouterOptions() {
18 |
19 | }
20 |
21 | public RouterOptions(Class extends Activity> klass) {
22 | this.setOpenClass(klass);
23 | }
24 |
25 | public RouterOptions(Map defaultParams) {
26 | this.setDefaultParams(defaultParams);
27 | }
28 |
29 | public RouterOptions(Map defaultParams, Class extends Activity> klass) {
30 | this.setDefaultParams(defaultParams);
31 | this.setOpenClass(klass);
32 | }
33 |
34 | public void setOpenClass(Class extends Activity> klass) {
35 | this._klass = klass;
36 | }
37 |
38 | public Class extends Activity> getOpenClass() {
39 | return this._klass;
40 | }
41 |
42 | public RouterCallback getCallback() {
43 | return this._callback;
44 | }
45 |
46 | public void setCallback(RouterCallback callback) {
47 | this._callback = callback;
48 | }
49 |
50 | public void setDefaultParams(Map defaultParams) {
51 | this._defaultParams = defaultParams;
52 | }
53 |
54 | public Map getDefaultParams() {
55 | return this._defaultParams;
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/IntentActivity.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v4.app.FragmentTransaction;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.util.Log;
8 |
9 | import com.jet.annotation.JUri;
10 | import com.jet.jet.annotation.JIntent;
11 | import com.jet.jet.process.Jet;
12 |
13 | import java.io.Serializable;
14 |
15 | /**
16 | * Uri 的参数通过 Intent传递进来
17 | */
18 | @JUri("/home")
19 | public class IntentActivity extends AppCompatActivity {
20 | @JIntent("stringExtra")
21 | String stringExtra;
22 | @JIntent("intExtra")
23 | int intExtra;
24 | @JIntent("longExtra")
25 | long longExtra;
26 | @JIntent("booleanExtra")
27 | boolean booleanExtra;
28 | @JIntent("serializable")
29 | Serializable serializable;
30 | @JIntent("bundle")
31 | Bundle bundle;
32 | @JIntent("stringArrays")
33 | String[] stringArrays;
34 |
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_intent);
40 | Jet.bind(this);
41 | // Intent intent = getIntent();
42 | // String stringExtra = intent.getStringExtra("stringExtra");
43 | // int intExtra = intent.getIntExtra("intExtra", 0);
44 | // long longExtra = intent.getLongExtra("longExtra", 0);
45 | // boolean booleanExtra = intent.getBooleanExtra("booleanExtra", false);
46 | // Serializable serializable = intent.getSerializableExtra("serializable");
47 | // Bundle bundle = intent.getBundleExtra("bundle");
48 | // String[] stringArrays = intent.getStringArrayExtra("stringArray");
49 | Intent intent = getIntent();
50 |
51 | Log.e("intent", "intent test:" + intent.getExtras().toString());
52 | // View content = findViewById(R.id.fl_content);
53 | BlankFragment blankFragment = BlankFragment.newInstance(this);
54 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
55 | transaction.add(R.id.fl_content, blankFragment);
56 | transaction.commit();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/jet_compiler/src/main/java/com/meiyou/compiler/PrintProcessor.java:
--------------------------------------------------------------------------------
1 | package com.jet.compiler;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.jet.annotation.Print;
5 |
6 | import java.util.LinkedHashSet;
7 | import java.util.Set;
8 |
9 | import javax.annotation.processing.AbstractProcessor;
10 | import javax.annotation.processing.Messager;
11 | import javax.annotation.processing.ProcessingEnvironment;
12 | import javax.annotation.processing.Processor;
13 | import javax.annotation.processing.RoundEnvironment;
14 | import javax.annotation.processing.SupportedAnnotationTypes;
15 | import javax.annotation.processing.SupportedSourceVersion;
16 | import javax.lang.model.SourceVersion;
17 | import javax.lang.model.element.Element;
18 | import javax.lang.model.element.TypeElement;
19 | import javax.tools.Diagnostic;
20 | @Deprecated
21 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
22 | @AutoService(Processor.class)
23 | @SupportedAnnotationTypes("com.jet.annotation.Print")
24 | public class PrintProcessor extends AbstractProcessor {
25 |
26 | private Messager mMessager;
27 |
28 | @Override
29 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
30 | super.init(processingEnvironment);
31 | mMessager = processingEnvironment.getMessager();
32 | }
33 |
34 | @Override
35 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
36 | for (TypeElement te : annotations) {
37 | for (Element e : roundEnv.getElementsAnnotatedWith(te)) {//find special annotationed element
38 | print(e.toString());//print element
39 | }
40 | }
41 | return true;
42 | }
43 |
44 | @Override
45 | public SourceVersion getSupportedSourceVersion() {
46 | return SourceVersion.latestSupported();
47 | }
48 |
49 | @Override
50 | public Set getSupportedAnnotationTypes() {
51 | LinkedHashSet annotations = new LinkedHashSet<>();
52 | annotations.add(Print.class.getCanonicalName());
53 | return super.getSupportedAnnotationTypes();
54 | }
55 |
56 | private void print(String msg) {
57 | mMessager.printMessage(Diagnostic.Kind.NOTE, msg);
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/common/Mock.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication.common;
2 |
3 | import org.json.JSONObject;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.Random;
8 |
9 | /**
10 | * Mock 数据类;
11 | *
12 | * @author zhengxiaobin
13 | * @since 17/6/9
14 | */
15 |
16 | public class Mock {
17 |
18 | /**
19 | * 模拟Map 数据
20 | *
21 | * @return
22 | */
23 | public static HashMap getMap() {
24 | HashMap map = new HashMap<>();
25 | map.put("key_int", 10000);
26 | map.put("key_string", "Hello");
27 | map.put("key_random", new Random().nextInt(100));
28 | MockObj value = new MockObj();
29 | map.put("key_obj", value);
30 | return map;
31 | }
32 |
33 | public static ArrayList getList() {
34 | ArrayList list = new ArrayList<>();
35 | for (int i = 0; i < 10; i++) {
36 | list.add("data" + i);
37 | }
38 | return list;
39 | }
40 |
41 | /**
42 | * 测试数据 Map,含有嵌套
43 | *
44 | * @return
45 | */
46 | public static HashMap getSampleMap() {
47 | HashMap map = new HashMap<>();
48 | map.put("event", "event11");
49 | map.put("event2", false);
50 | map.put("event3", 89);
51 | HashMap paramMap = new HashMap<>();
52 | paramMap.put("param1", "value1");
53 | paramMap.put("param2", 3);
54 | map.put("attribute", paramMap);
55 | return map;
56 |
57 | }
58 |
59 |
60 | /**
61 | * 测试数据 Json
62 | *
63 | * @return
64 | */
65 | public static JSONObject getSampleJson() {
66 | JSONObject object = new JSONObject();
67 | try {
68 | object.put("event", "event11");
69 | object.put("event2", "event2");
70 | JSONObject param = new JSONObject();
71 | param.put("param1", "param1");
72 | param.put("param2", "param2");
73 | object.put("attribute", param);
74 | } catch (Exception e) {
75 | e.printStackTrace();
76 | }
77 | return object;
78 | }
79 |
80 | private static class MockObj {
81 | String name = "Mike";
82 | int age = 39;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/jet_compiler/src/main/java/com/meiyou/compiler/AutoParcelProcessor.java:
--------------------------------------------------------------------------------
1 | package com.jet.compiler;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.jet.annotation.AutoParcel;
5 |
6 | import java.io.IOException;
7 | import java.util.Collection;
8 | import java.util.List;
9 | import java.util.Set;
10 |
11 | import javax.annotation.processing.AbstractProcessor;
12 | import javax.annotation.processing.Processor;
13 | import javax.annotation.processing.RoundEnvironment;
14 | import javax.annotation.processing.SupportedAnnotationTypes;
15 | import javax.annotation.processing.SupportedSourceVersion;
16 | import javax.lang.model.SourceVersion;
17 | import javax.lang.model.element.Element;
18 | import javax.lang.model.element.TypeElement;
19 | import javax.lang.model.util.ElementFilter;
20 | import javax.tools.JavaFileObject;
21 | @Deprecated
22 | @AutoService(Processor.class)
23 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
24 | @SupportedAnnotationTypes("com.jet.annotation.AutoParcel")
25 | public final class AutoParcelProcessor extends AbstractProcessor {
26 |
27 | @Override
28 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
29 | Collection extends Element> annotatedElements =
30 | roundEnvironment.getElementsAnnotatedWith(AutoParcel.class);
31 | List typesIn = ElementFilter.typesIn(annotatedElements);
32 |
33 | // List types =
34 | // new ArrayList().Builder()
35 | // .addAll(ElementFilter.typesIn(annotatedElements))
36 | // .build();
37 |
38 | for (TypeElement type : typesIn) {
39 | processType(type);
40 | }
41 |
42 | // 返回 true ,其他处理器不关心 AutoParcel 注解
43 | return true;
44 | }
45 |
46 | private void processType(TypeElement type) {
47 | // String className = generatedSubclassName(type);
48 | // String source = generateClass(type, className);
49 | // writeSourceFile(className, source, type);
50 | }
51 |
52 | private void writeSourceFile(
53 | String className,
54 | String text,
55 | TypeElement originatingType) {
56 | try {
57 | JavaFileObject sourceFile =
58 | processingEnv.getFiler().
59 | createSourceFile(className, originatingType);
60 | // Writerwriter = sourceFile.openWriter();
61 | // try {
62 | // writer.write(text);
63 | // } finally {
64 | // writer.close();
65 | // }
66 | } catch (IOException e) {// silent}
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/jet_router/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 | android {
5 | lintOptions {
6 | abortOnError false
7 | }
8 | compileSdkVersion 25
9 | buildToolsVersion "25.0.2"
10 |
11 | defaultConfig {
12 | minSdkVersion 14
13 | targetSdkVersion 25
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 |
19 | }
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | testCompile 'junit:junit:4.12'
34 | compile 'com.android.support:support-annotations:25.0.1'
35 | compile 'com.google.code.gson:gson:2.2.4'
36 |
37 | //使用compile 也会使用APT生成代码,而且是模块间依赖会传递
38 | // compile project(':jet_compiler')
39 |
40 | // annotationProcessor project(':jet_compiler')
41 |
42 | if (doPackage == "True") {
43 | compile project(':jet_annotation')
44 | } else {
45 | compile "com.jet.framework:router-annotation:${DEPEND_VERSION}"
46 | }
47 |
48 | // compile "com.meiyou.framework:router-annotation:1.0.0"
49 |
50 | //也只会当前Module有效
51 | // annotationProcessor project(':jet_compiler')
52 | //provided 只会在当前Module编译,不会被打包到AAR
53 | // provided project(':jet_compiler')
54 | // compile依赖会被传递到上层
55 | // compile project(':jet_compiler')
56 |
57 | if (doPackage == "True") {
58 | compile project(':jet_compiler')
59 | } else {
60 | compile "com.jet.framework:router-compiler:${DEPEND_VERSION}"
61 | }
62 |
63 | // compile "com.meiyou.framework:router-compiler:1.0.0"
64 |
65 | apply from: rootProject.file("mvn.gradle")
66 | }
67 |
68 | publish {
69 | userOrg = 'gybin02' //bintray注册的用户名
70 | groupId = 'com.meiyou.framework' //compile引用时的第1部分groupId
71 | artifactId = 'router' //compile引用时的第2部分项目名
72 | publishVersion = '1.0.0' //compile引用时的第3部分版本号
73 | desc = '自动化且易用'
74 | website = 'https://github.com/gybin02/RouterKiter'
75 | }
76 |
77 | task javadoc(type: Javadoc) {
78 | source = android.sourceSets.main.java.srcDirs
79 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
80 | failOnError false
81 | options.encoding "utf-8"
82 | options.charSet 'utf-8'
83 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | //apply plugin: 'com.neenbedankt.android-apt'
3 | //apply plugin: 'android-aspectjx'
4 |
5 |
6 | android {
7 | compileSdkVersion 25
8 | buildToolsVersion "25.0.2"
9 | defaultConfig {
10 | applicationId "com.seeker.router"
11 | minSdkVersion 14
12 | targetSdkVersion 25
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | // compile project(':jet_router')
31 | // annotationProcessor project(':jet_compiler')
32 |
33 |
34 | compile 'com.android.support:appcompat-v7:25.0.0'
35 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
36 | compile 'com.android.support:design:25.0.1'
37 | testCompile 'junit:junit:4.12'
38 | compile 'com.jet.framework:jet:1.0.0'
39 |
40 | compile project(':module_b')
41 |
42 | //测试使用 编译器编译;
43 | // annotationProcessor project(':jet_compiler')
44 | // compile project(':jet_compiler')
45 |
46 | }
47 |
48 | //拷贝生成 META-INF 文件进去
49 | //android.applicationVariants.all { variant ->
50 | // def variantName = variant.name
51 | // def variantNameCapitalized = variantName.capitalize()
52 | // def copyMetaInf = tasks.create "copyMetaInf$variantNameCapitalized", Copy
53 | // copyMetaInf.from project.fileTree(javaCompile.destinationDir)
54 | // copyMetaInf.include "META-INF/**"
55 | // copyMetaInf.into "build/intermediates/sourceFolderJavaResources/$variantName"
56 | // tasks.findByName("transformResourcesWithMergeJavaResFor$variantNameCapitalized").dependsOn copyMetaInf
57 | //}
58 |
59 | //拷贝生成的 assets/目录到打包目录
60 | android.applicationVariants.all { variant ->
61 | def variantName = variant.name
62 | def variantNameCapitalized = variantName.capitalize()
63 | def copyMetaInf = tasks.create "copyMetaInf$variantNameCapitalized", Copy
64 | copyMetaInf.from project.fileTree(javaCompile.destinationDir)
65 | copyMetaInf.include "assets/**"
66 | copyMetaInf.into "build/intermediates/sourceFolderJavaResources/$variantName"
67 | tasks.findByName("transformResourcesWithMergeJavaResFor$variantNameCapitalized").dependsOn copyMetaInf
68 | }
69 |
70 | //tasks.getByPath(":jet_router:mavenAndroidJavadocs").enabled = false
71 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
27 |
28 |
35 |
36 |
41 |
42 |
47 |
48 |
53 |
54 |
55 |
61 |
62 |
68 |
69 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/jet_compiler/src/main/java/com/meiyou/compiler/TestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.jet.compiler;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.squareup.javapoet.JavaFile;
5 | import com.squareup.javapoet.MethodSpec;
6 | import com.squareup.javapoet.TypeSpec;
7 |
8 | import java.io.IOException;
9 | import java.util.Set;
10 |
11 | import javax.annotation.processing.AbstractProcessor;
12 | import javax.annotation.processing.Filer;
13 | import javax.annotation.processing.Messager;
14 | import javax.annotation.processing.ProcessingEnvironment;
15 | import javax.annotation.processing.Processor;
16 | import javax.annotation.processing.RoundEnvironment;
17 | import javax.annotation.processing.SupportedAnnotationTypes;
18 | import javax.annotation.processing.SupportedSourceVersion;
19 | import javax.lang.model.SourceVersion;
20 | import javax.lang.model.element.TypeElement;
21 | import javax.tools.Diagnostic;
22 |
23 | @Deprecated
24 | @AutoService(Processor.class)
25 | @SupportedAnnotationTypes({"com.jet.annotation.Test"})
26 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
27 | public class TestProcessor extends AbstractProcessor {
28 | private Filer filer;
29 | private Messager mMessager;
30 |
31 | @Override
32 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
33 | super.init(processingEnvironment);
34 | filer = processingEnv.getFiler();
35 | mMessager = processingEnv.getMessager();
36 | }
37 |
38 | // @Override
39 | // public SourceVersion getSupportedSourceVersion() {
40 | // return SourceVersion.latestSupported();
41 | // }
42 |
43 | // @Override
44 | // public Set getSupportedAnnotationTypes() {
45 | // LinkedHashSet annotations = new LinkedHashSet<>();
46 | // annotations.add(Test.class.getCanonicalName());
47 | // return annotations;
48 | // }
49 |
50 | @Override
51 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
52 | //Process 可能会执行多次,
53 | if (set == null || set.isEmpty()) {
54 | info(">>> set is null... <<<");
55 | return true;
56 | }
57 |
58 | System.out.println("------ process -----");
59 | //MethodSpec这个类是要引入'com.squareup:javapoet:1.8.0'包,方便通过代码创建java文件
60 | MethodSpec main = MethodSpec.methodBuilder("main")
61 | //.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
62 | .returns(void.class)
63 | .addParameter(String[].class, "args")
64 | .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
65 | .build();
66 |
67 | TypeSpec helloWorld = TypeSpec.classBuilder("HelloChina")
68 | .addMethod(main)
69 | .build();
70 |
71 | JavaFile javaFile = JavaFile.builder("com.francis.helloworld", helloWorld)
72 | .build();
73 |
74 | try {
75 | //这里的输出要在Gradle Console中看
76 | javaFile.writeTo(System.out);
77 |
78 |
79 | // javaFile.writeTo(new File());
80 | // javaFile.writeTo(filer);
81 |
82 | } catch (IOException e) {
83 | e.printStackTrace();
84 | }
85 | return true;
86 | }
87 |
88 | private void info(String msg, Object... args) {
89 | mMessager.printMessage(
90 | Diagnostic.Kind.NOTE,
91 | String.format(msg, args));
92 | }
93 |
94 | }
--------------------------------------------------------------------------------
/Readme_en.md:
--------------------------------------------------------------------------------
1 | [  ](https://bintray.com/gybin02/maven/router/_latestVersion)
2 | [](http://shang.qq.com/wpa/qunwpa?idkey=f474c19f6b6b7d67e91685511207bcd326a38f50818d8e4569e52a167df85009)
3 | [](https://www.apache.org/licenses/LICENSE-2.0)
4 | # RouterKit
5 | [中文wiki](/Readme.md).
6 | 
7 |
8 |
9 | ## Getting started
10 |
11 |
12 | //edit module build.gradle file:
13 | ```groove
14 | //内部版本:0.0.1-SNAPSHOT
15 | compile "com.jet.framework:router:1.0.0"
16 | ```
17 |
18 | ## Simple usage
19 | `RouterKit` uses annotation to specify the mapping relationship.
20 |
21 | - eg1: Page Router
22 |
23 | ```java
24 | @JUri("/home")
25 | public class IntentActivity extends AppCompatActivity {
26 | // Uri 的参数通过 Intent传递进来, 推荐使用Jet自动读取;
27 | .....
28 | //
29 | }
30 | ```
31 | - or eg2: service Router
32 | ```java
33 | //支持,多个地址 @JUri(array={"/home","/action"})
34 | @JUri("/action")
35 | public class TestAction extends Action {
36 | Context context = MyApplication.getContext();
37 |
38 | @Override
39 | public void run(Map queryMap) {
40 | super.run(queryMap);
41 | //Uri 里面的参数通过Map传递进来
42 | String result = (String) queryMap.get("param");
43 | Toast.makeText(context, "Test Action: " + result, Toast.LENGTH_SHORT).show();
44 | }
45 | }
46 |
47 | ```
48 | - Method Call
49 |
50 | ```java
51 | // 尽可能早,推荐在Application中初始化,初始化路由表
52 | Router.getInstance().init(mApplication);
53 |
54 |
55 | // 方式一
56 | String uri = "meiyou:///home";
57 | Router.getInstance().run(uri);
58 |
59 | // 方式二
60 | Router.getInstance().run(context, Uri.parse("meiyou:///second?uid=233"));
61 |
62 | // 方式三
63 | // 如果AndroidManifest.xml注册了RouterCenterActivity,也可以通过下面的方式打开,如果是APP内部使用,不建议使用。
64 | // startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("meiyou:///home?uid=233")));
65 | ```
66 |
67 | ### Open From outSide Web Brower Or other APP
68 |
69 | just register RouterCenterActivity in AndroidManifest.xml,
70 | //即可变成经典的Uri打开,可以支持外部浏览器、其它APP打开内部的Activity。
71 | ```xml
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | ```
81 | ```java
82 | // Java代码调用
83 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("meiyou:///second?uid=233&name=Wiki")));
84 |
85 | // HTML方式,系统浏览器(不支持微信,微信内部开网页会禁止所有的Scheme)
86 | 打开JoyrunApp的SecondActivity
87 |
88 | ```
89 | ### Support Interceptor
90 |
91 | 通过前置拦截器可以对URL进行拦截,可以通过拦截器对URL进行修改,也可以拦截URL,不让路由器打开。
92 | ```java
93 | Router.addInterceptor(new UriInterceptor() {
94 | public String beforeExecute(InterceptorData data) {
95 | //return url.replace("test://www.XXX.com/","test://");
96 | return data;
97 | }
98 | });
99 | ```
100 | ### Support set Scheme
101 | ```java
102 | Router.addScheme("meiyou");
103 | ```
104 |
105 | ### 原理图
106 | 
107 |
108 |
109 | 
110 |
111 |
112 | ## Contact
113 | QQ群:547612870
114 |
115 | ### License
116 |
117 | Copyright 2017 zhengxiaobin;
118 |
119 | Licensed under the Apache License, Version 2.0 (the "License");
120 | you may not use this file except in compliance with the License.
121 | You may obtain a copy of the License at
122 |
123 | http://www.apache.org/licenses/LICENSE-2.0
124 |
125 | Unless required by applicable law or agreed to in writing, software
126 | distributed under the License is distributed on an "AS IS" BASIS,
127 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128 | See the License for the specific language governing permissions and
129 | limitations under the License.
130 |
131 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/BlankFragment.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.BaseAdapter;
11 | import android.widget.Button;
12 | import android.widget.ListView;
13 |
14 | import com.jet.jet.annotation.JFindView;
15 | import com.jet.jet.annotation.JFindViewOnClick;
16 | import com.jet.jet.process.Jet;
17 | import com.jet.router.Router;
18 |
19 | /**
20 | * BLank Fragment
21 | *
22 | * @author zhengxiaobin
23 | * @since 17/5/25 上午9:45
24 | */
25 | public class BlankFragment extends Fragment implements View.OnClickListener {
26 | // TODO: Rename parameter arguments, choose names that match
27 | // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
28 | private static final String ARG_PARAM1 = "param1";
29 | private static final String ARG_PARAM2 = "param2";
30 |
31 | private Context context;
32 |
33 | @JFindView(R.id.btn_findView)
34 | Button btn_findView;
35 |
36 | @JFindViewOnClick(R.id.btn_findview_onclick)
37 | Button btn_findview_onclick;
38 |
39 | @JFindView(R.id.listview)
40 | ListView listView;
41 |
42 | private String mParam1;
43 | private String mParam2;
44 |
45 | public BlankFragment() {
46 | }
47 |
48 | public static BlankFragment newInstance(Activity activity) {
49 | BlankFragment fragment = new BlankFragment();
50 | Bundle args = new Bundle();
51 | String param1 = "Hello ";
52 | String param2 = "world";
53 | args.putString(ARG_PARAM1, param1);
54 | args.putString(ARG_PARAM2, param2);
55 | fragment.setArguments(args);
56 | return fragment;
57 | }
58 |
59 | @Override
60 | public void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 | if (getArguments() != null) {
63 | mParam1 = getArguments().getString(ARG_PARAM1);
64 | mParam2 = getArguments().getString(ARG_PARAM2);
65 | }
66 | context = this.getActivity();
67 | }
68 |
69 | @Override
70 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
71 | Bundle savedInstanceState) {
72 | View view = View.inflate(context, R.layout.fragment_blank, null);
73 | // View viewById = view.findViewById(R.id.btn_findView);
74 | Jet.bind(this, view);
75 |
76 | setListView();
77 | return view;
78 | }
79 |
80 | private void setListView() {
81 | MyAdapter myAdapter = new MyAdapter();
82 | listView.setAdapter(myAdapter);
83 | listView.setVisibility(View.GONE);
84 | }
85 |
86 | @Override
87 | public void onClick(View v) {
88 | String uri = "";
89 | Router route = Router.getInstance();
90 | int id = v.getId();
91 | switch (id) {
92 | case R.id.btn_findView:
93 | uri = "meiyou:///home";
94 | route.run(uri);
95 | break;
96 | case R.id.btn_findview_onclick:
97 | uri = "meiyou:///home/user";
98 | route.run(uri);
99 | break;
100 | default:
101 | break;
102 | }
103 | }
104 |
105 | private class MyAdapter extends BaseAdapter {
106 |
107 | @Override
108 | public int getCount() {
109 | return 30;
110 | }
111 |
112 | @Override
113 | public Object getItem(int position) {
114 | return null;
115 | }
116 |
117 | @Override
118 | public long getItemId(int position) {
119 | return 0;
120 | }
121 |
122 | @Override
123 | public View getView(int position, View convertView, ViewGroup parent) {
124 | ViewHolder viewHolder;
125 | if (convertView == null) {
126 | convertView = View.inflate(context, R.layout.item_fragment_blank, null);
127 | viewHolder = new ViewHolder(convertView);
128 | // viewHolder.btn_findView = (Button) convertView.findViewById(R.id.btn_findView);
129 | // viewHolder.btn_findview_onclick = (Button) convertView.findViewById(R.id.btn_findview_onclick);
130 | convertView.setTag(viewHolder);
131 | } else {
132 | viewHolder = (ViewHolder) convertView.getTag();
133 | }
134 |
135 | viewHolder.btn_findView.setText("Hello, New set");
136 |
137 | return convertView;
138 | }
139 | }
140 |
141 | class ViewHolder {
142 | @JFindView(R.id.btn_findView)
143 | Button btn_findView;
144 |
145 | @JFindView(R.id.btn_findview_onclick)
146 | Button btn_findview_onclick;
147 |
148 |
149 | public ViewHolder(View view) {
150 | Jet.bind(this, view);
151 | }
152 |
153 | }
154 |
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seeker/tony/myapplication/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.seeker.tony.myapplication;
2 |
3 | import android.net.Uri;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.Toolbar;
7 | import android.util.Log;
8 | import android.view.Menu;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.widget.Button;
12 |
13 | import com.jet.jet.annotation.JFindViewOnClick;
14 | import com.jet.jet.process.Jet;
15 | import com.jet.router.Router;
16 | import com.seeker.tony.myapplication.common.Mock;
17 |
18 | import java.util.HashMap;
19 | import java.util.Map;
20 |
21 | //@JUri("")
22 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
23 | private static final String TAG = "MainActivity";
24 |
25 | @JFindViewOnClick(R.id.btn_findView)
26 | Button btnHello;
27 |
28 | @JFindViewOnClick(R.id.btn_findview_onclick)
29 | Button btnWorld;
30 |
31 | String temp = "";
32 |
33 | @JFindViewOnClick(R.id.btn_implement)
34 | Button btn_implement;
35 |
36 | @JFindViewOnClick(R.id.btn_log)
37 | Button btn_log;
38 | @JFindViewOnClick(R.id.btn_init)
39 | Button btn_init;
40 |
41 | String uri = "";
42 | Router route = Router.getInstance();
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_main);
48 | Jet.bind(this);
49 |
50 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
51 | setSupportActionBar(toolbar);
52 |
53 | }
54 |
55 |
56 | @Override
57 | public boolean onCreateOptionsMenu(Menu menu) {
58 | // Inflate the menu; this adds items to the action bar if it is present.
59 | getMenuInflater().inflate(R.menu.menu_main, menu);
60 | return true;
61 | }
62 |
63 | @Override
64 | public boolean onOptionsItemSelected(MenuItem item) {
65 | // Handle action bar item clicks here. The action bar will
66 | // automatically handle clicks on the Home/Up button, so long
67 | // as you specify a parent activity in AndroidManifest.xml.
68 | int id = item.getItemId();
69 |
70 | //noinspection SimplifiableIfStatement
71 | if (id == R.id.action_settings) {
72 | return true;
73 | }
74 |
75 | return super.onOptionsItemSelected(item);
76 | }
77 |
78 | public void onClick(View view) {
79 | int id = view.getId();
80 | route = Router.getInstance();
81 | switch (id) {
82 | case R.id.btn_findView:
83 | uri = "meiyou:///home?param=\"hello\"";
84 | route.run(uri);
85 | break;
86 | case R.id.btn_findview_onclick:
87 | uri = "meiyou:///action?param=1&test=true";
88 | route.run(uri);
89 | break;
90 | case R.id.btn_implement:
91 | uri = "meiyou:///moduleb/action";
92 | route.run(uri);
93 | break;
94 | case R.id.btn_log:
95 | uri = "meiyou:///moduleb";
96 | route.run(uri);
97 | // testLog(10);
98 | // testAOP();
99 | break;
100 | case R.id.btn_init:
101 | temp();
102 | break;
103 | }
104 |
105 | }
106 |
107 | private void temp() {
108 | // try {
109 | // Router.getInstance().registerAll();
110 | // } catch (Exception e) {
111 | // e.printStackTrace();
112 | // }
113 | // testUrl();
114 | createUri();
115 | }
116 |
117 | // @Test("")
118 | private void test() {
119 | // HashMap map = RouterTable.map;
120 | // Log.w(TAG, "test: " + map.size());
121 | // URI uri = new URI("");
122 | // Uri.parse()
123 | // HelloChina helloChina = new HelloChina();
124 |
125 | }
126 |
127 | public void testUrl() {
128 | HashMap sampleMap = Mock.getSampleMap();
129 | // LinkedHashMap linkedHashMap=new LinkedHashMap<>(sampleMap);
130 | Uri uri = Uri.parse("meiyou:///home");
131 | Uri.Builder builder = uri.buildUpon();
132 | for (Map.Entry entry : sampleMap.entrySet()) {
133 | String key = entry.getKey();
134 | Object value = entry.getValue();
135 | builder.appendQueryParameter(key, value.toString());
136 | }
137 | uri = builder.build();
138 | String s = uri.toString();
139 | Log.e(TAG, "testUrl: " + s);
140 |
141 | }
142 |
143 | public void createUri() {
144 | final Uri.Builder builder = new Uri.Builder();
145 | builder.scheme("meiyou");
146 | builder.authority("lingan.com");
147 | builder.path("/virtualpath/settings.xml");
148 | builder.appendQueryParameter("key", "value");
149 | builder.appendQueryParameter("data", "" + 1);
150 | builder.appendQueryParameter("chinese", "hell dodod");
151 | builder.appendQueryParameter("chinese2", "中文");
152 |
153 | Uri uri = builder.build();
154 | String s = uri.toString();
155 | Log.e(TAG, "testUrl: " + s);
156 |
157 | // URL url = new URL(uri.toString());
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Jet RouterKit
2 |
3 | [  ](https://bintray.com/gybin02/maven/router/_latestVersion)
4 | [](http://shang.qq.com/wpa/qunwpa?idkey=f474c19f6b6b7d67e91685511207bcd326a38f50818d8e4569e52a167df85009)
5 | [](https://www.apache.org/licenses/LICENSE-2.0)
6 |
7 |
8 |
9 | ~~路由库~~;Android平台对页面、服务的路由框架。自动化且易用。
10 | 
11 | - 基于**APT**技术(注解-编译时生成代码,不反射,无性能损耗),通过注解方式来实现**URL**打开Activity功能或 执行特定动作
12 | - 并支持在WebView和外部浏览器使用,支持路由表维护,降级访问等;
13 | - 使用[**Jet**](https://github.com/gybin02/Jet)技术支持Bundle、Intent,Uri参数自动注入页面并转换参数类型。
14 | - [English Version](/Readme_en.md)
15 |
16 | ### 方案对比
17 | |实现功能|**RouterKit**|Airbnb 的**DeepLinkDispatch**|阿里 **ARouter**|天猫 统跳协议|**ActivityRouter**Github上Star最多 |
18 | |:------:|:--------:| :----------------------:| :-------------:| :----------:|-------------:|
19 | |路由注册 |注解式APT自动注册 |每个module都要手动注册 |每个module的路由表都要APT类查找 |AndroidManiFest配置 |每个module都要手动注册|
20 | |路由查找 |路由表| 路由表 |路由表 |系统Intent| 路由表
21 | |路由分发 |Activity转发| Activity转发| Activity转发| Activity转发 |Activity转发|
22 | |动态替换 |主线程| 不支持 |线程等待 |不支持| 不支持|
23 | |动态拦截 |主线程| 不支持| 线程等待 |不支持 |主线程|
24 | |安全拦截 |主线程| 不支持 |线程等待 |不支持 |主线程|
25 | |方法调用 |手动拼装 |手动拼装 |手动拼装 |手动拼装 |手动拼装|
26 | |参数获取 |JET 依赖自动注入,支持所有类型| 参数定义在path,不利于多人协作| Apt依赖注入,但是要手动调用get方法| 手动调用 |手动调用|
27 | |结果返回 |onActivityResult| onActivityResult |onActivityResult |onActivityResult |onActivityResult|
28 | |支持多Module |支持 |不支持 |支持 |不支持| 支持|
29 |
30 |
31 | 整体类似 阿里开源的[**ARoute**](https://github.com/alibaba/ARouter) 功能;移除分组概念,强化多Module编译和自动注册路由表,会更通用。
32 |
33 | ### 特色:
34 | 1. 支持注解方式,APT编译器自动注册Activity 和**Action**(类似Struts里面的Action)
35 | 2. 支持自动注入Intent,Bundle、Uri里的参数到页面使用[**Jet**](http://git.meiyou.im/Android/jet)
36 | 3. 支持外部浏览器打开。
37 | 4. 支持HTTP协议。
38 | 5. 支持多个Module。
39 | 6. 支持Uri 跳转和 Action 执行;
40 | 7. 路由表自动初始化,也可以手动再维护;
41 | 8. 支持服务端下发路由配置,简单支持页面降级功能;
42 |
43 | ### 功能:
44 | - Apt实现自动路由注册,支持多Module
45 | - 路由表维护
46 | - Activity转发 和 Action转发(支持URI页面跳转和方法调用)
47 |
48 | ### 原理图
49 | 
50 |
51 |
52 | 
53 |
54 | ### 典型应用
55 | 1. 从外部URL映射到内部页面,以及参数传递与解析
56 | 2. 跨模块页面跳转,模块间解耦
57 | 3. 拦截跳转过程,处理登陆、埋点等逻辑
58 | 4. 跨模块API调用,通过控制反转来做组件解耦
59 |
60 | ### 使用范例
61 | - 声明1: 页面跳转
62 |
63 | ```java
64 | @JUri("/home")
65 | public class IntentActivity extends AppCompatActivity {
66 | // Uri 的参数通过 Intent传递进来, 推荐使用Jet自动读取;
67 | .....
68 | //
69 | }
70 | ```
71 | - or 声明2: 服务功能调用:
72 | ```java
73 | //支持,多个地址 @JUri(array={"/home","/action"})
74 | @JUri("/action")
75 | public class TestAction extends Action {
76 | Context context = MyApplication.getContext();
77 |
78 | @Override
79 | public void run(Map queryMap) {
80 | super.run(queryMap);
81 | //Uri 里面的参数通过Map传递进来
82 | String result = (String) queryMap.get("param");
83 | Toast.makeText(context, "Test Action: " + result, Toast.LENGTH_SHORT).show();
84 | }
85 | }
86 |
87 | ```
88 | - 方法调用
89 |
90 | ```java
91 | // 尽可能早,推荐在Application中初始化,初始化路由表
92 | Router.getInstance().init(mApplication);
93 |
94 |
95 | // 方式一
96 | String uri = "meiyou:///home";
97 | Router.getInstance().run(uri);
98 |
99 | // 方式二
100 | Router.getInstance().run(context, Uri.parse("meiyou:///second?uid=233"));
101 |
102 | // 方式三
103 | // 如果AndroidManifest.xml注册了RouterCenterActivity,也可以通过下面的方式打开,如果是APP内部使用,不建议使用。
104 | // startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("meiyou:///home?uid=233")));
105 | ```
106 |
107 | ### 从外部浏览器、其它APP打开
108 |
109 | 只要在AndroidManifest.xml注册了RouterCenterActivity,即可变成经典的Uri打开,可以支持外部浏览器、其它APP打开内部的Activity。
110 | ```xml
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | ```
120 | ```java
121 | // Java代码调用
122 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("meiyou:///second?uid=233&name=Wiki")));
123 |
124 | // HTML方式,系统浏览器(不支持微信,微信内部开网页会禁止所有的Scheme)
125 | 打开JoyrunApp的SecondActivity
126 |
127 | ```
128 |
129 | ### 支持拦截器,典型应用就是:某些URI需要授权才能访问
130 |
131 | 通过前置拦截器可以对URL进行拦截,可以通过拦截器对URL进行修改,也可以拦截URL,不让路由器打开。
132 | ```java
133 | Router.addInterceptor(new UriInterceptor() {
134 | public String beforeExecute(InterceptorData data) {
135 | //return url.replace("test://www.XXX.com/","test://");
136 | return data;
137 | }
138 | });
139 | ```
140 | ### 支持 设置Scheme ,只有允许的Scheme才有效;才允许路由分发
141 | ```java
142 | Router.addScheme("meiyou");
143 | ```
144 |
145 | ### 集成
146 | 在gradle文件配置:
147 | ```groove
148 | //内部版本:0.0.1-SNAPSHOT
149 | compile "com.jet.framework:router:1.0.0"
150 | ```
151 |
152 | ### 混淆
153 | ### 常见问题
154 | * [Intent参数自动注入IOC - Jet](http://git.meiyou.im/Android/jet)
155 | * 参考[Android 组件化 —— 路由设计最佳实践](http://www.jianshu.com/p/8a3eeeaf01e8)
156 | * [开源最佳实践:Android平台页面路由框架ARouter](https://yq.aliyun.com/articles/71687?spm=5176.100240.searchblog.7.8os9Go)
157 | * [iOS 组件化 —— 路由设计思路分析](http://www.jianshu.com/p/76da56b3bd55)
158 | * [前端组件化]Vue.js And React 组件化(https://halfrost.com/vue_ios_modularization/)
159 | * [LiteRouter模仿retrofit,各个业务分根据需求约定好接口,就像一份接口文档一样](http://www.jianshu.com/p/79e9a54e85b2)
160 | * [routable-android 模式匹配方式的路由](https://github.com/clayallsopp/routable-android)
161 | * [NodeJs-Express 路由框架](http://www.expressjs.com.cn/guide/routing.html)
162 |
163 | ### TODO
164 | - JUri 支持数组数据(fixed)
165 | - Module传递依赖解决 (fixed)
166 | - 自定义 注解实现,可以再自定义额外的路由表,实现自定义的注解的路由,Door接口的优化
167 | - Gradle Plugin实现,APT 主工程 需要配置编译过程问题
168 | - 拦截器排序,优先级 priority
169 | - 路由匹配规则Matcher功能升级, Pattern 模式匹配
170 | - 调用方式接口化,like: retrofit;
171 | - 路由结果回调? isNeed?
172 | - Kotlin版本实现
173 | - 路由表初始化异步线程化
174 | - 安全性
175 | - like Express, 拦截器,中间件化?
176 |
177 |
178 | ### 交流群:
179 | QQ群:547612870
180 |
181 | ### License
182 |
183 | Copyright 2017 gybin02@163.com
184 |
185 | Licensed under the Apache License, Version 2.0 (the "License");
186 | you may not use this file except in compliance with the License.
187 | You may obtain a copy of the License at
188 |
189 | http://www.apache.org/licenses/LICENSE-2.0
190 |
191 | Unless required by applicable law or agreed to in writing, software
192 | distributed under the License is distributed on an "AS IS" BASIS,
193 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
194 | See the License for the specific language governing permissions and
195 | limitations under the License.
196 |
197 |
--------------------------------------------------------------------------------
/jet_compiler/src/main/java/com/meiyou/compiler/RouterProcessor.java:
--------------------------------------------------------------------------------
1 | package com.jet.compiler;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.google.gson.Gson;
5 | import com.jet.annotation.JUri;
6 | import com.squareup.javapoet.CodeBlock;
7 | import com.squareup.javapoet.FieldSpec;
8 | import com.squareup.javapoet.JavaFile;
9 | import com.squareup.javapoet.TypeSpec;
10 |
11 | import java.io.IOException;
12 | import java.io.Writer;
13 | import java.util.ArrayList;
14 | import java.util.Arrays;
15 | import java.util.HashMap;
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.annotation.processing.SupportedAnnotationTypes;
25 | import javax.annotation.processing.SupportedSourceVersion;
26 | import javax.lang.model.SourceVersion;
27 | import javax.lang.model.element.Element;
28 | import javax.lang.model.element.Modifier;
29 | import javax.lang.model.element.TypeElement;
30 | import javax.lang.model.util.Types;
31 | import javax.tools.FileObject;
32 | import javax.tools.StandardLocation;
33 |
34 | /**
35 | * 直接Build,由于Gradle的配置,代码不变,APT可能不执行,要执行clean + build;
36 | *
37 | * @author zhengxiaobin
38 | * @since 17/7/13
39 | */
40 | @AutoService(Processor.class)
41 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
42 | @SupportedAnnotationTypes({"com.jet.annotation.JUri"})
43 | public class RouterProcessor extends AbstractProcessor {
44 | //测试保存在META-INF里面
45 | static final String METADATA_PATH = "META-INF/spring-configuration-metadata.json";
46 | public static final String ASSET_JSON = "assets/router/module.json";
47 |
48 | public static final String ASSET_PATH = "assets/router/";
49 | public static final String FILE_SUFFIX = ".json";
50 |
51 | public static final String PkgName = "com.jet.router.data";
52 | public static final String ClassName = "RouterTable";
53 |
54 | /**
55 | * APT 默认目录
56 | */
57 | Filer filer;
58 | private Types types;
59 |
60 | @Override
61 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
62 | super.init(processingEnvironment);
63 | filer = processingEnvironment.getFiler();
64 | types = processingEnvironment.getTypeUtils();
65 |
66 | }
67 |
68 | /**
69 | * @param annotations 所有支持的Annotation
70 | * @param roundEnvironment 当前环境
71 | * @return
72 | */
73 | @Override
74 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
75 | try {
76 | //APT 会执行多轮,需要过滤掉
77 | if (annotations == null || annotations.isEmpty()) {
78 | System.out.println(">>> annotations is null... <<<");
79 | return true;
80 | }
81 |
82 | HashMap map = new HashMap<>();
83 | for (TypeElement annotation : annotations) {
84 |
85 | Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(annotation);
86 | for (Element element : elements) {
87 | JUri uri = element.getAnnotation(JUri.class);
88 | TypeElement typeElement = (TypeElement) element;
89 |
90 | String value = uri.value();
91 | String[] array = uri.array();
92 | ArrayList list = new ArrayList<>();
93 | list.add(value);
94 | list.addAll(Arrays.asList(array));
95 | String clazzName = typeElement.getQualifiedName().toString();
96 | for (String key : list) {
97 | //避免Key是空的情况
98 | if (key.length() == 0) {
99 | break;
100 | }
101 | map.put(key, clazzName);
102 | }
103 |
104 | }
105 | }
106 | //生成Java代码
107 | createJava(map);
108 | } catch (Exception e) {
109 | e.printStackTrace();
110 | }
111 | return true;
112 | }
113 |
114 | /**
115 | * javapoet 🔚介绍
116 | *
117 | * http://www.jianshu.com/p/95f12f72f69a
118 | * http://www.jianshu.com/p/76e9e3a8ec0f
119 | * http://blog.csdn.net/crazy1235/article/details/51876192
120 | * http://blog.csdn.net/qq_26376637/article/details/52374063
121 | *
122 | * @param map
123 | * @throws Exception
124 | */
125 | private void createJava(HashMap map) throws Exception {
126 | String content = new Gson().toJson(map);
127 | //打印出内容
128 | System.out.println(">>> content:... <<< " + content);
129 | writeFile(content);
130 | }
131 |
132 | /**
133 | * 生成JSON文件保存到Assets里面
134 | *
135 | * @param content
136 | * @throws Exception
137 | */
138 | private void writeFile(String content) throws Exception {
139 | FileObject fileObject = createResource();
140 | // FileObject fileObject = createSourcePath();
141 |
142 | Writer writer = fileObject.openWriter();
143 | writer.write(content);
144 | writer.close();
145 | // System.out.println("Done");
146 | }
147 |
148 | /**
149 | * 获取Resource地址
150 | *
151 | * @return
152 | * @throws IOException
153 | */
154 | private FileObject createResource() throws IOException {
155 | String string = types.toString();
156 | //使用HashCode作为文件名字,避免冲突
157 | int hashCode = types.hashCode();
158 | // System.out.println("typename: " + string + " hashCode: " + hashCode);
159 |
160 | String path = ASSET_PATH + hashCode + FILE_SUFFIX;
161 | // String path = ASSET_JSON;
162 | // String path =METADATA_PATH;
163 | FileObject resource = filer
164 | .createResource(StandardLocation.CLASS_OUTPUT, "", path);
165 | return resource;
166 | }
167 |
168 | /**
169 | * 生成Java 源代码;
170 | *
171 | * @param map
172 | */
173 | @Deprecated
174 | private void createSource(HashMap map) throws Exception {
175 | CodeBlock.Builder builder = CodeBlock.builder();
176 | for (Map.Entry entry : map.entrySet()) {
177 | String key = entry.getKey();
178 | String clazz = entry.getValue();
179 |
180 | // builder.add("$T.createBean($S, $S);", RouterBean.class, key, clazz);
181 | }
182 | CodeBlock codeBlock = builder.build();
183 |
184 |
185 | FieldSpec field = FieldSpec.builder(HashMap.class, "map", Modifier.PUBLIC, Modifier.STATIC)
186 | .initializer(CodeBlock.of("new HashMap()"))
187 | .build();
188 |
189 | TypeSpec typeSpec = TypeSpec.classBuilder(ClassName + "$$1")
190 | .addModifiers(Modifier.PUBLIC)
191 | .addStaticBlock(codeBlock)
192 | .addField(field)
193 | .build();
194 | JavaFile javaFile = JavaFile.builder(PkgName, typeSpec).build();
195 | //打印
196 | // javaFile.writeTo(System.out);
197 | // String content = javaFile.toString();
198 | javaFile.writeTo(filer);
199 | }
200 |
201 | /**
202 | * 获取源代码路径
203 | *
204 | * @return
205 | * @throws IOException
206 | */
207 | @Deprecated
208 | private FileObject createSourcePath() throws IOException {
209 | // String string = types.toString();
210 | // int hashCode = types.hashCode();
211 | // System.out.println("typename: "+string+" hashCode: " + hashCode);
212 |
213 | FileObject resource = filer
214 | .createSourceFile("com.test.go." + "RouterTable" + "$$1");
215 | return resource;
216 | }
217 |
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/Router.java:
--------------------------------------------------------------------------------
1 | package com.jet.router;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.res.AssetManager;
6 | import android.net.Uri;
7 | import android.text.TextUtils;
8 | import android.util.Log;
9 |
10 | import com.google.gson.Gson;
11 | import com.jet.router.action.Action;
12 | import com.jet.router.intercept.InterceptorData;
13 | import com.jet.router.intercept.UriInterceptor;
14 | import com.jet.router.meiyou.UriMeiyou;
15 | import com.jet.router.model.RouterBean;
16 |
17 | import java.io.IOException;
18 | import java.io.InputStream;
19 | import java.lang.reflect.Method;
20 | import java.net.URLDecoder;
21 | import java.util.ArrayList;
22 | import java.util.Arrays;
23 | import java.util.Enumeration;
24 | import java.util.HashMap;
25 | import java.util.LinkedHashMap;
26 | import java.util.Map;
27 |
28 | import dalvik.system.DexFile;
29 |
30 | /**
31 | * 实现路由功能
32 | * 需要调用 init初始化;
33 | * run(String uri),执行路由
34 | * 可以新增拦截器;
35 | * 可以新增Scheme判断,是否有效URI;
36 | *
37 | * 路由表,要不要加密?
38 | *
39 | * @author zhengxiaobin
40 | * @since 17/7/13
41 | */
42 |
43 | public class Router {
44 | private static final String TAG = "Router";
45 | private static Router instance;
46 |
47 | private Context context;
48 | /**
49 | * 路由表
50 | */
51 | private HashMap routerTable = new HashMap<>();
52 |
53 | /**
54 | * 拦截器列表
55 | */
56 | private ArrayList interceptorList = new ArrayList<>();
57 | private ArrayList schemeList = new ArrayList<>();
58 |
59 | public static Router getInstance() {
60 | // FIXME: 17/7/21 测试初始
61 | if (instance == null) {
62 | instance = new Router();
63 | }
64 | return instance;
65 | }
66 |
67 | public void init(Context context) {
68 | try {
69 | this.context = context.getApplicationContext();
70 | registerAll();
71 | Log.d(TAG, "routerTable: size = " + routerTable.size());
72 | } catch (Exception e1) {
73 | e1.printStackTrace();
74 | }
75 | }
76 |
77 | /**
78 | * 读取APT生成代码:
79 | * 1. 直接先编译代码,在读取类
80 | * 2. 反射读取类;
81 | * 3. APT数据保存到Asset里面,可以是JSon这样的,然后读取;
82 | */
83 | private Router() {
84 | }
85 |
86 | /**
87 | * Main Method, 要不要改成静态的?
88 | * eg: "meiyou:///home/action"
89 | *
90 | * @param uri
91 | */
92 | public void run(String uri) {
93 | try {
94 | if (context == null) {
95 | Log.e(TAG, "请先初始化JetRoute:init()");
96 | return;
97 | }
98 |
99 | Uri uriTemp = Uri.parse(uri);
100 | run(uriTemp);
101 | } catch (Exception e) {
102 | e.printStackTrace();
103 | }
104 | }
105 |
106 | /**
107 | * Run;
108 | * @param uriMeiyou
109 | * @param param
110 | */
111 | public void run(UriMeiyou uriMeiyou, HashMap param) {
112 | String path = uriMeiyou.getPath();
113 | run(path, param);
114 | }
115 |
116 | /**
117 | * 跳转
118 | *
119 | * @param uri 具体的URI: "meiyou:///home"
120 | * @param param: Object支持基础数据类型,如果是对象,推荐转成String;
121 | */
122 | public void run(String uri, HashMap param) {
123 | Uri uriTemp = Uri.parse(uri);
124 | Uri.Builder builder = uriTemp.buildUpon();
125 | for (Map.Entry entry : param.entrySet()) {
126 | String key = entry.getKey();
127 | Object value = entry.getValue();
128 | builder.appendQueryParameter(key, value.toString());
129 | }
130 | Uri uriNew = builder.build();
131 | run(uriNew);
132 | }
133 |
134 |
135 | public void run(Uri uri) {
136 | try {
137 | if (context == null) {
138 | Log.e(TAG, "请先初始化JetRoute:init()");
139 | return;
140 | }
141 |
142 | if (!checkUri(uri)) {
143 | return;
144 | }
145 | String path = uri.getPath();
146 |
147 | if (!routerTable.containsKey(path)) {
148 | Log.e(TAG, "未找到该路由:" + path);
149 | return;
150 | }
151 | InterceptorData data = doIntercept(uri);
152 | doRun(data.mUri);
153 |
154 | } catch (Exception e) {
155 | e.printStackTrace();
156 | }
157 | }
158 |
159 |
160 |
161 | /**
162 | * 新增拦截器
163 | *
164 | * @param interceptor
165 | */
166 | public void addInterceptor(UriInterceptor interceptor) {
167 | interceptorList.add(interceptor);
168 | }
169 |
170 | /**
171 | * 新增支持的Scheme;支持多Scheme
172 | * 不设置:全部允许;推荐设置;
173 | * eg: "meiyou"
174 | *
175 | * @param scheme
176 | */
177 | public void addScheme(String... scheme) {
178 | schemeList.addAll(Arrays.asList(scheme));
179 | }
180 |
181 | /************** private Part ********/
182 |
183 | /**
184 | * 前置拦截
185 | *
186 | * @param uriTemp
187 | * @return
188 | */
189 | private InterceptorData doIntercept(Uri uriTemp) {
190 | InterceptorData data = new InterceptorData();
191 | data.mUri = uriTemp;
192 | for (UriInterceptor interceptor : interceptorList) {
193 | data = interceptor.beforeExecute(data);
194 | }
195 | return data;
196 | }
197 |
198 | /**
199 | * 处理运行Uri
200 | *
201 | * @param uri
202 | * @throws Exception
203 | */
204 | private void doRun(Uri uri) throws Exception {
205 | String path = uri.getPath();
206 | String target = routerTable.get(path);
207 |
208 | int type = RouterBean.getType(target);
209 | Map queryMap = getQuery(uri);
210 | //页面跳转
211 | if (type == RouterBean.TYPE_UI) {
212 | Class clazz = Class.forName(target);
213 | Intent intent = new Intent(context, clazz);
214 | fillIntent(intent, queryMap);
215 |
216 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
217 | context.startActivity(intent);
218 | } else {
219 | Class> clazz = Class.forName(target);
220 | Action function = (Action) clazz.newInstance();
221 | //是否要使用Intent传递数据?
222 | // Intent intent = new Intent();
223 | // fillIntent(intent, queryMap);
224 | function.run(queryMap);
225 | }
226 | }
227 |
228 | /**
229 | * Check uri 是否有效
230 | *
231 | * String mHost = uri.getHost();
232 | * String mScheme = uri.getScheme();
233 | * String mPath = uri.getPath();
234 | * String mQuery = uri.getQuery();
235 | * [scheme:][//authority][path][?query][#fragment]
236 | * URL:http://developer.android.com/referencejava/net/URL.html?s=a#getRef()
237 | * 那么它的各个属性的值就为:
238 | * Authority是:developer.android.com
239 | * Host是:developer.android.com
240 | * Scheme是:HTTP
241 | * Port是:-1
242 | * File是/referencejava/net/ URL.html?s=a
243 | * Path是/referencejava/net/URL.html
244 | * Query是:s=a
245 | *
246 | * @param uri
247 | * @return true,有效,
248 | */
249 | private boolean checkUri(Uri uri) {
250 | String scheme = uri.getScheme();
251 | if (schemeList.size() == 0) {
252 | return true;
253 | } else {
254 | if (schemeList.contains(scheme)) {
255 | return true;
256 | }
257 | }
258 | return false;
259 |
260 | }
261 |
262 | // /**
263 | // * 获取URI path
264 | // *
265 | // * @param uri
266 | // * @return
267 | // */
268 | // private String getUriPath(String uri) {
269 | // return uri;
270 | // }
271 |
272 | // public Map getQuery(String uri) {
273 | // Map query = new LinkedHashMap<>();
274 | // return query;
275 | // }
276 |
277 |
278 | private static Map getQuery(Uri uri) {
279 | Map queryPairs = new LinkedHashMap<>();
280 | try {
281 | String query = uri.getQuery();
282 | if (TextUtils.isEmpty(query)) {
283 | return queryPairs;
284 | }
285 | String[] pairs = query.split("&");
286 | for (String pair : pairs) {
287 | int idx = pair.indexOf("=");
288 | String key = URLDecoder.decode(pair.substring(0, idx), "UTF-8");
289 | String value = pair.substring(idx + 1);
290 | //不使用Base64
291 | // value = base64UrlDecode(value);
292 | queryPairs.put(key, value);
293 | }
294 | } catch (Exception e) {
295 | e.printStackTrace();
296 | }
297 | return queryPairs;
298 | }
299 |
300 |
301 | /**
302 | * 填充Intent
303 | *
304 | * @param intent
305 | * @param queryMap
306 | */
307 | private void fillIntent(Intent intent, Map queryMap) {
308 | try {
309 | if (queryMap != null) {
310 | for (Map.Entry entry : queryMap.entrySet()) {
311 | String key = entry.getKey();
312 | String value = entry.getValue();
313 | intent.putExtra(key, value);
314 | }
315 | }
316 | } catch (Exception ex) {
317 | ex.printStackTrace();
318 | }
319 | }
320 |
321 |
322 | public void registerAll() throws Exception {
323 | AssetManager assetManager = context.getResources().getAssets();
324 | String root = "router";
325 | String[] list = assetManager.list(root);
326 | for (String path : list) {
327 | InputStream inputStream = assetManager.open(root + "/" + path);
328 | String s = InputStream2String(inputStream);
329 | Map map = new Gson().fromJson(s, Map.class);
330 | routerTable.putAll(map);
331 | // for (Map.Entry entry : map.entrySet()) {
332 | // String key = entry.getKey();
333 | // String value = entry.getValue();
334 | // RouterBean bean = new RouterBean(key, value);
335 | // }
336 | }
337 |
338 | }
339 |
340 | private static String InputStream2String(InputStream is) {
341 | String result = "";
342 | try {
343 | byte[] buffer = new byte[is.available()];
344 | is.read(buffer);//输出流
345 | result = new String(buffer, "utf-8");
346 | is.close();
347 | } catch (IOException e) {
348 | e.printStackTrace();
349 | }
350 | return result;
351 | }
352 |
353 | /**
354 | * 反射读取map 数据;
355 | */
356 | // @Deprecated
357 | // private void register() {
358 | // Class> table = Class.forName(RouterConstant.PkgName + "." + RouterConstant.ClassName);
359 | // Field field = table.getDeclaredField("map");
360 | // Object instance = table.newInstance();
361 | //
362 | // Object data = field.get(instance);
363 | // if (data instanceof HashMap) {
364 | // routerTable = (HashMap) data;
365 | // }
366 | // }
367 |
368 | /**
369 | * 使用反射读取,路由表
370 | *
371 | * @throws Exception
372 | */
373 | @Deprecated
374 | private void register() throws Exception {
375 | String[] classes = getClassesFromPackage(context, RouterConstant.PkgName);
376 | for (String clazzName : classes) {
377 | Class> clazz = Class.forName(clazzName);
378 | Method register = clazz.getMethod("register");
379 | register.invoke(null);
380 | }
381 | }
382 |
383 | /**
384 | * 获取包名下所有的类,小心性能
385 | *
386 | * @param context
387 | * @param packageName
388 | * @return
389 | */
390 | @Deprecated
391 | private static String[] getClassesFromPackage(Context context, String packageName) {
392 | ArrayList classes = new ArrayList();
393 | try {
394 | DexFile df = new DexFile(context.getPackageCodePath());
395 | Enumeration entries = df.entries();
396 | while (entries.hasMoreElements()) {
397 | String className = (String) entries.nextElement();
398 | if (className.contains(packageName)) {
399 | classes.add(className);
400 | }
401 | }
402 | } catch (IOException e) {
403 | e.printStackTrace();
404 | }
405 |
406 | return classes.toArray(new String[]{});
407 | }
408 |
409 |
410 | }
411 |
--------------------------------------------------------------------------------
/jet_router/src/main/java/com/meiyou/router/routable/RouterPatter.java:
--------------------------------------------------------------------------------
1 | /*
2 | Routable for Android
3 | Copyright (c) 2013 Turboprop, Inc.
4 | http://usepropeller.com
5 | Licensed under the MIT License.
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package com.jet.router.routable;
24 |
25 | import android.app.Activity;
26 | import android.content.Context;
27 | import android.content.Intent;
28 | import android.net.Uri;
29 | import android.os.Bundle;
30 |
31 | import java.net.URI;
32 | import java.util.HashMap;
33 | import java.util.Map;
34 | import java.util.Map.Entry;
35 |
36 | public class RouterPatter {
37 | private static final RouterPatter _router = new RouterPatter();
38 |
39 | /**
40 | * A globally accessible Router instance that will work for
41 | * most use cases.
42 | */
43 | public static RouterPatter sharedRouter() {
44 | return _router;
45 | }
46 |
47 |
48 |
49 |
50 |
51 |
52 | private static class RouterParams {
53 | public RouterOptions routerOptions;
54 | public Map openParams;
55 | }
56 |
57 | private final Map _routes = new HashMap();
58 | private String _rootUrl = null;
59 | private final Map _cachedRoutes = new HashMap();
60 | private Context _context;
61 |
62 | /**
63 | * Creates a new Router
64 | */
65 | public RouterPatter() {
66 |
67 | }
68 |
69 | /**
70 | * Creates a new Router
71 | *
72 | * @param context {@link Context} that all {@link Intent}s generated by the router will use
73 | */
74 | public RouterPatter(Context context) {
75 | this.setContext(context);
76 | }
77 |
78 | /**
79 | * @param context {@link Context} that all {@link Intent}s generated by the router will use
80 | */
81 | public void setContext(Context context) {
82 | this._context = context;
83 | }
84 |
85 | /**
86 | * @return The context for the router
87 | */
88 | public Context getContext() {
89 | return this._context;
90 | }
91 |
92 | /**
93 | * Map a URL to a callback
94 | *
95 | * @param format The URL being mapped; for example, "users/:id" or "groups/:id/topics/:topic_id"
96 | * @param callback {@link RouterCallback} instance which contains the code to execute when the URL is opened
97 | */
98 | public void map(String format, RouterCallback callback) {
99 | RouterOptions options = new RouterOptions();
100 | options.setCallback(callback);
101 | this.map(format, null, options);
102 | }
103 |
104 | /**
105 | * Map a URL to open an {@link Activity}
106 | *
107 | * @param format The URL being mapped; for example, "users/:id" or "groups/:id/topics/:topic_id"
108 | * @param klass The {@link Activity} class to be opened with the URL
109 | */
110 | public void map(String format, Class extends Activity> klass) {
111 | this.map(format, klass, null);
112 | }
113 |
114 | /**
115 | * Map a URL to open an {@link Activity}
116 | *
117 | * @param format The URL being mapped; for example, "users/:id" or "groups/:id/topics/:topic_id"
118 | * @param klass The {@link Activity} class to be opened with the URL
119 | * @param options The {@link RouterOptions} to be used for more granular and customized options for when the URL is opened
120 | */
121 | public void map(String format, Class extends Activity> klass, RouterOptions options) {
122 | if (options == null) {
123 | options = new RouterOptions();
124 | }
125 | options.setOpenClass(klass);
126 | this._routes.put(format, options);
127 | }
128 |
129 | /**
130 | * Set the root url; used when opening an activity or callback via RouterActivity
131 | *
132 | * @param rootUrl The URL format to use as the root
133 | */
134 | public void setRootUrl(String rootUrl) {
135 | this._rootUrl = rootUrl;
136 | }
137 |
138 | /**
139 | * @return The router's root URL, or null.
140 | */
141 | public String getRootUrl() {
142 | return this._rootUrl;
143 | }
144 |
145 | /**
146 | * Open a URL using the operating system's configuration (such as opening a link to Chrome or a video to YouTube)
147 | *
148 | * @param url The URL; for example, "http://www.youtube.com/watch?v=oHg5SJYRHA0"
149 | */
150 | public void openExternal(String url) {
151 | this.openExternal(url, this._context);
152 | }
153 |
154 | /**
155 | * Open a URL using the operating system's configuration (such as opening a link to Chrome or a video to YouTube)
156 | *
157 | * @param url The URL; for example, "http://www.youtube.com/watch?v=oHg5SJYRHA0"
158 | * @param context The context which is used in the generated {@link Intent}
159 | */
160 | public void openExternal(String url, Context context) {
161 | this.openExternal(url, null, context);
162 | }
163 |
164 | /**
165 | * Open a URL using the operating system's configuration (such as opening a link to Chrome or a video to YouTube)
166 | *
167 | * @param url The URL; for example, "http://www.youtube.com/watch?v=oHg5SJYRHA0"
168 | * @param extras The {@link Bundle} which contains the extras to be assigned to the generated {@link Intent}
169 | */
170 | public void openExternal(String url, Bundle extras) {
171 | this.openExternal(url, extras, this._context);
172 | }
173 |
174 | /**
175 | * Open a URL using the operating system's configuration (such as opening a link to Chrome or a video to YouTube)
176 | *
177 | * @param url The URL; for example, "http://www.youtube.com/watch?v=oHg5SJYRHA0"
178 | * @param extras The {@link Bundle} which contains the extras to be assigned to the generated {@link Intent}
179 | * @param context The context which is used in the generated {@link Intent}
180 | */
181 | public void openExternal(String url, Bundle extras, Context context) {
182 | if (context == null) {
183 | throw new ContextNotProvided(
184 | "You need to supply a context for Router "
185 | + this.toString());
186 | }
187 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
188 | this.addFlagsToIntent(intent, context);
189 | if (extras != null) {
190 | intent.putExtras(extras);
191 | }
192 | context.startActivity(intent);
193 | }
194 |
195 | /**
196 | * Open a map'd URL set using {@link #map(String, Class)} or {@link #map(String, RouterCallback)}
197 | *
198 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
199 | */
200 | public void open(String url) {
201 | this.open(url, this._context);
202 | }
203 |
204 | /**
205 | * Open a map'd URL set using {@link #map(String, Class)} or {@link #map(String, RouterCallback)}
206 | *
207 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
208 | * @param extras The {@link Bundle} which contains the extras to be assigned to the generated {@link Intent}
209 | */
210 | public void open(String url, Bundle extras) {
211 | this.open(url, extras, this._context);
212 | }
213 |
214 | /**
215 | * Open a map'd URL set using {@link #map(String, Class)} or {@link #map(String, RouterCallback)}
216 | *
217 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
218 | * @param context The context which is used in the generated {@link Intent}
219 | */
220 | public void open(String url, Context context) {
221 | this.open(url, null, context);
222 | }
223 |
224 | /**
225 | * Open a map'd URL set using {@link #map(String, Class)} or {@link #map(String, RouterCallback)}
226 | *
227 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
228 | * @param extras The {@link Bundle} which contains the extras to be assigned to the generated {@link Intent}
229 | * @param context The context which is used in the generated {@link Intent}
230 | */
231 | public void open(String url, Bundle extras, Context context) {
232 | if (context == null) {
233 | throw new ContextNotProvided(
234 | "You need to supply a context for Router "
235 | + this.toString());
236 | }
237 | RouterParams params = this.paramsForUrl(url);
238 | RouterOptions options = params.routerOptions;
239 | if (options.getCallback() != null) {
240 | RouteContext routeContext = new RouteContext(params.openParams, extras, context);
241 |
242 | options.getCallback().run(routeContext);
243 | return;
244 | }
245 |
246 | Intent intent = this.intentFor(context, params);
247 | if (intent == null) {
248 | // Means the options weren't opening a new activity
249 | return;
250 | }
251 | if (extras != null) {
252 | intent.putExtras(extras);
253 | }
254 | context.startActivity(intent);
255 | }
256 |
257 | /*
258 | * Allows Intents to be spawned regardless of what context they were opened with.
259 | */
260 | private void addFlagsToIntent(Intent intent, Context context) {
261 | if (context == this._context) {
262 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
263 | }
264 | }
265 |
266 | /**
267 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
268 | * @return The {@link Intent} for the url
269 | */
270 | public Intent intentFor(String url) {
271 | RouterParams params = this.paramsForUrl(url);
272 |
273 | return intentFor(params);
274 | }
275 |
276 | private Intent intentFor(RouterParams params) {
277 | RouterOptions options = params.routerOptions;
278 | Intent intent = new Intent();
279 | if (options.getDefaultParams() != null) {
280 | for (Entry entry : options.getDefaultParams().entrySet()) {
281 | intent.putExtra(entry.getKey(), entry.getValue());
282 | }
283 | }
284 | for (Entry entry : params.openParams.entrySet()) {
285 | intent.putExtra(entry.getKey(), entry.getValue());
286 | }
287 | return intent;
288 | }
289 |
290 | /**
291 | * @param url The URL to check
292 | * @return Whether or not the URL refers to an anonymous callback function
293 | */
294 | public boolean isCallbackUrl(String url) {
295 | RouterParams params = this.paramsForUrl(url);
296 | RouterOptions options = params.routerOptions;
297 | return options.getCallback() != null;
298 | }
299 |
300 | /**
301 | * @param context The context which is spawning the intent
302 | * @param url The URL; for example, "users/16" or "groups/5/topics/20"
303 | * @return The {@link Intent} for the url, with the correct {@link Activity} set, or null.
304 | */
305 | public Intent intentFor(Context context, String url) {
306 | RouterParams params = this.paramsForUrl(url);
307 |
308 | return intentFor(context, params);
309 | }
310 |
311 | private Intent intentFor(Context context, RouterParams params) {
312 | RouterOptions options = params.routerOptions;
313 | if (options.getCallback() != null) {
314 | return null;
315 | }
316 |
317 | Intent intent = intentFor(params);
318 | intent.setClass(context, options.getOpenClass());
319 | this.addFlagsToIntent(intent, context);
320 | return intent;
321 | }
322 |
323 | /*
324 | * Takes a url (i.e. "/users/16/hello") and breaks it into a {@link RouterParams} instance where
325 | * each of the parameters (like ":id") has been parsed.
326 | */
327 | private RouterParams paramsForUrl(String url) {
328 | final String cleanedUrl = cleanUrl(url);
329 |
330 | URI parsedUri = URI.create("http://tempuri.org/" + cleanedUrl);
331 |
332 | String urlPath = parsedUri.getPath().substring(1);
333 |
334 | if (this._cachedRoutes.get(cleanedUrl) != null) {
335 | return this._cachedRoutes.get(cleanedUrl);
336 | }
337 |
338 | String[] givenParts = urlPath.split("/");
339 |
340 | RouterParams routerParams = null;
341 | for (Entry entry : this._routes.entrySet()) {
342 | String routerUrl = cleanUrl(entry.getKey());
343 | RouterOptions routerOptions = entry.getValue();
344 | String[] routerParts = routerUrl.split("/");
345 |
346 | if (routerParts.length != givenParts.length) {
347 | continue;
348 | }
349 |
350 | Map givenParams = urlToParamsMap(givenParts, routerParts);
351 | if (givenParams == null) {
352 | continue;
353 | }
354 |
355 | routerParams = new RouterParams();
356 | routerParams.openParams = givenParams;
357 | routerParams.routerOptions = routerOptions;
358 | break;
359 | }
360 |
361 | if (routerParams == null) {
362 | throw new RouteNotFoundException("No route found for url " + url);
363 | }
364 |
365 | //// FIXME: 17/7/25 remove by zxb
366 | // List query = URLEncodedUtils.parse(parsedUri, "utf-8");
367 | //
368 | // for (NameValuePair pair : query) {
369 | // routerParams.openParams.put(pair.getName(), pair.getValue());
370 | // }
371 |
372 | this._cachedRoutes.put(cleanedUrl, routerParams);
373 | return routerParams;
374 | }
375 |
376 | /**
377 | * @param givenUrlSegments An array representing the URL path attempting to be opened (i.e. ["users", "42"])
378 | * @param routerUrlSegments An array representing a possible URL match for the router (i.e. ["users", ":id"])
379 | * @return A map of URL parameters if it's a match (i.e. {"id" => "42"}) or null if there is no match
380 | */
381 | private Map urlToParamsMap(String[] givenUrlSegments, String[] routerUrlSegments) {
382 | Map formatParams = new HashMap();
383 | for (int index = 0; index < routerUrlSegments.length; index++) {
384 | String routerPart = routerUrlSegments[index];
385 | String givenPart = givenUrlSegments[index];
386 |
387 | if (routerPart.charAt(0) == ':') {
388 | String key = routerPart.substring(1, routerPart.length());
389 | formatParams.put(key, givenPart);
390 | continue;
391 | }
392 |
393 | if (!routerPart.equals(givenPart)) {
394 | return null;
395 | }
396 | }
397 |
398 | return formatParams;
399 | }
400 |
401 | /**
402 | * Clean up url
403 | *
404 | * @param url
405 | * @return cleaned url
406 | */
407 | private String cleanUrl(String url) {
408 | if (url.startsWith("/")) {
409 | return url.substring(1, url.length());
410 | }
411 | return url;
412 | }
413 |
414 |
415 |
416 |
417 | }
--------------------------------------------------------------------------------