├── .gitignore ├── .travis.yml ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── javadoc.gradle ├── pics └── route.gif ├── router-anno ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── lzh │ └── nonview │ └── router │ └── anno │ ├── ActionLauncher.java │ ├── ActivityLauncher.java │ ├── RouteConfig.java │ ├── RouteExecutor.java │ ├── RouteInterceptors.java │ └── RouterRule.java ├── router-api ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── com │ │ └── lzh │ │ └── nonview │ │ └── router │ │ ├── module │ │ └── RemoteRule.aidl │ │ └── protocol │ │ └── IService.aidl │ └── java │ └── com │ └── lzh │ └── nonview │ └── router │ ├── InstanceRouter.java │ ├── Router.java │ ├── RouterConfiguration.java │ ├── activityresult │ ├── ActivityResultCallback.java │ └── ActivityResultDispatcher.java │ ├── exception │ ├── InterceptorException.java │ └── NotFoundException.java │ ├── executors │ └── MainThreadExecutor.java │ ├── extras │ └── RouteBundleExtras.java │ ├── interceptors │ ├── RouteInterceptor.java │ └── RouteInterceptorAction.java │ ├── launcher │ ├── ActionLauncher.java │ ├── ActivityLauncher.java │ ├── DefaultActionLauncher.java │ ├── DefaultActivityLauncher.java │ └── Launcher.java │ ├── module │ ├── ActionRouteRule.java │ ├── ActivityRouteRule.java │ ├── CreatorRouteRule.java │ ├── RemoteRule.java │ ├── RouteCreator.java │ └── RouteRule.java │ ├── parser │ └── URIParser.java │ ├── protocol │ ├── HostServiceWrapper.java │ └── IRemoteFactory.java │ ├── route │ ├── ActionRoute.java │ ├── ActionSupport.java │ ├── ActivityRoute.java │ ├── BaseRoute.java │ ├── BrowserRoute.java │ ├── IActionRoute.java │ ├── IActivityRoute.java │ ├── IBaseRoute.java │ ├── ICreatorInjector.java │ ├── IRoute.java │ ├── InternalCallback.java │ └── RouteCallback.java │ └── tools │ ├── Cache.java │ ├── CacheStore.java │ ├── Constants.java │ ├── RouterLog.java │ └── Utils.java ├── router-compiler ├── .gitignore ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── lzh │ │ └── nonview │ │ └── router │ │ └── compiler │ │ ├── Compiler.java │ │ ├── Constants.java │ │ ├── exception │ │ └── RouterException.java │ │ ├── factory │ │ └── RuleFactory.java │ │ ├── model │ │ ├── BasicConfigurations.java │ │ ├── Parser.java │ │ └── RouteRuleConfig.java │ │ └── util │ │ ├── UtilMgr.java │ │ └── Utils.java │ └── resources │ └── META-INF │ └── services │ └── javax.annotation.processing.Processor ├── router-host ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lzh │ │ └── nonview │ │ └── router │ │ └── host │ │ ├── DefaultVerify.java │ │ ├── RemoteVerify.java │ │ └── RouterHostService.java │ └── res │ └── values │ └── strings.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lzh │ │ └── nonview │ │ └── router │ │ └── demo │ │ ├── App.kt │ │ ├── ArgsActivity.kt │ │ ├── BaseActivity.kt │ │ ├── IntentPrinterActivity.kt │ │ ├── LoginActivity.kt │ │ ├── MainActivity.kt │ │ ├── ResultActivity.kt │ │ ├── UserActivity.kt │ │ ├── action │ │ ├── ExecutorAction.kt │ │ └── SayHelloAction.kt │ │ ├── executor │ │ └── TestExecutor.kt │ │ ├── interceptors │ │ ├── DefaultInterceptor.kt │ │ └── LoginInterceptor.kt │ │ ├── manager │ │ └── DataManager.kt │ │ └── pojo │ │ └── User.kt │ └── res │ ├── anim │ ├── anim_fade_in.xml │ └── anim_fade_out.xml │ ├── layout │ ├── activity_intent_printer.xml │ ├── activity_login.xml │ ├── activity_main.xml │ ├── activity_result.xml │ └── activity_user.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── upload.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | /routerlib/build 9 | /compiler/build 10 | /app/build 11 | /annotation/build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | sudo: false 4 | 5 | android: 6 | components: 7 | - platform-tools 8 | - tools 9 | - build-tools-25.0.0 10 | - android-23 11 | - sys-img-armeabi-v7a-android-23 12 | - extra-android-m2repository 13 | licenses: 14 | - 'android-sdk-preview-license-52d11cd2' 15 | - 'android-sdk-license-.+' 16 | - 'google-gdk-license-.+' 17 | 18 | script: ./gradlew clean assemble --stacktrace -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.2.41' 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.2' 11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | maven { url "https://jitpack.io" } 23 | 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | 31 | //添加 32 | ext { 33 | compile_version = 27 34 | target_version = 27 35 | build_tool = '27.0.3' 36 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | #org.gradle.daemon=true 21 | #org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JumeiRdGroup/Router/3a7340ed0e2be0d434531ab30baafbc91f3f5237/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Apr 15 16:47:25 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /javadoc.gradle: -------------------------------------------------------------------------------- 1 | // build a jar with source files 2 | task sourcesJar(type: Jar) { 3 | from android.sourceSets.main.java.srcDirs 4 | classifier = 'sources' 5 | } 6 | 7 | task javadoc(type: Javadoc) { 8 | failOnError false 9 | source = android.sourceSets.main.java.sourceFiles 10 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 11 | classpath += configurations.compile 12 | } 13 | 14 | // build a jar with javadoc 15 | task javadocJar(type: Jar, dependsOn: javadoc) { 16 | classifier = 'javadoc' 17 | from javadoc.destinationDir 18 | } 19 | 20 | artifacts { 21 | archives sourcesJar 22 | archives javadocJar 23 | } -------------------------------------------------------------------------------- /pics/route.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JumeiRdGroup/Router/3a7340ed0e2be0d434531ab30baafbc91f3f5237/pics/route.gif -------------------------------------------------------------------------------- /router-anno/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /router-anno/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | dependencies { 5 | } 6 | 7 | targetCompatibility = '1.7' 8 | sourceCompatibility = '1.7' 9 | 10 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/ActionLauncher.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | @Retention(RetentionPolicy.CLASS) 9 | @Target({ElementType.TYPE}) 10 | public @interface ActionLauncher { 11 | Class value(); 12 | } 13 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/ActivityLauncher.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | @Retention(RetentionPolicy.CLASS) 9 | @Target({ElementType.TYPE}) 10 | public @interface ActivityLauncher { 11 | Class value(); 12 | } 13 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/RouteConfig.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | * This annotation defined some basic configurations 10 | */ 11 | @Retention(RetentionPolicy.CLASS) 12 | @Target({ElementType.TYPE}) 13 | public @interface RouteConfig { 14 | 15 | /** 16 | * @return a base url to combine with the route you set via {@link RouterRule}. 17 | */ 18 | String baseUrl() default ""; 19 | 20 | /** 21 | * Defined a basic package value.when you haven't set a package value in {@link RouterRule},this word should be used instead 22 | * @return a basic package value. 23 | */ 24 | String pack() default ""; 25 | } 26 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/RouteExecutor.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | import java.util.concurrent.Executor; 8 | 9 | /** 10 | * This annotation provided user to indicate which thread the routing event will be called. 11 | * @author haoge 12 | */ 13 | @Retention(RetentionPolicy.CLASS) 14 | @Target({ElementType.TYPE}) 15 | public @interface RouteExecutor { 16 | /** 17 | * @return subClass of Executor. if not set. it should be MainThreadExecutor. 18 | */ 19 | Class value(); 20 | } 21 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/RouteInterceptors.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | * This annotation provide to set a serial of RouteInterceptor to used. 10 | */ 11 | @Retention(RetentionPolicy.CLASS) 12 | @Target({ElementType.TYPE}) 13 | public @interface RouteInterceptors { 14 | /** 15 | * Set the subclasses of RouteInterceptor to used, The interceptors will be triggered in sequence. 16 | * @return The array of RouteInterceptor class. 17 | */ 18 | Class[] value(); 19 | } 20 | -------------------------------------------------------------------------------- /router-anno/src/main/java/com/lzh/nonview/router/anno/RouterRule.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.anno; 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 | @Retention(RetentionPolicy.CLASS) 9 | @Target({ElementType.TYPE}) 10 | public @interface RouterRule { 11 | /** 12 | * value of scheme.should be unique and nonNull 13 | * @return scheme 14 | */ 15 | String[] value(); 16 | } 17 | -------------------------------------------------------------------------------- /router-api/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /router-api/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | android { 5 | compileSdkVersion compile_version 6 | buildToolsVersion build_tool 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion target_version 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | lintOptions { 21 | abortOnError false 22 | } 23 | 24 | packagingOptions { 25 | exclude 'LICENSE.txt' 26 | } 27 | 28 | sourceSets { 29 | main { 30 | jni.srcDirs = [] //disable automatic ndk-build 31 | } 32 | } 33 | } 34 | 35 | dependencies { 36 | api fileTree(include: ['*.jar'], dir: 'libs') 37 | api project(':router-anno') 38 | } 39 | 40 | apply from: '../javadoc.gradle' -------------------------------------------------------------------------------- /router-api/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/admin/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 | -------------------------------------------------------------------------------- /router-api/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /router-api/src/main/aidl/com/lzh/nonview/router/module/RemoteRule.aidl: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.module; 2 | 3 | parcelable RemoteRule; -------------------------------------------------------------------------------- /router-api/src/main/aidl/com/lzh/nonview/router/protocol/IService.aidl: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.protocol; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | 6 | import com.lzh.nonview.router.module.RemoteRule; 7 | 8 | /** 9 | * Remote Service for Host app. it provided a bridge to do multi-module supported. 10 | */ 11 | interface IService { 12 | 13 | void register(String pluginName); 14 | boolean isRegister(String pluginName); 15 | 16 | void addActivityRules(in Map rules); 17 | void addActionRules(in Map rules); 18 | 19 | RemoteRule getActionRule(in Uri uri); 20 | RemoteRule getActivityRule(in Uri uri); 21 | } -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/InstanceRouter.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router; 2 | 3 | import android.net.Uri; 4 | import android.os.Bundle; 5 | 6 | import com.lzh.nonview.router.module.CreatorRouteRule; 7 | import com.lzh.nonview.router.parser.URIParser; 8 | import com.lzh.nonview.router.route.ICreatorInjector; 9 | import com.lzh.nonview.router.tools.Cache; 10 | import com.lzh.nonview.router.tools.RouterLog; 11 | import com.lzh.nonview.router.tools.Utils; 12 | 13 | import java.util.Map; 14 | 15 | /** 16 | * @author haoge on 2018/5/25 17 | */ 18 | public class InstanceRouter { 19 | 20 | private Uri uri; 21 | private Bundle extra = new Bundle(); 22 | 23 | private InstanceRouter(Uri uri) { 24 | this.uri = uri; 25 | } 26 | 27 | static InstanceRouter build(String url) { 28 | return new InstanceRouter(Uri.parse(url)); 29 | } 30 | 31 | public InstanceRouter addExtras(Bundle extra){ 32 | if (extra != null) { 33 | this.extra.putAll(extra); 34 | } 35 | return this; 36 | } 37 | 38 | public T createInstance() { 39 | try { 40 | Map rules = Cache.getCreatorRules(); 41 | URIParser parser = new URIParser(uri); 42 | String route = parser.getRoute(); 43 | CreatorRouteRule rule = rules.get(route); 44 | if (rule == null) { 45 | RouterLog.d("Could not match rule for this uri"); 46 | return null; 47 | } 48 | 49 | Object instance = rule.getTarget().newInstance(); 50 | 51 | if (instance instanceof ICreatorInjector) { 52 | Bundle bundle = Utils.parseToBundle(parser); 53 | ((ICreatorInjector) instance).inject(bundle); 54 | } 55 | 56 | return (T) instance; 57 | } catch (Throwable e) { 58 | RouterLog.e("Create target class from InstanceRouter failed. cause by:" + e.getMessage(), e); 59 | return null; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/Router.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router; 17 | 18 | import android.content.Context; 19 | import android.net.Uri; 20 | import android.os.Bundle; 21 | 22 | import com.lzh.nonview.router.exception.NotFoundException; 23 | import com.lzh.nonview.router.extras.RouteBundleExtras; 24 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 25 | import com.lzh.nonview.router.module.RouteRule; 26 | import com.lzh.nonview.router.protocol.HostServiceWrapper; 27 | import com.lzh.nonview.router.route.ActionRoute; 28 | import com.lzh.nonview.router.activityresult.ActivityResultCallback; 29 | import com.lzh.nonview.router.route.ActivityRoute; 30 | import com.lzh.nonview.router.route.BaseRoute; 31 | import com.lzh.nonview.router.route.BrowserRoute; 32 | import com.lzh.nonview.router.route.IActionRoute; 33 | import com.lzh.nonview.router.route.IActivityRoute; 34 | import com.lzh.nonview.router.route.IBaseRoute; 35 | import com.lzh.nonview.router.route.IRoute; 36 | import com.lzh.nonview.router.route.InternalCallback; 37 | import com.lzh.nonview.router.route.RouteCallback; 38 | import com.lzh.nonview.router.tools.Cache; 39 | import com.lzh.nonview.router.tools.Constants; 40 | import com.lzh.nonview.router.tools.Utils; 41 | 42 | import java.util.concurrent.Executor; 43 | 44 | 45 | /** 46 | * Entry of Router。 47 | * 48 | * @author haoge 49 | */ 50 | public final class Router{ 51 | 52 | /** 53 | * The key of raw uri. you can obtains it uri by this key, for eg: 54 | *
 55 |      *      bundle.getParcelable(Router.RAW_URI)
 56 |      * 
57 | */ 58 | public static final String RAW_URI = "_ROUTER_RAW_URI_KEY_"; 59 | public static boolean DEBUG = false; 60 | 61 | private Uri uri; 62 | private InternalCallback internalCallback; 63 | 64 | private Router(Uri uri) { 65 | this.uri = uri; 66 | internalCallback = new InternalCallback(this.uri); 67 | } 68 | 69 | /** 70 | * Create Router by url string 71 | * @param url The url to create Router 72 | * @return new Router 73 | */ 74 | public static Router create(String url) { 75 | return new Router(Uri.parse(url == null?"":url)); 76 | } 77 | 78 | /** 79 | * Create Router by uri 80 | * @param uri the uri to create Router 81 | * @return new Router 82 | */ 83 | public static Router create(Uri uri) { 84 | return new Router(uri); 85 | } 86 | 87 | public static InstanceRouter createInstanceRouter(String url) { 88 | return InstanceRouter.build(url); 89 | } 90 | 91 | /** 92 | * Set a callback to notify the user when the routing were success or failure. 93 | * @param callback The callback you set. 94 | * @return Router itself 95 | */ 96 | public Router setCallback (RouteCallback callback) { 97 | this.internalCallback.setCallback(callback); 98 | return this; 99 | } 100 | 101 | public Router addInterceptor(RouteInterceptor interceptor) { 102 | this.internalCallback.getExtras().addInterceptor(interceptor); 103 | return this; 104 | } 105 | 106 | public Router requestCode(int requestCode) { 107 | this.internalCallback.getExtras().setRequestCode(requestCode); 108 | return this; 109 | } 110 | 111 | public Router resultCallback(ActivityResultCallback callback) { 112 | this.internalCallback.getExtras().putValue(Constants.KEY_RESULT_CALLBACK, callback); 113 | return this; 114 | } 115 | 116 | public Router addFlags(int flag) { 117 | this.internalCallback.getExtras().addFlags(flag); 118 | return this; 119 | } 120 | 121 | public Router setAnim(int enterAnim, int exitAnim) { 122 | this.internalCallback.getExtras().setInAnimation(enterAnim); 123 | this.internalCallback.getExtras().setOutAnimation(exitAnim); 124 | return this; 125 | } 126 | 127 | public Router setOptions(Bundle options) { 128 | this.internalCallback.getExtras().putValue(Constants.KEY_ACTIVITY_OPTIONS, options); 129 | return this; 130 | } 131 | 132 | public Router addExtras(Bundle extras) { 133 | this.internalCallback.getExtras().addExtras(extras); 134 | return this; 135 | } 136 | 137 | public Router setExecutor(Executor executor) { 138 | this.internalCallback.getExtras().putValue(Constants.KEY_ACTION_EXECUTOR, executor); 139 | return this; 140 | } 141 | 142 | /** 143 | * Restore a Routing event from last uri and extras. 144 | * @param uri last uri 145 | * @param extras last extras 146 | * @return The restored routing find by {@link Router#getRoute()} 147 | */ 148 | public static IRoute resume(Uri uri, RouteBundleExtras extras) { 149 | IRoute route = Router.create(uri).getRoute(); 150 | if (route instanceof BaseRoute) { 151 | ((BaseRoute) route).replaceExtras(extras); 152 | } 153 | return route; 154 | } 155 | 156 | /** 157 | * launch routing task. 158 | * @param context context to launched 159 | */ 160 | public void open(Context context) { 161 | getRoute().open(context); 162 | } 163 | 164 | 165 | /** 166 | * Get route by uri, you should get a route by this way and set some extras data before open 167 | * @return 168 | * An IRoute object.it will be {@link BrowserRoute}, {@link ActivityRoute} or {@link ActionRoute}.
169 | * and it also will be {@link IRoute.EmptyRoute} if it not found 170 | */ 171 | public IRoute getRoute () { 172 | IRoute route = getLocalRoute(); 173 | if (!(route instanceof IRoute.EmptyRoute)) { 174 | return route; 175 | } 176 | route = HostServiceWrapper.create(uri, internalCallback); 177 | if (route instanceof IRoute.EmptyRoute) { 178 | notifyNotFound(String.format("find Route by %s failed:",uri)); 179 | } 180 | return route; 181 | } 182 | 183 | private IRoute getLocalRoute() { 184 | try { 185 | RouteRule rule; 186 | if (!Utils.isValidUri(uri)) { 187 | return new IRoute.EmptyRoute(internalCallback); 188 | } else if ((rule = ActionRoute.findRule(uri, Cache.TYPE_ACTION_ROUTE)) != null) { 189 | return new ActionRoute().create(uri, rule, new Bundle(), internalCallback); 190 | } else if ((rule = ActivityRoute.findRule(uri, Cache.TYPE_ACTIVITY_ROUTE)) != null) { 191 | return new ActivityRoute().create(uri, rule, new Bundle(), internalCallback); 192 | } else if (BrowserRoute.canOpenRouter(uri)) { 193 | return BrowserRoute.getInstance().setUri(uri); 194 | } else { 195 | return new IRoute.EmptyRoute(internalCallback); 196 | } 197 | } catch (Exception e) { 198 | internalCallback.onOpenFailed(e); 199 | return new IRoute.EmptyRoute(internalCallback); 200 | } 201 | } 202 | 203 | /** 204 | *

205 | * Get {@link IBaseRoute} by uri, it could be one of {@link IActivityRoute} or {@link IActionRoute}. 206 | * and you can add some {@link android.os.Bundle} data and {@link RouteInterceptor} into it. 207 | *

208 | * @return returns an {@link IBaseRoute} finds by uri or {@link IBaseRoute.EmptyBaseRoute} for not found 209 | */ 210 | public IBaseRoute getBaseRoute() { 211 | IRoute route = getRoute(); 212 | if (route instanceof IBaseRoute) { 213 | return (IBaseRoute) route; 214 | } 215 | 216 | notifyNotFound(String.format("find BaseRoute by %s failed, but is %s",uri, route.getClass().getSimpleName())); 217 | return new IBaseRoute.EmptyBaseRoute(internalCallback); 218 | } 219 | 220 | /** 221 | * Get {@link IActivityRoute} by uri,you should get a route by this way and set some extras data before open 222 | * @return returns an {@link IActivityRoute} finds by uri or {@link IActivityRoute.EmptyActivityRoute} for not found. 223 | */ 224 | public IActivityRoute getActivityRoute() { 225 | IRoute route = getRoute(); 226 | if (route instanceof IActivityRoute) { 227 | return (IActivityRoute) route; 228 | } 229 | 230 | // return an empty route to avoid NullPointException 231 | notifyNotFound(String.format("find ActivityRoute by %s failed, but is %s",uri, route.getClass().getSimpleName())); 232 | return new IActivityRoute.EmptyActivityRoute(internalCallback); 233 | } 234 | 235 | /** 236 | * Get {@link IActionRoute} by uri,you should get a route by this way and set some extras data before open 237 | * @return returns an {@link IActionRoute} finds by uri or {@link IActionRoute.EmptyActionRoute} for not found. 238 | */ 239 | public IActionRoute getActionRoute() { 240 | IRoute route = getRoute(); 241 | if (route instanceof IActionRoute) { 242 | return (IActionRoute) route; 243 | } 244 | 245 | notifyNotFound(String.format("find ActionRoute by %s failed, but is %s",uri, route.getClass().getSimpleName())); 246 | // return a empty route to avoid NullPointException 247 | return new IActionRoute.EmptyActionRoute(internalCallback); 248 | } 249 | 250 | private void notifyNotFound(String msg) { 251 | internalCallback.onOpenFailed(new NotFoundException(msg)); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/RouterConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router; 17 | 18 | import android.app.Activity; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.net.Uri; 22 | 23 | import com.lzh.nonview.router.activityresult.ActivityResultDispatcher; 24 | import com.lzh.nonview.router.extras.RouteBundleExtras; 25 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 26 | import com.lzh.nonview.router.launcher.ActionLauncher; 27 | import com.lzh.nonview.router.launcher.ActivityLauncher; 28 | import com.lzh.nonview.router.launcher.DefaultActionLauncher; 29 | import com.lzh.nonview.router.launcher.DefaultActivityLauncher; 30 | import com.lzh.nonview.router.module.RouteCreator; 31 | import com.lzh.nonview.router.protocol.HostServiceWrapper; 32 | import com.lzh.nonview.router.protocol.IRemoteFactory; 33 | import com.lzh.nonview.router.route.ActionRoute; 34 | import com.lzh.nonview.router.route.ActivityRoute; 35 | import com.lzh.nonview.router.route.InternalCallback; 36 | import com.lzh.nonview.router.route.RouteCallback; 37 | import com.lzh.nonview.router.tools.Cache; 38 | 39 | import java.util.concurrent.Executor; 40 | 41 | /** 42 | * Entrance class to store router configurations. 43 | */ 44 | public final class RouterConfiguration { 45 | 46 | private RouteInterceptor interceptor; 47 | private RouteCallback callback; 48 | 49 | private IRemoteFactory remoteFactory = null; 50 | private Class activityLauncher; 51 | private Class actionLauncher; 52 | 53 | 54 | public RouteInterceptor getInterceptor() { 55 | return interceptor; 56 | } 57 | 58 | /** 59 | * Set a default routing interceptor to used. it will be called by all the routes. 60 | * @param interceptor the default interceptor 61 | * @return config itself 62 | * @see RouteInterceptor 63 | */ 64 | public RouterConfiguration setInterceptor(RouteInterceptor interceptor) { 65 | this.interceptor = interceptor; 66 | return this; 67 | } 68 | 69 | public RouteCallback getCallback() { 70 | return callback; 71 | } 72 | 73 | /** 74 | * Set a default routing callback to used. it will be called by all the routes. 75 | * @param callback The default callback 76 | * @return config itself 77 | * @see RouteCallback 78 | */ 79 | public RouterConfiguration setCallback(RouteCallback callback) { 80 | this.callback = callback; 81 | return this; 82 | } 83 | 84 | public IRemoteFactory getRemoteFactory() { 85 | return remoteFactory; 86 | } 87 | 88 | /** 89 | * Set a default remote factory to used. the factory must contains a default empty construction. 90 | * @param remoteFactory The remote factory class 91 | * @return config itself 92 | * @see IRemoteFactory 93 | */ 94 | public RouterConfiguration setRemoteFactory(IRemoteFactory remoteFactory) { 95 | this.remoteFactory = remoteFactory; 96 | return this; 97 | } 98 | 99 | public Class getActivityLauncher() { 100 | return activityLauncher == null ? DefaultActivityLauncher.class : activityLauncher; 101 | } 102 | 103 | /** 104 | * Set a default activity launcher to used. 105 | * @param activityLauncher The launcher class for {@link ActivityRoute} 106 | * @return config itself 107 | * @see ActivityLauncher 108 | */ 109 | public RouterConfiguration setActivityLauncher(Class activityLauncher) { 110 | this.activityLauncher = activityLauncher; 111 | return this; 112 | } 113 | 114 | public Class getActionLauncher() { 115 | return actionLauncher == null ? DefaultActionLauncher.class : actionLauncher; 116 | } 117 | 118 | /** 119 | * Set a default action launcher to used. 120 | * @param actionLauncher The launcher class for {@link ActionRoute} 121 | * @return config itself 122 | * @see ActionLauncher 123 | */ 124 | public RouterConfiguration setActionLauncher(Class actionLauncher) { 125 | this.actionLauncher = actionLauncher; 126 | return this; 127 | } 128 | 129 | /** 130 | * Add a route rule creator and register it for remote service if is launched. 131 | * @param creator Route rules creator.can't be null 132 | */ 133 | public void addRouteCreator(RouteCreator creator) { 134 | Cache.addCreator(creator); 135 | HostServiceWrapper.registerRulesToHostService(); 136 | } 137 | 138 | /** 139 | * To register an executor that 140 | * @param key The class of Executor 141 | * @param value The Executor instance associate with the key. 142 | * @see Cache#registerExecutors(Class, Executor) 143 | */ 144 | public void registerExecutors(Class key, Executor value) { 145 | Cache.registerExecutors(key, value); 146 | } 147 | 148 | /** 149 | * @see RouterConfiguration#startHostService(String, Context, String) 150 | * @param hostPackage The package name of host. it to launch a remote service of host. 151 | * @param context The valid context 152 | */ 153 | public void startHostService(String hostPackage, Context context) { 154 | startHostService(hostPackage, context, null); 155 | } 156 | 157 | /** 158 | * start a remote host service 159 | * @param hostPackage The package name of host. it to launch a remote service of host. 160 | * @param context The valid context 161 | * @param pluginName The unique identifier plugin name. or null to use the plugin-package name for it. 162 | */ 163 | public void startHostService(String hostPackage, Context context, String pluginName) { 164 | HostServiceWrapper.startHostService(hostPackage, context, pluginName); 165 | } 166 | 167 | /** 168 | * Check if the specified plug-in names have been registered to the remote service. 169 | * @param pluginName The specified plug-in names 170 | * @return True if it has been registered. 171 | */ 172 | public boolean isRegister(String pluginName) { 173 | return HostServiceWrapper.isRegister(pluginName); 174 | } 175 | 176 | /** 177 | * Restore a {@link RouteBundleExtras} by uri. this method should only be called in lifecycle of {@link RouteCallback}. 178 | * otherwise it will be null cause it is cleaned. 179 | * @param uri The uri that you open 180 | * @return The {@link RouteBundleExtras} instance that you may set before before you open the routing by uri. 181 | */ 182 | public RouteBundleExtras restoreExtras(Uri uri) { 183 | return InternalCallback.findExtrasByUri(uri); 184 | } 185 | 186 | public Context restorContext(Uri uri) { 187 | return InternalCallback.findContextByUri(uri); 188 | } 189 | 190 | public boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { 191 | return ActivityResultDispatcher.get().dispatchActivityResult(activity, requestCode, resultCode, data); 192 | } 193 | 194 | private static RouterConfiguration config = new RouterConfiguration(); 195 | private RouterConfiguration() {} 196 | public static RouterConfiguration get() { 197 | return config; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/activityresult/ActivityResultCallback.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.activityresult; 2 | 3 | import android.content.Intent; 4 | 5 | public interface ActivityResultCallback { 6 | void onResult(int resultCode, Intent data); 7 | } 8 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/activityresult/ActivityResultDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.activityresult; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | 6 | import com.lzh.nonview.router.tools.Utils; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | public final class ActivityResultDispatcher { 16 | 17 | private Map> container = new HashMap<>(); 18 | 19 | private static ActivityResultDispatcher dispatcher = new ActivityResultDispatcher(); 20 | private ActivityResultDispatcher(){ } 21 | public static ActivityResultDispatcher get() { 22 | return dispatcher; 23 | } 24 | 25 | public void bindRequestArgs(Activity activity, int requestCode, ActivityResultCallback callback) { 26 | if (!Utils.isValid(activity) 27 | || callback == null 28 | || requestCode == -1) { 29 | return; 30 | } 31 | 32 | List list = findListByKey(activity); 33 | list.add(new RequestArgs(requestCode, callback)); 34 | } 35 | 36 | public boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { 37 | if (!container.containsKey(activity)) { 38 | return false; 39 | } 40 | 41 | boolean handle = false; 42 | List list = findListByKey(activity); 43 | for (RequestArgs args:list) { 44 | if (args.requestCode == requestCode) { 45 | args.callback.onResult(resultCode, data); 46 | list.remove(args); 47 | handle = true; 48 | break; 49 | } 50 | } 51 | 52 | releaseInvalidItems(); 53 | return handle; 54 | } 55 | 56 | // 移除无效的条目:比如当前activity在后台时被回收了 57 | private void releaseInvalidItems() { 58 | Set keys = container.keySet(); 59 | Iterator iterator = keys.iterator(); 60 | while (iterator.hasNext()) { 61 | Activity next = iterator.next(); 62 | if (!Utils.isValid(next) 63 | || container.get(next).isEmpty()) { 64 | iterator.remove(); 65 | } 66 | } 67 | } 68 | 69 | private List findListByKey(Activity activity) { 70 | List list = container.get(activity); 71 | if (list == null) { 72 | list = new ArrayList<>(); 73 | container.put(activity, list); 74 | } 75 | return list; 76 | } 77 | 78 | private static class RequestArgs { 79 | int requestCode; 80 | ActivityResultCallback callback; 81 | 82 | public RequestArgs(int requestCode, ActivityResultCallback callback) { 83 | this.requestCode = requestCode; 84 | this.callback = callback; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/exception/InterceptorException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.exception; 17 | 18 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 19 | 20 | /** 21 | * Throw this exception when routing events were intercepted。 22 | * @author haoge 23 | */ 24 | public class InterceptorException extends RuntimeException { 25 | 26 | private final RouteInterceptor interceptor; 27 | public InterceptorException(RouteInterceptor interceptor) { 28 | super("This route action has been intercepted"); 29 | this.interceptor = interceptor; 30 | } 31 | 32 | /** 33 | * Provide users with access to the interceptor 34 | * @return The interceptor who intercept the event 35 | */ 36 | public RouteInterceptor getInterceptor() { 37 | return interceptor; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/exception/NotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.exception; 17 | 18 | /** 19 | * The custom exception represents not found 20 | * @author haoge 21 | */ 22 | public class NotFoundException extends RuntimeException { 23 | 24 | public NotFoundException(String detailMessage) { 25 | super(detailMessage); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/executors/MainThreadExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.executors; 17 | 18 | import android.os.Handler; 19 | import android.os.Looper; 20 | 21 | import java.util.concurrent.Executor; 22 | 23 | public class MainThreadExecutor implements Executor{ 24 | 25 | private Handler mainHandler = new Handler(Looper.getMainLooper()); 26 | 27 | @Override 28 | public void execute(Runnable command) { 29 | 30 | if (Looper.myLooper() == Looper.getMainLooper()) { 31 | command.run(); 32 | } else { 33 | mainHandler.post(command); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/extras/RouteBundleExtras.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.extras; 17 | 18 | import android.os.Bundle; 19 | import android.os.Parcel; 20 | import android.os.Parcelable; 21 | import android.text.TextUtils; 22 | 23 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 24 | import com.lzh.nonview.router.route.IBaseRoute; 25 | import com.lzh.nonview.router.route.RouteCallback; 26 | import com.lzh.nonview.router.tools.CacheStore; 27 | 28 | import java.util.ArrayList; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | /** 34 | * An extra container contains {@link RouteBundleExtras#extras} and {@link RouteBundleExtras#interceptors} 35 | *

36 | * extras: the extra bundle data set by {@link IBaseRoute#addExtras(Bundle)} 37 | * interceptors: the extra RouteInterceptor set by {@link IBaseRoute#addInterceptor(RouteInterceptor)} 38 | *

39 | * 40 | * @author haoge 41 | * @see com.lzh.nonview.router.route.IBaseRoute 42 | */ 43 | public final class RouteBundleExtras implements Parcelable{ 44 | 45 | private ArrayList interceptors = new ArrayList<>(); 46 | private RouteCallback callback; 47 | private Map additionalMap = new HashMap<>(); 48 | 49 | private Bundle extras = new Bundle(); 50 | // the extras belows is only supports for ActivityRoute. 51 | private int requestCode = -1; 52 | private int inAnimation = -1; 53 | private int outAnimation = -1; 54 | private int flags = 0; 55 | 56 | public RouteBundleExtras() {} 57 | 58 | public void addInterceptor(RouteInterceptor interceptor) { 59 | if (interceptor != null && !getInterceptors().contains(interceptor)) { 60 | getInterceptors().add(interceptor); 61 | } 62 | } 63 | 64 | public void removeInterceptor(RouteInterceptor interceptor) { 65 | if (interceptor != null) { 66 | getInterceptors().remove(interceptor); 67 | } 68 | } 69 | 70 | public void removeAllInterceptors() { 71 | getInterceptors().clear(); 72 | } 73 | 74 | public List getInterceptors() { 75 | return interceptors; 76 | } 77 | 78 | public void setCallback(RouteCallback callback) { 79 | this.callback = callback; 80 | } 81 | 82 | public RouteCallback getCallback() { 83 | return callback; 84 | } 85 | 86 | public int getRequestCode() { 87 | return requestCode; 88 | } 89 | 90 | public void setRequestCode(int requestCode) { 91 | this.requestCode = requestCode; 92 | } 93 | 94 | public int getInAnimation() { 95 | return inAnimation; 96 | } 97 | 98 | public void setInAnimation(int inAnimation) { 99 | this.inAnimation = inAnimation; 100 | } 101 | 102 | public int getOutAnimation() { 103 | return outAnimation; 104 | } 105 | 106 | public void setOutAnimation(int outAnimation) { 107 | this.outAnimation = outAnimation; 108 | } 109 | 110 | public int getFlags() { 111 | return flags; 112 | } 113 | 114 | public void addFlags(int flags) { 115 | this.flags |= flags; 116 | } 117 | 118 | public T getValue(String key) { 119 | if (TextUtils.isEmpty(key)) { 120 | return null; 121 | } 122 | 123 | try { 124 | //noinspection unchecked 125 | return (T) additionalMap.get(key); 126 | } catch (ClassCastException cast) { 127 | return null; 128 | } 129 | } 130 | 131 | public void putValue(String key, Object value) { 132 | if (TextUtils.isEmpty(key) || value == null) { 133 | return; 134 | } 135 | 136 | additionalMap.put(key, value); 137 | } 138 | 139 | // ------------------------- divider for parcelable ------------------------ 140 | private RouteBundleExtras(Parcel in) { 141 | requestCode = in.readInt(); 142 | inAnimation = in.readInt(); 143 | outAnimation = in.readInt(); 144 | flags = in.readInt(); 145 | extras = in.readBundle(getClass().getClassLoader()); 146 | 147 | ArrayList interceptors = CacheStore.get().get(in.readInt()); 148 | RouteCallback callback = CacheStore.get().get(in.readInt()); 149 | Map additionalMap = CacheStore.get().get(in.readInt()); 150 | 151 | if (interceptors != null) this.interceptors = interceptors; 152 | if (callback != null) this.callback = callback; 153 | if (additionalMap != null) this.additionalMap = additionalMap; 154 | } 155 | 156 | public static final Creator CREATOR = new Creator() { 157 | @Override 158 | public RouteBundleExtras createFromParcel(Parcel in) { 159 | return new RouteBundleExtras(in); 160 | } 161 | 162 | @Override 163 | public RouteBundleExtras[] newArray(int size) { 164 | return new RouteBundleExtras[size]; 165 | } 166 | }; 167 | 168 | @Override 169 | public int describeContents() { 170 | return 0; 171 | } 172 | 173 | @Override 174 | public void writeToParcel(Parcel dest, int flags) { 175 | dest.writeInt(requestCode); 176 | dest.writeInt(inAnimation); 177 | dest.writeInt(outAnimation); 178 | dest.writeInt(this.flags); 179 | 180 | dest.writeBundle(extras); 181 | 182 | dest.writeInt(CacheStore.get().put(interceptors)); 183 | dest.writeInt(CacheStore.get().put(callback)); 184 | dest.writeInt(CacheStore.get().put(additionalMap)); 185 | } 186 | 187 | public Bundle getExtras() { 188 | return extras; 189 | } 190 | 191 | public void addExtras(Bundle extras) { 192 | if (extras != null) { 193 | this.extras.putAll(extras); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/interceptors/RouteInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.interceptors; 17 | 18 | import android.content.Context; 19 | import android.net.Uri; 20 | 21 | import com.lzh.nonview.router.Router; 22 | import com.lzh.nonview.router.extras.RouteBundleExtras; 23 | 24 | /** 25 | * An interceptor interface 26 | * @author haoge 27 | */ 28 | public interface RouteInterceptor{ 29 | 30 | /** 31 | * Whether or not be interrupted when open activity by uri 32 | * @param uri uri the uri to open 33 | * @param context context 34 | * @param extras some extras data for route, 35 | * sometimes is null when you not use 36 | * {@link Router#getBaseRoute()} to set some extras data into it 37 | * @return true if should be intercepted 38 | */ 39 | boolean intercept (Uri uri, RouteBundleExtras extras, Context context); 40 | 41 | /** 42 | * This method should be invoked when you has been intercepted 43 | * @param uri uri the uri to open 44 | * @param context context 45 | * @param extras some extras data for route, 46 | * sometimes is null when you not use 47 | * {@link Router#getBaseRoute()} to set some extras data into it 48 | */ 49 | void onIntercepted(Uri uri, RouteBundleExtras extras, Context context); 50 | } 51 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/interceptors/RouteInterceptorAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.interceptors; 17 | 18 | import java.util.List; 19 | 20 | public interface RouteInterceptorAction { 21 | 22 | /** 23 | * Add a interceptor to container 24 | * @param interceptor interceptor instance 25 | * @return The real type 26 | */ 27 | T addInterceptor (RouteInterceptor interceptor); 28 | 29 | /** 30 | * Remove a interceptor from container 31 | * @param interceptor interceptor instance 32 | * @return The real type 33 | */ 34 | T removeInterceptor (RouteInterceptor interceptor); 35 | 36 | /** 37 | * remove all of interceptors you has set before 38 | * @return The real type 39 | */ 40 | T removeAllInterceptors (); 41 | 42 | /** 43 | * get all interceptors you has set before 44 | * @return all of interceptors 45 | */ 46 | List getInterceptors (); 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/launcher/ActionLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.launcher; 17 | 18 | import com.lzh.nonview.router.module.ActionRouteRule; 19 | import com.lzh.nonview.router.tools.Cache; 20 | import com.lzh.nonview.router.tools.Constants; 21 | 22 | import java.util.concurrent.Executor; 23 | 24 | /** 25 | * The base class of Action Launcher 26 | * 27 | *

28 | * The default impl is {@link DefaultActionLauncher} 29 | *

30 | */ 31 | public abstract class ActionLauncher extends Launcher { 32 | 33 | /** 34 | * @return returns a executor instance to switching thread. 35 | */ 36 | protected Executor getExecutor() { 37 | Executor executor = extras.getValue(Constants.KEY_ACTION_EXECUTOR); 38 | if (executor == null) { 39 | executor = Cache.findOrCreateExecutor(((ActionRouteRule) rule).getExecutor()); 40 | } 41 | return executor; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/launcher/ActivityLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.launcher; 17 | 18 | import android.app.Fragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | 22 | 23 | /** 24 | * The base class of Activity Launcher 25 | * 26 | *

27 | * The default impl is {@link DefaultActivityLauncher} 28 | *

29 | */ 30 | public abstract class ActivityLauncher extends Launcher{ 31 | 32 | /** 33 | * This method will be invoked when you call {@link com.lzh.nonview.router.route.ActivityRoute#createIntent(Context)} 34 | * 35 | * @param context The context instance. 36 | * @return The new intent that created by the launcher 37 | */ 38 | public abstract Intent createIntent(Context context); 39 | 40 | /** 41 | * The launch method for Fragment: {@link Fragment#startActivityForResult(Intent, int)} 42 | * @param fragment The fragment instance 43 | * @throws Exception a error occurs 44 | */ 45 | public abstract void open(Fragment fragment) throws Exception; 46 | } 47 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/launcher/DefaultActionLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.launcher; 17 | 18 | import android.content.Context; 19 | import android.os.Bundle; 20 | 21 | import com.lzh.nonview.router.route.ActionSupport; 22 | 23 | /** 24 | * Default Action Launcher for {@link com.lzh.nonview.router.route.ActionRoute} 25 | */ 26 | public class DefaultActionLauncher extends ActionLauncher{ 27 | 28 | @Override 29 | public void open(Context context) { 30 | final ActionSupport support = newInstance(rule.getRuleClz()); 31 | final Bundle data = new Bundle(); 32 | data.putAll(bundle); 33 | data.putAll(extras.getExtras()); 34 | getExecutor().execute(new ActionRunnable(support, context, data)); 35 | } 36 | 37 | private static class ActionRunnable implements Runnable { 38 | 39 | ActionSupport support; 40 | Context context; 41 | Bundle data; 42 | 43 | ActionRunnable(ActionSupport support, Context context, Bundle data) { 44 | this.support = support; 45 | this.context = context; 46 | this.data = data; 47 | } 48 | 49 | @Override 50 | public void run() { 51 | support.onRouteTrigger(context, data); 52 | } 53 | } 54 | 55 | private ActionSupport newInstance(String name) { 56 | try { 57 | return (ActionSupport) Class.forName(name).newInstance(); 58 | } catch (Exception e) { 59 | throw new RuntimeException(String.format("create instance of %s failed", name), e); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/launcher/DefaultActivityLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.launcher; 17 | 18 | import android.app.Activity; 19 | import android.app.Fragment; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.os.Build; 23 | 24 | import com.lzh.nonview.router.activityresult.ActivityResultCallback; 25 | import com.lzh.nonview.router.activityresult.ActivityResultDispatcher; 26 | import com.lzh.nonview.router.extras.RouteBundleExtras; 27 | 28 | /** 29 | * Default Activity Launcher for {@link com.lzh.nonview.router.route.ActivityRoute} 30 | */ 31 | public class DefaultActivityLauncher extends ActivityLauncher{ 32 | 33 | @Override 34 | public Intent createIntent(Context context) { 35 | Intent intent = new Intent(); 36 | intent.setClassName(context, rule.getRuleClz()); 37 | intent.putExtras(bundle); 38 | intent.putExtras(extras.getExtras()); 39 | intent.addFlags(extras.getFlags()); 40 | return intent; 41 | } 42 | 43 | @Override 44 | public void open(Fragment fragment) { 45 | if (resumeContext != null) { 46 | open(resumeContext); 47 | } else if (resultCallback != null) { 48 | open(fragment.getActivity()); 49 | } else { 50 | Intent intent = createIntent(fragment.getActivity()); 51 | fragment.startActivityForResult(intent, extras.getRequestCode()); 52 | overridePendingTransition(fragment.getActivity(), extras); 53 | } 54 | } 55 | 56 | @Override 57 | public void open(Context context) { 58 | Activity resume = resumeContext; 59 | if (resume != null) { 60 | context = resume; 61 | } 62 | 63 | ActivityResultCallback callback = resultCallback; 64 | int requestCode = extras.getRequestCode(); 65 | 66 | Intent intent = createIntent(context); 67 | if (context instanceof Activity) { 68 | Activity activity = (Activity) context; 69 | if (options != null && Build.VERSION.SDK_INT >= 16) { 70 | activity.startActivityForResult(intent, requestCode, options); 71 | } else { 72 | activity.startActivityForResult(intent,requestCode); 73 | } 74 | overridePendingTransition((Activity) context, extras); 75 | ActivityResultDispatcher.get().bindRequestArgs(activity, requestCode, callback); 76 | } else { 77 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 78 | context.startActivity(intent); 79 | } 80 | } 81 | 82 | protected void overridePendingTransition(Activity activity, RouteBundleExtras extras) { 83 | if (activity == null || extras == null) { 84 | return; 85 | } 86 | 87 | int inAnimation = extras.getInAnimation(); 88 | int outAnimation = extras.getOutAnimation(); 89 | if (inAnimation >= 0 && outAnimation >= 0) { 90 | activity.overridePendingTransition(inAnimation,outAnimation); 91 | } 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/launcher/Launcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.launcher; 17 | 18 | import android.app.Activity; 19 | import android.content.Context; 20 | import android.net.Uri; 21 | import android.os.Bundle; 22 | 23 | import com.lzh.nonview.router.Router; 24 | import com.lzh.nonview.router.activityresult.ActivityResultCallback; 25 | import com.lzh.nonview.router.extras.RouteBundleExtras; 26 | import com.lzh.nonview.router.module.RouteRule; 27 | import com.lzh.nonview.router.tools.Constants; 28 | 29 | import java.util.Random; 30 | 31 | /** 32 | * The base launcher class. 33 | */ 34 | public abstract class Launcher { 35 | private static Random sCodeGenerator = new Random(); 36 | 37 | protected Uri uri; 38 | protected Bundle bundle; 39 | protected RouteBundleExtras extras; 40 | protected RouteRule rule; 41 | protected Bundle remote; 42 | 43 | protected Activity resumeContext; 44 | protected ActivityResultCallback resultCallback; 45 | protected Bundle options; 46 | 47 | /** 48 | * Requires to open with this launcher. 49 | * @param context context 50 | * @throws Exception Some error occurs. 51 | */ 52 | public abstract void open(Context context) throws Exception; 53 | 54 | /** 55 | * Set all of extras data to used. 56 | * @param uri The route uri. 57 | * @param bundle The bundle data that is parsed by uri params. 58 | * @param extras The extras data you set via {@link Router#getRoute()} 59 | * @param rule The rule that associate with the uri. 60 | */ 61 | public final void set(Uri uri, Bundle bundle, RouteBundleExtras extras, RouteRule rule, Bundle remote) { 62 | this.uri = uri; 63 | this.bundle = bundle; 64 | this.extras = extras; 65 | this.rule = rule; 66 | this.remote = remote; 67 | 68 | resumeContext = extras.getValue(Constants.KEY_RESUME_CONTEXT); 69 | resultCallback = extras.getValue(Constants.KEY_RESULT_CALLBACK); 70 | options = extras.getValue(Constants.KEY_ACTIVITY_OPTIONS); 71 | 72 | int requestCode = extras.getRequestCode(); 73 | if (resultCallback != null && requestCode == -1) { 74 | extras.setRequestCode(sCodeGenerator.nextInt(0x0000ffff)); 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/ActionRouteRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.module; 17 | 18 | import com.lzh.nonview.router.executors.MainThreadExecutor; 19 | import com.lzh.nonview.router.launcher.ActionLauncher; 20 | import com.lzh.nonview.router.route.ActionSupport; 21 | 22 | import java.util.concurrent.Executor; 23 | 24 | public class ActionRouteRule extends RouteRule { 25 | 26 | private Class executor = MainThreadExecutor.class; 27 | 28 | public ActionRouteRule(Class clz) { 29 | super(clz.getCanonicalName()); 30 | } 31 | 32 | public ActionRouteRule(String clzName) { 33 | super(clzName); 34 | } 35 | 36 | public ActionRouteRule setExecutorClass(Class executor) { 37 | if (executor != null) { 38 | this.executor = executor; 39 | } 40 | return this; 41 | } 42 | 43 | public Class getExecutor() { 44 | return executor; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/ActivityRouteRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.module; 17 | 18 | 19 | import android.app.Activity; 20 | 21 | import com.lzh.nonview.router.launcher.ActivityLauncher; 22 | 23 | public class ActivityRouteRule extends RouteRule { 24 | 25 | public ActivityRouteRule(Class clz) { 26 | super(clz.getCanonicalName()); 27 | } 28 | 29 | public ActivityRouteRule(String clzName) { 30 | super(clzName); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/CreatorRouteRule.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.module; 2 | 3 | import com.lzh.nonview.router.launcher.Launcher; 4 | 5 | /** 6 | * @author haoge on 2018/5/25 7 | */ 8 | public class CreatorRouteRule extends RouteRule { 9 | 10 | private Class target; 11 | 12 | public CreatorRouteRule(Class clz) { 13 | super(clz.getCanonicalName()); 14 | this.target = clz; 15 | } 16 | 17 | public Class getTarget() { 18 | return target; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/RemoteRule.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.module; 2 | 3 | import android.os.Bundle; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import java.util.HashMap; 8 | 9 | public class RemoteRule implements Parcelable{ 10 | // target class name 11 | private String name; 12 | // params in RouteRule 13 | private HashMap params; 14 | // the extra bundle created by IRemoteFactory. 15 | private Bundle extra; 16 | // type in [Action, Activity] 17 | private int type; 18 | 19 | private RouteRule rule; 20 | 21 | public RemoteRule() { 22 | } 23 | 24 | protected RemoteRule(Parcel in) { 25 | name = in.readString(); 26 | params = in.readHashMap(getClass().getClassLoader()); 27 | type = in.readInt(); 28 | extra = in.readBundle(getClass().getClassLoader()); 29 | } 30 | 31 | public static final Creator CREATOR = new Creator() { 32 | @Override 33 | public RemoteRule createFromParcel(Parcel in) { 34 | return new RemoteRule(in); 35 | } 36 | 37 | @Override 38 | public RemoteRule[] newArray(int size) { 39 | return new RemoteRule[size]; 40 | } 41 | }; 42 | 43 | public static RemoteRule create(RouteRule rule, Bundle extra) { 44 | RemoteRule remote = new RemoteRule(); 45 | remote.name = rule.getRuleClz(); 46 | remote.params = rule.getParams(); 47 | remote.type = (rule instanceof ActivityRouteRule) ? 0 : 1; 48 | remote.extra = extra; 49 | return remote; 50 | } 51 | 52 | @Override 53 | public int describeContents() { 54 | return 0; 55 | } 56 | 57 | @Override 58 | public void writeToParcel(Parcel dest, int flags) { 59 | dest.writeString(name); 60 | dest.writeMap(params); 61 | dest.writeInt(type); 62 | dest.writeBundle(extra); 63 | } 64 | 65 | public Bundle getExtra() { 66 | return extra; 67 | } 68 | 69 | public RouteRule getRule() { 70 | if (rule != null) { 71 | return rule; 72 | } 73 | 74 | switch (type) { 75 | case 0: 76 | rule = new ActivityRouteRule(name).setParams(params); 77 | break; 78 | default: 79 | rule = new ActionRouteRule(name).setParams(params); 80 | } 81 | return rule; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/RouteCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.module; 17 | 18 | import java.util.Map; 19 | 20 | /** 21 | * An interface to define route rules to router lib 22 | * @author haoge 23 | */ 24 | public interface RouteCreator { 25 | 26 | /** 27 | * create route rules for ActivityRoute 28 | * @return A map that contains of all Activity route rules. 29 | */ 30 | Map createActivityRouteRules(); 31 | 32 | /** 33 | * create route rules for ActionRoute 34 | * @return A map that contains of all Action route rules. 35 | */ 36 | Map createActionRouteRules(); 37 | 38 | Map createCreatorRouteRule(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/module/RouteRule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.module; 17 | 18 | import android.app.Activity; 19 | 20 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 21 | import com.lzh.nonview.router.launcher.Launcher; 22 | import com.lzh.nonview.router.route.ActionSupport; 23 | 24 | import java.util.HashMap; 25 | 26 | /** 27 | * An entity to contains some data for route 28 | * 29 | * @author haoge 30 | */ 31 | @SuppressWarnings("unchecked") 32 | public class RouteRule{ 33 | 34 | public RouteRule(String clzName) { 35 | this.clzName = clzName; 36 | } 37 | 38 | /** The class name must be subclass of {@link Activity} or {@link ActionSupport}*/ 39 | private String clzName; 40 | private HashMap params = new HashMap<>(); 41 | private Class launcher; 42 | private Class[] interceptors = new Class[0]; 43 | 44 | public String getRuleClz() { 45 | return clzName; 46 | } 47 | 48 | public HashMap getParams() { 49 | return params; 50 | } 51 | 52 | R setParams(HashMap params) { 53 | if (params != null) { 54 | this.params = params; 55 | } 56 | return (R) this; 57 | } 58 | 59 | /** 60 | * Set a serial of {@link RouteInterceptor} to used, it means when you launch this routing, the interceptors will be triggered. 61 | * @param classes The array of {@link RouteInterceptor} 62 | * @return RouteRule 63 | */ 64 | public R setInterceptors(Class ... classes) { 65 | if (classes != null) { 66 | this.interceptors = classes; 67 | } 68 | return (R) this; 69 | } 70 | 71 | public Class[] getInterceptors() { 72 | return interceptors; 73 | } 74 | 75 | public R setLauncher(Class launcher) { 76 | this.launcher = launcher; 77 | return (R) this; 78 | } 79 | 80 | public Class getLauncher() { 81 | return launcher; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/parser/URIParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.parser; 17 | 18 | import android.net.Uri; 19 | import android.text.TextUtils; 20 | 21 | import com.lzh.nonview.router.tools.Utils; 22 | 23 | import java.net.URLDecoder; 24 | import java.util.HashMap; 25 | import java.util.IdentityHashMap; 26 | import java.util.Map; 27 | 28 | /** 29 | * A parser to parse uri to scheme/host/params .etc 30 | * Created by lzh on 16/9/5. 31 | */ 32 | public class URIParser { 33 | 34 | private Uri uri; 35 | private String route; 36 | private Map params; 37 | 38 | public URIParser(Uri uri) { 39 | this.uri = uri; 40 | parse(); 41 | } 42 | 43 | private void parse() { 44 | this.route = Utils.format(uri.getScheme() + "://" + uri.getHost() + uri.getPath()); 45 | String query = uri.getEncodedQuery(); 46 | if (!TextUtils.isEmpty(query)) { 47 | params = parseParams(query); 48 | } else { 49 | params = new HashMap<>(); 50 | } 51 | } 52 | 53 | /** 54 | * Parse params form query string 55 | *

56 | * To support parse list to bundle,use {@link IdentityHashMap} to hold key-value 57 | *

58 | * @param query query in uri 59 | * @return a map contains key-value data parsed by query in uri 60 | */ 61 | static Map parseParams(String query) { 62 | Map params = new IdentityHashMap<>(); 63 | String[] split = query.split("&"); 64 | for (String param : split) { 65 | if (!param.contains("=")) { 66 | continue; 67 | } 68 | int index = param.indexOf("="); 69 | //noinspection RedundantStringConstructorCall 70 | params.put(new String(param.substring(0, index)), URLDecoder.decode(param.substring(index + 1))); 71 | } 72 | return params; 73 | } 74 | 75 | public Map getParams() { 76 | return params; 77 | } 78 | 79 | public String getRoute() { 80 | return route; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/protocol/HostServiceWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.protocol; 17 | 18 | import android.app.Service; 19 | import android.content.ComponentName; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.ServiceConnection; 23 | import android.net.Uri; 24 | import android.os.Bundle; 25 | import android.os.IBinder; 26 | import android.text.TextUtils; 27 | 28 | import com.lzh.nonview.router.RouterConfiguration; 29 | import com.lzh.nonview.router.module.RemoteRule; 30 | import com.lzh.nonview.router.module.RouteRule; 31 | import com.lzh.nonview.router.route.ActionRoute; 32 | import com.lzh.nonview.router.route.ActivityRoute; 33 | import com.lzh.nonview.router.route.IRoute; 34 | import com.lzh.nonview.router.route.InternalCallback; 35 | import com.lzh.nonview.router.tools.Cache; 36 | 37 | import java.util.HashMap; 38 | import java.util.Map; 39 | 40 | public class HostServiceWrapper { 41 | 42 | private static Context context; 43 | private static IService service; 44 | private static String pluginName; 45 | 46 | private static ServiceConnection connection = new ServiceConnection() { 47 | @Override 48 | public void onServiceConnected(ComponentName name, IBinder service) { 49 | HostServiceWrapper.service = IService.Stub.asInterface(service); 50 | // register rules to remote service. 51 | registerRulesToHostService(); 52 | } 53 | 54 | @Override 55 | public void onServiceDisconnected(ComponentName name) { 56 | HostServiceWrapper.service = null; 57 | } 58 | }; 59 | 60 | /** 61 | * Set a host package name. it will be used to bind a remote service in host app. 62 | * 63 | * @param hostPackage the package name of host. 64 | * @param context the context to start remote service. 65 | * @param pluginName The plugin name to register to remote service. to help to judge if it should be 66 | */ 67 | public static void startHostService(String hostPackage, Context context, String pluginName) { 68 | if (service != null) { 69 | throw new RuntimeException("You've bind a remote service before"); 70 | } 71 | if (TextUtils.isEmpty(hostPackage)) { 72 | throw new IllegalArgumentException("Please provide a valid host package name."); 73 | } 74 | HostServiceWrapper.context = context.getApplicationContext(); 75 | HostServiceWrapper.pluginName = TextUtils.isEmpty(pluginName) ? context.getPackageName() : pluginName; 76 | 77 | Intent intent = new Intent(); 78 | intent.setPackage(hostPackage); 79 | intent.setAction("com.lzh.router.action.HOST"); 80 | context.bindService(intent, connection, Service.BIND_AUTO_CREATE); 81 | } 82 | 83 | public static IRoute create(Uri uri, InternalCallback callback) { 84 | try { 85 | return createWithThrow(uri, callback); 86 | } catch (Exception e) { 87 | return new IRoute.EmptyRoute(callback); 88 | } 89 | } 90 | 91 | private static IRoute createWithThrow(Uri uri, InternalCallback callback) throws Exception{ 92 | RemoteRule rule; 93 | if ((rule = service.getActivityRule(uri)) != null) { 94 | return new ActivityRoute().create(uri, rule.getRule(), rule.getExtra(), callback); 95 | } else if ((rule = service.getActionRule(uri)) != null) { 96 | return new ActionRoute().create(uri, rule.getRule(), rule.getExtra(), callback); 97 | } else { 98 | return new IRoute.EmptyRoute(callback); 99 | } 100 | } 101 | 102 | public static boolean isRegister(String pluginName) { 103 | try { 104 | return service.isRegister(pluginName); 105 | } catch (Exception e) { 106 | return false; 107 | } 108 | } 109 | 110 | public static void registerRulesToHostService() { 111 | try { 112 | if (service == null) { 113 | return; 114 | } 115 | service.register(pluginName); 116 | service.addActionRules(transform(Cache.getActionRules())); 117 | service.addActivityRules(transform(Cache.getActivityRules())); 118 | } catch (Exception e) { 119 | // ignore 120 | } 121 | } 122 | 123 | private static Map transform(Map source){ 124 | Map dest = new HashMap<>(); 125 | for (String route : source.keySet()) { 126 | RouteRule rule = source.get(route); 127 | RemoteRule remote = RemoteRule.create(rule, getRemote(context, rule)); 128 | dest.put(route, remote); 129 | } 130 | return dest; 131 | } 132 | 133 | private static Bundle getRemote(Context context, RouteRule rule){ 134 | IRemoteFactory factory = RouterConfiguration.get().getRemoteFactory(); 135 | return factory == null ? null : factory.createRemote(context, rule); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/protocol/IRemoteFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.protocol; 17 | 18 | import android.content.Context; 19 | import android.os.Bundle; 20 | 21 | import com.lzh.nonview.router.RouterConfiguration; 22 | import com.lzh.nonview.router.module.RouteRule; 23 | 24 | /** 25 | *

26 | * This factory used to create and provide a remote bundle data. 27 | *

28 | * 29 | *

When need to register the routing rules to remote bridge service via {@link RouterConfiguration#startHostService(String, Context)}, 30 | * the factory will be called to create a bundle and pass it to remote service from aidl interface. 31 | */ 32 | public interface IRemoteFactory { 33 | /** 34 | * Create a extra bundle data so that others process or plugin could compat. 35 | * @param application The application context. 36 | * @param rule The routing rule 37 | * @return new extra bundle or null. 38 | */ 39 | Bundle createRemote(Context application, RouteRule rule); 40 | } 41 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/ActionRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import com.lzh.nonview.router.RouterConfiguration; 19 | import com.lzh.nonview.router.launcher.ActionLauncher; 20 | import com.lzh.nonview.router.launcher.Launcher; 21 | import com.lzh.nonview.router.module.ActionRouteRule; 22 | import com.lzh.nonview.router.tools.Constants; 23 | 24 | import java.util.concurrent.Executor; 25 | 26 | public class ActionRoute extends BaseRoute implements IActionRoute { 27 | 28 | @Override 29 | protected Launcher obtainLauncher() throws Exception{ 30 | ActionRouteRule rule = (ActionRouteRule) routeRule; 31 | Class launcher = rule.getLauncher(); 32 | if (launcher == null) { 33 | launcher = RouterConfiguration.get().getActionLauncher(); 34 | } 35 | return launcher.newInstance(); 36 | } 37 | 38 | @Override 39 | public void setExecutor(Executor executor) { 40 | callback.getExtras().putValue(Constants.KEY_ACTION_EXECUTOR, executor); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/ActionSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.content.Context; 19 | import android.os.Bundle; 20 | 21 | /** 22 | *

You can inherit from this class to create action routing event. 23 | * 24 | * @author haoge 25 | */ 26 | public abstract class ActionSupport { 27 | 28 | /** 29 | * The callback method to received routing bundle data. 30 | * @param context The context who launch the routing event. 31 | * @param bundle The extras bundle data from {@link IBaseRoute#addExtras(Bundle)} and url parameters. 32 | */ 33 | public abstract void onRouteTrigger(Context context, Bundle bundle); 34 | } 35 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/ActivityRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.app.Fragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | 23 | import com.lzh.nonview.router.RouterConfiguration; 24 | import com.lzh.nonview.router.activityresult.ActivityResultCallback; 25 | import com.lzh.nonview.router.launcher.ActivityLauncher; 26 | import com.lzh.nonview.router.launcher.Launcher; 27 | import com.lzh.nonview.router.module.ActivityRouteRule; 28 | import com.lzh.nonview.router.tools.Constants; 29 | import com.lzh.nonview.router.tools.Utils; 30 | 31 | /** 32 | * A route tool to check route rule by uri and launch activity 33 | * Created by lzh on 16/9/5. 34 | */ 35 | public class ActivityRoute extends BaseRoute implements IActivityRoute { 36 | 37 | @Override 38 | public Intent createIntent(Context context) { 39 | ActivityLauncher activityLauncher = (ActivityLauncher) launcher; 40 | activityLauncher.set(uri, bundle, callback.getExtras(), routeRule, remote); 41 | return activityLauncher.createIntent(context); 42 | } 43 | 44 | @Override 45 | public IActivityRoute requestCode(int requestCode) { 46 | this.callback.getExtras().setRequestCode(requestCode); 47 | return this; 48 | } 49 | 50 | @Override 51 | public IActivityRoute resultCallback(ActivityResultCallback callback) { 52 | this.callback.getExtras().putValue(Constants.KEY_RESULT_CALLBACK, callback); 53 | return this; 54 | } 55 | 56 | @Override 57 | public IActivityRoute setOptions(Bundle options) { 58 | this.callback.getExtras().putValue(Constants.KEY_ACTIVITY_OPTIONS, options); 59 | return this; 60 | } 61 | 62 | @Override 63 | public IActivityRoute setAnim(int enterAnim, int exitAnim) { 64 | this.callback.getExtras().setInAnimation(enterAnim); 65 | this.callback.getExtras().setOutAnimation(exitAnim); 66 | return this; 67 | } 68 | 69 | @Override 70 | public IActivityRoute addFlags(int flag) { 71 | this.callback.getExtras().addFlags(flag); 72 | return this; 73 | } 74 | 75 | @Override 76 | public void open(Fragment fragment) { 77 | try { 78 | Utils.checkInterceptor(uri, callback.getExtras(), fragment.getActivity(), getInterceptors()); 79 | ActivityLauncher activityLauncher = (ActivityLauncher) launcher; 80 | activityLauncher.set(uri, bundle, callback.getExtras(), routeRule, remote); 81 | activityLauncher.open(fragment); 82 | callback.onOpenSuccess(routeRule); 83 | } catch (Throwable e) { 84 | callback.onOpenFailed(e); 85 | } 86 | 87 | callback.invoke(fragment.getActivity()); 88 | } 89 | 90 | @Override 91 | protected Launcher obtainLauncher() throws Exception{ 92 | ActivityRouteRule rule = (ActivityRouteRule) routeRule; 93 | Class launcher = rule.getLauncher(); 94 | if (launcher == null) { 95 | launcher = RouterConfiguration.get().getActivityLauncher(); 96 | } 97 | return launcher.newInstance(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/BaseRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.content.Context; 19 | import android.net.Uri; 20 | import android.os.Bundle; 21 | 22 | import com.lzh.nonview.router.Router; 23 | import com.lzh.nonview.router.RouterConfiguration; 24 | import com.lzh.nonview.router.extras.RouteBundleExtras; 25 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 26 | import com.lzh.nonview.router.interceptors.RouteInterceptorAction; 27 | import com.lzh.nonview.router.launcher.Launcher; 28 | import com.lzh.nonview.router.module.RouteRule; 29 | import com.lzh.nonview.router.parser.URIParser; 30 | import com.lzh.nonview.router.tools.Cache; 31 | import com.lzh.nonview.router.tools.Utils; 32 | 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | 36 | @SuppressWarnings("unchecked") 37 | public abstract class BaseRoute implements IRoute, IBaseRoute, RouteInterceptorAction { 38 | protected Bundle bundle; 39 | InternalCallback callback; 40 | protected Uri uri; 41 | protected Bundle remote; 42 | protected RouteRule routeRule = null; 43 | protected Launcher launcher; 44 | 45 | public final IRoute create(Uri uri, RouteRule rule, Bundle remote, InternalCallback callback) { 46 | try { 47 | this.uri = uri; 48 | this.remote = remote; 49 | this.callback = callback; 50 | this.routeRule = rule; 51 | this.bundle = Utils.parseToBundle(new URIParser(uri)); 52 | this.bundle.putParcelable(Router.RAW_URI, uri); 53 | this.launcher = obtainLauncher(); 54 | return this; 55 | } catch (Throwable e) { 56 | callback.onOpenFailed(e); 57 | return new EmptyRoute(callback); 58 | } 59 | } 60 | 61 | // =========Unify method of IBaseRoute 62 | @Override 63 | public final void open(Context context) { 64 | try { 65 | Utils.checkInterceptor(uri, callback.getExtras(), context,getInterceptors()); 66 | launcher.set(uri, bundle, callback.getExtras(), routeRule, remote); 67 | launcher.open(context); 68 | // realOpen(context); 69 | callback.onOpenSuccess(routeRule); 70 | } catch (Throwable e) { 71 | callback.onOpenFailed(e); 72 | } 73 | 74 | callback.invoke(context); 75 | } 76 | 77 | @Override 78 | public T addExtras(Bundle extras) { 79 | this.callback.getExtras().addExtras(extras); 80 | return (T) this; 81 | } 82 | 83 | // =============RouteInterceptor operation=============== 84 | public T addInterceptor(RouteInterceptor interceptor) { 85 | if (callback.getExtras() != null) { 86 | callback.getExtras().addInterceptor(interceptor); 87 | } 88 | return (T) this; 89 | } 90 | 91 | @Override 92 | public T removeInterceptor(RouteInterceptor interceptor) { 93 | if (callback.getExtras() != null) { 94 | callback.getExtras().removeInterceptor(interceptor); 95 | } 96 | return (T) this; 97 | } 98 | 99 | @Override 100 | public T removeAllInterceptors() { 101 | if (callback.getExtras() != null) { 102 | callback.getExtras().removeAllInterceptors(); 103 | } 104 | return (T) this; 105 | } 106 | 107 | @Override 108 | public List getInterceptors() { 109 | 110 | List interceptors = new ArrayList<>(); 111 | // add global interceptor 112 | if (RouterConfiguration.get().getInterceptor() != null) { 113 | interceptors.add(RouterConfiguration.get().getInterceptor()); 114 | } 115 | 116 | // add extra interceptors 117 | if (callback.getExtras() != null) { 118 | interceptors.addAll(callback.getExtras().getInterceptors()); 119 | } 120 | 121 | // add interceptors in rule 122 | for (Class interceptor : routeRule.getInterceptors()) { 123 | if (interceptor != null) { 124 | try { 125 | interceptors.add(interceptor.newInstance()); 126 | } catch (Exception e) { 127 | throw new RuntimeException(String.format("The interceptor class [%s] should provide a default empty construction", interceptor)); 128 | } 129 | } 130 | } 131 | 132 | return interceptors; 133 | } 134 | 135 | // ========getter/setter============ 136 | public void replaceExtras(RouteBundleExtras extras) { 137 | this.callback.setExtras(extras); 138 | } 139 | 140 | public static RouteRule findRule(Uri uri, int type) { 141 | return Cache.getRouteMapByUri(new URIParser(uri), type); 142 | } 143 | 144 | // ============abstract methods============ 145 | protected abstract Launcher obtainLauncher() throws Exception; 146 | 147 | } 148 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/BrowserRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.net.Uri; 21 | 22 | import com.lzh.nonview.router.tools.Utils; 23 | 24 | /** 25 | * A route tool to open uri by browser 26 | * Created by lzh on 16/9/5. 27 | */ 28 | public class BrowserRoute implements IRoute { 29 | 30 | Uri uri; 31 | 32 | private static final BrowserRoute route = new BrowserRoute(); 33 | 34 | public static BrowserRoute getInstance () { 35 | return route; 36 | } 37 | 38 | @Override 39 | public void open(Context context) { 40 | Intent intent = new Intent(Intent.ACTION_VIEW,uri); 41 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 42 | context.startActivity(intent); 43 | } 44 | 45 | public static boolean canOpenRouter(Uri uri) { 46 | return Utils.isHttp(uri.getScheme()); 47 | } 48 | 49 | public IRoute setUri(Uri uri) { 50 | this.uri = uri; 51 | return this; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/IActionRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import java.util.concurrent.Executor; 19 | 20 | /** 21 | *

22 | * Base on the {@link IBaseRoute} 23 | *

24 | */ 25 | public interface IActionRoute extends IBaseRoute{ 26 | 27 | void setExecutor(Executor executor); 28 | 29 | class EmptyActionRoute extends EmptyBaseRoute implements IActionRoute { 30 | 31 | public EmptyActionRoute(InternalCallback internal) { 32 | super(internal); 33 | } 34 | 35 | @Override 36 | public void setExecutor(Executor executor) { } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/IActivityRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.app.Fragment; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | 23 | import com.lzh.nonview.router.activityresult.ActivityResultCallback; 24 | import com.lzh.nonview.router.extras.RouteBundleExtras; 25 | import com.lzh.nonview.router.tools.Constants; 26 | 27 | /** 28 | *

29 | * Base on the {@link IBaseRoute}, This interface provided some methods 30 | * to set some extras data for used by {@link android.app.Activity#startActivityForResult(Intent, int)} 31 | *

32 | */ 33 | public interface IActivityRoute extends IBaseRoute { 34 | 35 | /** 36 | * Create intent by {@link RouteBundleExtras} and {@link Bundle} that parsed by uri 37 | * @param context The context to create intent 38 | * @return Intent that contains of extras data and bundle that parsed by uri 39 | */ 40 | Intent createIntent (Context context); 41 | 42 | /** 43 | * Set request code for {@link android.app.Activity#startActivityForResult(Intent, int)} 44 | * @param requestCode request code 45 | * @return IActivityRoute 46 | */ 47 | IActivityRoute requestCode(int requestCode); 48 | 49 | IActivityRoute resultCallback(ActivityResultCallback callback); 50 | 51 | IActivityRoute setOptions(Bundle options); 52 | 53 | /** 54 | * Set anim for {@link android.app.Activity#overridePendingTransition(int, int)} 55 | * @param enterAnim enter animation 56 | * @param exitAnim exit animation 57 | * @return IActivityRoute 58 | */ 59 | IActivityRoute setAnim (int enterAnim, int exitAnim); 60 | 61 | /** 62 | * Associate with {@link Intent#addFlags(int)} 63 | * @param flag flag 64 | * @return IActivityRoute 65 | */ 66 | IActivityRoute addFlags(int flag); 67 | 68 | /** 69 | * Launch routing by {@link Fragment} 70 | * @param fragment the fragment to startActivity 71 | */ 72 | void open(Fragment fragment); 73 | 74 | class EmptyActivityRoute extends EmptyBaseRoute implements IActivityRoute { 75 | 76 | public EmptyActivityRoute(InternalCallback internal) { 77 | super(internal); 78 | } 79 | 80 | @Override 81 | public Intent createIntent(Context context) { 82 | internal.invoke(context); 83 | return new Intent(); 84 | } 85 | 86 | @Override 87 | public IActivityRoute requestCode(int requestCode) { 88 | internal.getExtras().setRequestCode(requestCode); 89 | return this; 90 | } 91 | 92 | @Override 93 | public IActivityRoute resultCallback(ActivityResultCallback callback) { 94 | internal.getExtras().putValue(Constants.KEY_RESULT_CALLBACK, callback); 95 | return this; 96 | } 97 | 98 | @Override 99 | public IActivityRoute setOptions(Bundle options) { 100 | internal.getExtras().putValue(Constants.KEY_ACTIVITY_OPTIONS, options); 101 | return this; 102 | } 103 | 104 | @Override 105 | public IActivityRoute setAnim(int enterAnim, int exitAnim) { 106 | internal.getExtras().setInAnimation(enterAnim); 107 | internal.getExtras().setOutAnimation(exitAnim); 108 | return this; 109 | } 110 | 111 | @Override 112 | public IActivityRoute addFlags(int flag) { 113 | internal.getExtras().addFlags(flag); 114 | return this; 115 | } 116 | 117 | @Override 118 | public void open(Fragment fragment) { 119 | internal.invoke(fragment.getActivity()); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/IBaseRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.os.Bundle; 19 | 20 | import com.lzh.nonview.router.extras.RouteBundleExtras; 21 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 22 | import com.lzh.nonview.router.interceptors.RouteInterceptorAction; 23 | 24 | import java.util.List; 25 | 26 | /** 27 | * Base on {@link IRoute} and {@link RouteInterceptorAction}, it subclass could be one of the
28 | * {@link IActionRoute} and {@link IActivityRoute} 29 | * @param The real type 30 | */ 31 | public interface IBaseRoute extends IRoute, RouteInterceptorAction{ 32 | /** 33 | * add extra bundle data to {@link RouteBundleExtras} 34 | * @param extras bundle data 35 | * @return {@link IBaseRoute} 36 | * @see IActionRoute 37 | * @see IActivityRoute 38 | */ 39 | T addExtras(Bundle extras); 40 | 41 | /** 42 | * Add a interceptor to container 43 | * @param interceptor interceptor instance 44 | * @return The real type 45 | */ 46 | T addInterceptor (RouteInterceptor interceptor); 47 | 48 | /** 49 | * Remove a interceptor from container 50 | * @param interceptor interceptor instance 51 | * @return The real type 52 | */ 53 | T removeInterceptor (RouteInterceptor interceptor); 54 | 55 | /** 56 | * remove all of interceptors you has set before 57 | * @return The real type 58 | */ 59 | T removeAllInterceptors (); 60 | 61 | /** 62 | * get all interceptors you has set before 63 | * @return all of interceptors 64 | */ 65 | List getInterceptors (); 66 | 67 | @SuppressWarnings("unchecked") 68 | class EmptyBaseRoute extends EmptyRoute implements IBaseRoute { 69 | 70 | public EmptyBaseRoute(InternalCallback internal) { 71 | super(internal); 72 | } 73 | 74 | @Override 75 | public T addExtras(Bundle extras) { 76 | internal.getExtras().addExtras(extras); 77 | return (T) this; 78 | } 79 | 80 | @Override 81 | public T addInterceptor(RouteInterceptor interceptor) { 82 | internal.getExtras().addInterceptor(interceptor); 83 | return (T) this; 84 | } 85 | 86 | @Override 87 | public T removeInterceptor(RouteInterceptor interceptor) { 88 | internal.getExtras().removeInterceptor(interceptor); 89 | return (T) this; 90 | } 91 | 92 | @Override 93 | public T removeAllInterceptors() { 94 | internal.getExtras().removeAllInterceptors(); 95 | return (T) this; 96 | } 97 | 98 | @Override 99 | public List getInterceptors() { 100 | return internal.getExtras().getInterceptors(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/ICreatorInjector.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.route; 2 | 3 | import android.os.Bundle; 4 | 5 | /** 6 | * @author haoge on 2018/5/25 7 | */ 8 | public interface ICreatorInjector { 9 | void inject(Bundle bundle); 10 | } 11 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/IRoute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.content.Context; 19 | 20 | /** 21 | * The top interface of routing operations. The subclass could be:
22 | * {@link BrowserRoute} / {@link IActionRoute} or {@link IActivityRoute} 23 | */ 24 | public interface IRoute { 25 | 26 | /** 27 | * open route with uri by context 28 | * @param context The context to launch routing event 29 | */ 30 | void open(Context context); 31 | 32 | class EmptyRoute implements IRoute{ 33 | protected InternalCallback internal; 34 | 35 | public EmptyRoute(InternalCallback internal) { 36 | this.internal = internal; 37 | } 38 | 39 | public InternalCallback getInternal() { 40 | return internal; 41 | } 42 | 43 | @Override 44 | public void open(Context context) { 45 | internal.invoke(context); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/InternalCallback.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.route; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | import android.util.Pair; 6 | 7 | import com.lzh.nonview.router.RouterConfiguration; 8 | import com.lzh.nonview.router.exception.NotFoundException; 9 | import com.lzh.nonview.router.extras.RouteBundleExtras; 10 | import com.lzh.nonview.router.module.RouteRule; 11 | import com.lzh.nonview.router.tools.RouterLog; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | *

18 | * Internal route callback. 19 | *

20 | */ 21 | public final class InternalCallback { 22 | 23 | // store the map to provided find extras for uri. 24 | private static Map> cache = new HashMap<>(); 25 | 26 | private Uri uri; 27 | private RouteBundleExtras extras = new RouteBundleExtras(); 28 | private RouteRule rule; 29 | private Throwable error; 30 | 31 | public InternalCallback(Uri uri) { 32 | this.uri = uri; 33 | } 34 | 35 | public void setCallback(RouteCallback callback) { 36 | extras.setCallback(callback); 37 | } 38 | 39 | public RouteBundleExtras getExtras() { 40 | return extras; 41 | } 42 | 43 | public void setExtras(RouteBundleExtras extras) { 44 | if (extras != null) { 45 | this.extras = extras; 46 | } 47 | } 48 | 49 | public void onOpenSuccess(RouteRule rule) { 50 | this.rule = rule; 51 | } 52 | 53 | public void onOpenFailed(Throwable e) { 54 | if (error == null) { 55 | // 只接受第一次配置的异常 56 | this.error = e; 57 | } 58 | } 59 | 60 | void invoke(Context context) { 61 | cache.put(uri, new Pair<>(context, extras)); 62 | invokeWithCallback(RouterConfiguration.get().getCallback(), 63 | extras.getCallback()); 64 | cache.remove(uri); 65 | } 66 | 67 | private void invokeWithCallback(RouteCallback global, RouteCallback callback) { 68 | if (error != null && error instanceof NotFoundException) { 69 | RouterLog.d("[RouterLog] Could not found matched route for " + uri); 70 | if (global != null) { 71 | global.notFound(uri, (NotFoundException) error); 72 | } 73 | if (callback != null) { 74 | callback.notFound(uri, (NotFoundException) error); 75 | } 76 | } else if (error != null) { 77 | RouterLog.e("[RouterLog] Launch route with " + uri + " failed.", error); 78 | if (global != null) { 79 | global.onOpenFailed(uri, error); 80 | } 81 | if (callback != null) { 82 | callback.onOpenFailed(uri, error); 83 | } 84 | } else if (rule != null) { 85 | RouterLog.d("[RouterLog] Launch route with " + uri + " successful!, target class name is " + rule.getRuleClz()); 86 | if (global != null) { 87 | global.onOpenSuccess(uri, rule); 88 | } 89 | if (callback != null) { 90 | callback.onOpenSuccess(uri, rule); 91 | } 92 | } else { 93 | RouterLog.e("[RouterLog] Launch route with " + uri + " failed.", null); 94 | if (global != null) { 95 | global.onOpenFailed(uri, new RuntimeException("Unknown error")); 96 | } 97 | if (callback != null) { 98 | callback.onOpenFailed(uri, new RuntimeException("Unknown error")); 99 | } 100 | } 101 | } 102 | 103 | public static RouteBundleExtras findExtrasByUri(Uri uri) { 104 | Pair pair = cache.get(uri); 105 | return pair == null? null : pair.second; 106 | } 107 | 108 | public static Context findContextByUri(Uri uri) { 109 | Pair pair = cache.get(uri); 110 | return pair == null? null : pair.first; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/route/RouteCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.route; 17 | 18 | import android.net.Uri; 19 | 20 | import com.lzh.nonview.router.exception.NotFoundException; 21 | import com.lzh.nonview.router.module.ActionRouteRule; 22 | import com.lzh.nonview.router.module.ActivityRouteRule; 23 | import com.lzh.nonview.router.module.RouteRule; 24 | 25 | /** 26 | * The route callback to notify the status of routing event. 27 | * @author haoge 28 | */ 29 | public interface RouteCallback { 30 | 31 | /** 32 | * This method will be invoked when there is no routing matched with uri. 33 | * @param uri uri the uri to open 34 | * @param e {@link NotFoundException} 35 | */ 36 | void notFound(Uri uri, NotFoundException e); 37 | 38 | /** 39 | * This method will be invoked when the routing task opened successful 40 | * 41 | * @param uri the uri to open 42 | * @param rule The uri matching rule, it could be {@link ActionRouteRule} or {@link ActivityRouteRule} 43 | */ 44 | void onOpenSuccess(Uri uri, RouteRule rule); 45 | 46 | /** 47 | * A callback method to notice that you occurs some exception.
48 | * exclude {@link NotFoundException} 49 | * @param uri the uri to open 50 | * @param e the exception 51 | */ 52 | void onOpenFailed(Uri uri, Throwable e); 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/tools/Cache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.tools; 17 | 18 | import com.lzh.nonview.router.executors.MainThreadExecutor; 19 | import com.lzh.nonview.router.module.ActionRouteRule; 20 | import com.lzh.nonview.router.module.ActivityRouteRule; 21 | import com.lzh.nonview.router.module.CreatorRouteRule; 22 | import com.lzh.nonview.router.module.RouteCreator; 23 | import com.lzh.nonview.router.module.RouteRule; 24 | import com.lzh.nonview.router.parser.URIParser; 25 | 26 | import java.util.ArrayList; 27 | import java.util.HashMap; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.concurrent.Executor; 31 | 32 | /** 33 | * The cache manager to holds all the cached instance. 34 | * @author haoge 35 | */ 36 | public final class Cache { 37 | 38 | private static boolean shouldReload;// if should be reload routeMap. 39 | /** A container to contains all of route rule creator,compat with some complex scene*/ 40 | private static List creatorList = new ArrayList<>(); 41 | /** A map to contains all of route rule created by creatorList*/ 42 | private static Map activityRouteMap = new HashMap<>(); 43 | private static Map actionRouteMap = new HashMap<>(); 44 | private static Map creatorRouteMap = new HashMap<>(); 45 | public static final int TYPE_ACTIVITY_ROUTE = 0; 46 | public static final int TYPE_ACTION_ROUTE = 1; 47 | 48 | private final static Map, Executor> container = new HashMap<>(); 49 | 50 | /** 51 | *

52 | * Add a {@link RouteCreator} who contains some route rules to be used. 53 | * this method could be invoked multiple-times. so that you can put multiple route rules from difference modules 54 | *

55 | * @param creator {@link RouteCreator} 56 | */ 57 | public static void addCreator (RouteCreator creator) { 58 | if (creator == null) { 59 | throw new IllegalArgumentException("Route creator should not be null"); 60 | } 61 | creatorList.add(creator); 62 | shouldReload = true; 63 | } 64 | 65 | public static Map getCreatorRules() { 66 | obtainRouteRulesIfNeed(); 67 | return creatorRouteMap; 68 | } 69 | 70 | public static Map getActionRules() { 71 | obtainRouteRulesIfNeed(); 72 | return actionRouteMap; 73 | } 74 | 75 | public static Map getActivityRules() { 76 | obtainRouteRulesIfNeed(); 77 | return activityRouteMap; 78 | } 79 | 80 | public static RouteRule getRouteMapByUri(URIParser parser, int type) { 81 | String route = parser.getRoute(); 82 | Map routes; 83 | if (type == TYPE_ACTIVITY_ROUTE) { 84 | routes = getActivityRules(); 85 | } else { 86 | routes = getActionRules(); 87 | } 88 | return (RouteRule) routes.get(route); 89 | } 90 | 91 | private static void obtainRouteRulesIfNeed() { 92 | if (shouldReload) { 93 | activityRouteMap.clear(); 94 | actionRouteMap.clear(); 95 | creatorRouteMap.clear(); 96 | int count = creatorList == null ? 0 : creatorList.size(); 97 | for (int i = 0; i < count; i++) { 98 | try { 99 | addAll(activityRouteMap, creatorList.get(i).createActivityRouteRules()); 100 | addAll(actionRouteMap, creatorList.get(i).createActionRouteRules()); 101 | addAll(creatorRouteMap, creatorList.get(i).createCreatorRouteRule()); 102 | } catch (AbstractMethodError error) { 103 | // ignore 兼容早期没有createCreatorRouteRule的结构 104 | } 105 | } 106 | shouldReload = false; 107 | } 108 | } 109 | 110 | private static void addAll(Map src, Map target) { 111 | if (target == null || src == null) { 112 | return; 113 | } 114 | for (Map.Entry entry : target.entrySet()) { 115 | src.put(Utils.format(entry.getKey()), entry.getValue()); 116 | } 117 | } 118 | 119 | public static Executor findOrCreateExecutor(Class key) { 120 | try { 121 | Executor executor = container.get(key); 122 | if (executor == null) { 123 | executor = key.newInstance(); 124 | registerExecutors(key, executor); 125 | } 126 | return executor; 127 | } catch (Throwable t) { 128 | // provided MainThreadExecutor if occurs an error. 129 | return new MainThreadExecutor(); 130 | } 131 | } 132 | 133 | /** 134 | * To register an Executor to be used. 135 | * @param key The class of Executor 136 | * @param value The Executor instance associate with the key. 137 | */ 138 | @SuppressWarnings("WeakerAccess") 139 | public static void registerExecutors(Class key, Executor value) { 140 | if (key == null || value == null) { 141 | return; 142 | } 143 | 144 | container.remove(key); 145 | container.put(key, value); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/tools/CacheStore.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.tools; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 进行临时性存储。方便将不方便放入Intent中进行存储的数据进行存储: 7 | * 8 | * 9 | *
10 |  * // 举例:跨页面传递Context
11 |  *
12 |  * // 跳转前存储context
13 |  * Intent intent = getIntent();
14 |  * int index = CacheStore.get().put(context);
15 |  * intent.putExtra(KEY_INDEX_CONTEXT, index);
16 |  * startActivity(intent);
17 |  *
18 |  * // 跳转后读取context
19 |  * Intent intent = getIntent();
20 |  * int index = intent.getExtra(KEY_INDEX_CONTEXT);
21 |  * // 读取后自动从CacheStore容器中移除。
22 |  * Context context = CacheStore.get().get(index);
23 |  * 
24 | * Created by haoge on 2018/5/3. 25 | */ 26 | public class CacheStore { 27 | 28 | private Object[] stores = new Object[10]; 29 | 30 | private static CacheStore INSTANCE = new CacheStore(); 31 | private CacheStore(){} 32 | public static CacheStore get() { 33 | return INSTANCE; 34 | } 35 | 36 | public T get(int index) { 37 | if (index < 0 || index >= stores.length) { 38 | return null; 39 | } 40 | Object value = stores[index]; 41 | stores[index] = null; 42 | try { 43 | //noinspection unchecked 44 | return (T) value; 45 | } catch (ClassCastException cast) { 46 | return null; 47 | } 48 | } 49 | 50 | public int put(Object value) { 51 | if (value == null) { 52 | return -1; 53 | } 54 | int index = findIndex(value); 55 | stores[index] = value; 56 | return index; 57 | } 58 | 59 | private int findIndex(Object value) { 60 | int firstEmptyIndex = -1; 61 | for (int i = 0; i < stores.length; i++) { 62 | Object item = stores[i]; 63 | if (item == null && firstEmptyIndex == -1) { 64 | firstEmptyIndex = i; 65 | } 66 | 67 | if (item == value) { 68 | return i; 69 | } 70 | } 71 | 72 | if (firstEmptyIndex == -1) { 73 | // 到此说明容器已满,需要扩容。定每次扩容大小为10 74 | int lastLength = stores.length; 75 | stores = Arrays.copyOf(stores, lastLength + 10); 76 | return lastLength; 77 | } 78 | // 返回首个空闲元素索引值。 79 | return firstEmptyIndex; 80 | } 81 | } -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/tools/Constants.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.tools; 2 | 3 | public interface Constants { 4 | String KEY_RESUME_CONTEXT = "ROUTER-KEY:RESUME_CONTEXT"; 5 | String KEY_RESULT_CALLBACK = "ROUTER-KEY:RESULT_CALLBACK"; 6 | String KEY_ACTION_EXECUTOR = "ROUTER-KEY:ACTION_EXECUTOR"; 7 | String KEY_ACTIVITY_OPTIONS = "ROUTER-KEY:ACTIVITY_OPTIONS"; 8 | } 9 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/tools/RouterLog.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.tools; 2 | 3 | import android.util.Log; 4 | 5 | import com.lzh.nonview.router.Router; 6 | 7 | public final class RouterLog { 8 | private static final String TAG = "RouterLog"; 9 | 10 | public static void d(String message) { 11 | if (Router.DEBUG) { 12 | Log.d(TAG, message); 13 | } 14 | } 15 | public static void e(String message, Throwable t) { 16 | if (Router.DEBUG) { 17 | Log.e(TAG, message, t); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /router-api/src/main/java/com/lzh/nonview/router/tools/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.tools; 17 | 18 | import android.app.Activity; 19 | import android.content.Context; 20 | import android.net.Uri; 21 | import android.os.Build; 22 | import android.os.Bundle; 23 | import android.text.TextUtils; 24 | 25 | import com.lzh.nonview.router.exception.InterceptorException; 26 | import com.lzh.nonview.router.extras.RouteBundleExtras; 27 | import com.lzh.nonview.router.interceptors.RouteInterceptor; 28 | import com.lzh.nonview.router.parser.URIParser; 29 | 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.Set; 33 | 34 | @SuppressWarnings("unchecked") 35 | public class Utils { 36 | 37 | /** 38 | * Adjust if the scheme is http or https 39 | * @param scheme scheme for uri 40 | * @return return true if is http or https 41 | */ 42 | public static boolean isHttp (String scheme) { 43 | return "http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme); 44 | } 45 | 46 | public static String format(String url) { 47 | if (url.endsWith("/")){ 48 | return url.substring(0, url.length() - 1); 49 | } 50 | return url; 51 | } 52 | 53 | public static void checkInterceptor(Uri uri, RouteBundleExtras extras, Context context, List interceptors) { 54 | for (RouteInterceptor interceptor : interceptors) { 55 | if (interceptor.intercept(uri,extras,context)) { 56 | extras.putValue(Constants.KEY_RESUME_CONTEXT, context); 57 | interceptor.onIntercepted(uri,extras,context); 58 | throw new InterceptorException(interceptor); 59 | } 60 | } 61 | } 62 | 63 | public static Bundle parseToBundle(URIParser parser) { 64 | Bundle bundle = new Bundle(); 65 | Map params = parser.getParams(); 66 | Set keySet = params.keySet(); 67 | for (String key : keySet) { 68 | bundle.putString(key, params.get(key)); 69 | } 70 | return bundle; 71 | } 72 | 73 | public static boolean isValid(Activity activity) { 74 | return activity != null 75 | && !activity.isFinishing() 76 | && !(Build.VERSION.SDK_INT >= 17 && activity.isDestroyed()); 77 | } 78 | 79 | public static boolean isValidUri(Uri uri) { 80 | return uri != null && !TextUtils.isEmpty(uri.getScheme()) && !TextUtils.isEmpty(uri.getHost()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /router-compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /router-compiler/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | dependencies { 5 | implementation 'com.squareup:javapoet:1.7.0' 6 | implementation project(':router-anno') 7 | } 8 | 9 | targetCompatibility = '1.7' 10 | sourceCompatibility = '1.7' 11 | 12 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler; 2 | 3 | import com.lzh.nonview.router.anno.RouteConfig; 4 | import com.lzh.nonview.router.anno.RouterRule; 5 | import com.lzh.nonview.router.compiler.exception.RouterException; 6 | import com.lzh.nonview.router.compiler.factory.RuleFactory; 7 | import com.lzh.nonview.router.compiler.model.BasicConfigurations; 8 | import com.lzh.nonview.router.compiler.model.Parser; 9 | import com.lzh.nonview.router.compiler.model.RouteRuleConfig; 10 | import com.lzh.nonview.router.compiler.util.UtilMgr; 11 | import com.lzh.nonview.router.compiler.util.Utils; 12 | import com.squareup.javapoet.ClassName; 13 | 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.HashSet; 17 | import java.util.Iterator; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.Set; 21 | 22 | import javax.annotation.processing.AbstractProcessor; 23 | import javax.annotation.processing.ProcessingEnvironment; 24 | import javax.annotation.processing.RoundEnvironment; 25 | import javax.lang.model.SourceVersion; 26 | import javax.lang.model.element.Element; 27 | import javax.lang.model.element.TypeElement; 28 | import javax.tools.Diagnostic; 29 | 30 | /** 31 | * The entry class of annotation processor 32 | */ 33 | public class Compiler extends AbstractProcessor{ 34 | @Override 35 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 36 | try { 37 | BasicConfigurations config = processRouteConfig(roundEnv); 38 | processRouteRules(roundEnv, config); 39 | return false; 40 | } catch (RouterException e) { 41 | e.printStackTrace(); 42 | error(e.getElement(),e.getMessage()); 43 | return true; 44 | } 45 | } 46 | 47 | /** 48 | * Parse the {@link RouteConfig} and create a {@link BasicConfigurations} to be used. 49 | * @param roundEnv data sources 50 | * @return The instance of {@link BasicConfigurations} 51 | * @throws RouterException pack all of the exception when a error occurs. 52 | */ 53 | private BasicConfigurations processRouteConfig(RoundEnvironment roundEnv) throws RouterException{ 54 | TypeElement type = null; 55 | try { 56 | Set elements = roundEnv.getElementsAnnotatedWith(RouteConfig.class); 57 | Iterator iterator = elements.iterator(); 58 | BasicConfigurations configurations = null; 59 | while (iterator.hasNext()) { 60 | type = (TypeElement) iterator.next(); 61 | if (configurations != null) { 62 | throw new RouterException("The RouteConfig in this module was defined duplicated!",type); 63 | } 64 | if (!Utils.isSuperClass(type,Constants.CLASSNAME_APPLICATION)) { 65 | throw new RouterException("The class you are annotated by RouteConfig must be a Application",type); 66 | } 67 | RouteConfig config = type.getAnnotation(RouteConfig.class); 68 | configurations = new BasicConfigurations(config); 69 | } 70 | return configurations == null ? new BasicConfigurations(null) : configurations; 71 | } catch (RouterException e) { 72 | throw e; 73 | } catch (Throwable e) { 74 | throw new RouterException(e.getMessage(),e,type); 75 | } 76 | } 77 | 78 | /** 79 | * Parse all of the elements that annotated by {@link RouterRule}. and combines the {@link BasicConfigurations} to create new java file. 80 | * @param roundEnv The data sources 81 | * @param config The instance of {@link BasicConfigurations} that be parsed by {@link Compiler#processRouteConfig(RoundEnvironment)} 82 | * @throws RouterException pack all of the exception when a error occurs. 83 | */ 84 | private void processRouteRules(RoundEnvironment roundEnv, BasicConfigurations config) throws RouterException{ 85 | List parsers = new ArrayList<>(); 86 | Set elements = roundEnv.getElementsAnnotatedWith(RouterRule.class); 87 | if (elements.isEmpty()) { 88 | return; 89 | } 90 | TypeElement type = null; 91 | try { 92 | for (Element ele : elements) { 93 | type = (TypeElement) ele; 94 | if (!Utils.checkTypeValid(type)) continue; 95 | 96 | RouterRule rule = type.getAnnotation(RouterRule.class); 97 | RouteRuleConfig ruleConfig = RouteRuleConfig.create(rule, config, type); 98 | 99 | Parser parser = Parser.create(type, ruleConfig); 100 | parser.parse(); 101 | 102 | parsers.add(parser); 103 | } 104 | 105 | new RuleFactory(ClassName.get(config.pack, "RouterRuleCreator"), parsers).generateCode(); 106 | } catch (RouterException e) { 107 | throw e; 108 | } catch (Throwable e) { 109 | throw new RouterException(e.getMessage(),e,type); 110 | } 111 | } 112 | 113 | /** 114 | * compiler output method, when a error occurs. should be notice here. 115 | * 116 | * @param element Element of class who has a exception when compiled 117 | * @param message The message should be noticed to user 118 | * @param args args to inflate message 119 | */ 120 | private void error(Element element, String message, Object... args) { 121 | if (args.length > 0) { 122 | message = String.format(message, args); 123 | } 124 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element); 125 | } 126 | 127 | @Override 128 | public SourceVersion getSupportedSourceVersion() { 129 | return SourceVersion.latestSupported(); 130 | } 131 | 132 | @Override 133 | public Set getSupportedAnnotationTypes() { 134 | Set set = new HashSet<>(); 135 | set.add(RouterRule.class.getCanonicalName()); 136 | set.add(RouteConfig.class.getCanonicalName()); 137 | return set; 138 | } 139 | 140 | @Override 141 | public synchronized void init(ProcessingEnvironment processingEnv) { 142 | super.init(processingEnv); 143 | UtilMgr.getMgr().init(processingEnv); 144 | } 145 | 146 | 147 | } 148 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/Constants.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler; 2 | 3 | public class Constants { 4 | 5 | // Application 6 | public static final String CLASSNAME_APPLICATION = "android.app.Application"; 7 | // Activity 8 | public static final String CLASSNAME_ACTIVITY = "android.app.Activity"; 9 | // ActionSupport 10 | public static final String CLASSNAME_ACTION_SUPPORT = "com.lzh.nonview.router.route.ActionSupport"; 11 | // RouteRule 12 | public static final String CLASSNAME_ROUTE_MAP = "com.lzh.nonview.router.module.RouteRule"; 13 | // ActivityRouteRule 14 | public static final String CLASSNAME_ACTIVITY_ROUTE_MAP = "com.lzh.nonview.router.module.ActivityRouteRule"; 15 | // ActionRouteRule 16 | public static final String CLASSNAME_ACTION_ROUTE_MAP = "com.lzh.nonview.router.module.ActionRouteRule"; 17 | // CreatorRouteRule 18 | public static final String CLASSNAME_CREATOR_ROUTE_MAP = "com.lzh.nonview.router.module.CreatorRouteRule"; 19 | // RouteCreator 20 | public static final String CLASSNAME_ROUTE_CREATOR = "com.lzh.nonview.router.module.RouteCreator"; 21 | // MainThreadExecutor 22 | public static final String CLASSNAME_MAINTHREADEXECUTOR = "com.lzh.nonview.router.executors.MainThreadExecutor"; 23 | // DefaultActivityLauncher 24 | public static final String CLASSNAME_ACTIVITY_LAUNCHER = "com.lzh.nonview.router.launcher.ActivityLauncher"; 25 | // DefaultActionLauncher 26 | public static final String CLASSNAME_ACTION_LAUNCHER = "com.lzh.nonview.router.launcher.ActionLauncher"; 27 | 28 | // RouteCreator.createActivityRouteRule 29 | public static final String METHODNAME_CREATE_ACTIVITY_ROUTER = "createActivityRouteRules"; 30 | // RouteCreator.createActionRouteRule 31 | public static final String METHODNAME_CREATE_ACTION_ROUTER = "createActionRouteRules"; 32 | // RouteCreator.createCreatorRouteRule 33 | public static final String METHODNAME_CREATE_CREATOR_ROUTER = "createCreatorRouteRule"; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/exception/RouterException.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.exception; 2 | 3 | import javax.lang.model.element.Element; 4 | 5 | public class RouterException extends RuntimeException { 6 | 7 | private Element element; 8 | 9 | public RouterException(String message, Element element) { 10 | super(message); 11 | this.element = element; 12 | } 13 | 14 | public RouterException(String message, Throwable cause, Element element) { 15 | super(message, cause); 16 | this.element = element; 17 | } 18 | 19 | public Element getElement() { 20 | return element; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/factory/RuleFactory.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.factory; 2 | 3 | import com.lzh.nonview.router.compiler.Constants; 4 | import com.lzh.nonview.router.compiler.model.Parser; 5 | import com.lzh.nonview.router.compiler.util.UtilMgr; 6 | import com.lzh.nonview.router.compiler.util.Utils; 7 | import com.squareup.javapoet.ClassName; 8 | import com.squareup.javapoet.CodeBlock; 9 | import com.squareup.javapoet.JavaFile; 10 | import com.squareup.javapoet.MethodSpec; 11 | import com.squareup.javapoet.TypeName; 12 | import com.squareup.javapoet.TypeSpec; 13 | 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | import javax.lang.model.element.Element; 21 | import javax.lang.model.element.ElementKind; 22 | import javax.lang.model.element.ExecutableElement; 23 | import javax.lang.model.element.Modifier; 24 | import javax.lang.model.element.TypeElement; 25 | import javax.lang.model.type.TypeMirror; 26 | 27 | public class RuleFactory { 28 | 29 | private ClassName clzName; 30 | private List activityParser = new ArrayList<>(); 31 | private List actionParser = new ArrayList<>(); 32 | private List creatorParser = new ArrayList<>(); 33 | private ClassName routeMap = ClassName.bestGuess(Constants.CLASSNAME_ROUTE_MAP); 34 | private ClassName activityRouteMap = ClassName.bestGuess(Constants.CLASSNAME_ACTIVITY_ROUTE_MAP); 35 | private ClassName actionRouteMap = ClassName.bestGuess(Constants.CLASSNAME_ACTION_ROUTE_MAP); 36 | private ClassName creatorRouteMap = ClassName.bestGuess(Constants.CLASSNAME_CREATOR_ROUTE_MAP); 37 | 38 | public RuleFactory(ClassName name, List parserList) { 39 | this.clzName = name; 40 | for (Parser item : parserList) { 41 | if (Utils.isSuperClass(item.getType(), Constants.CLASSNAME_ACTIVITY)) { 42 | activityParser.add(item); 43 | } else if (Utils.isSuperClass(item.getType(), Constants.CLASSNAME_ACTION_SUPPORT)){ 44 | actionParser.add(item); 45 | } else { 46 | creatorParser.add(item); 47 | } 48 | } 49 | } 50 | 51 | public void generateCode () throws IOException { 52 | ClassName creator = ClassName.bestGuess(Constants.CLASSNAME_ROUTE_CREATOR); 53 | TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(clzName) 54 | .addSuperinterface(creator) 55 | .addModifiers(Modifier.PUBLIC); 56 | 57 | MethodSpec.Builder methodActivityRulesCreator = MethodSpec.overriding(getOverrideMethod(creator, Constants.METHODNAME_CREATE_ACTIVITY_ROUTER)); 58 | methodActivityRulesCreator.addStatement("$T routes = new $T<>()",Map.class, activityRouteMap, HashMap.class); 59 | for (Parser parser : activityParser ) { 60 | String[] schemaes = parser.getScheme(); 61 | for (String schema : schemaes) { 62 | appendMethod(parser,methodActivityRulesCreator,schema, Constants.CLASSNAME_ACTIVITY_ROUTE_MAP); 63 | } 64 | } 65 | methodActivityRulesCreator.addStatement("return routes"); 66 | 67 | MethodSpec.Builder methodActionRulesCreator = MethodSpec.overriding(getOverrideMethod(creator, Constants.METHODNAME_CREATE_ACTION_ROUTER)); 68 | methodActionRulesCreator.addStatement("$T routes = new $T<>()",Map.class, actionRouteMap, HashMap.class); 69 | for (Parser parser : actionParser ) { 70 | String[] schemaes = parser.getScheme(); 71 | for (String schema : schemaes) { 72 | appendMethod(parser,methodActionRulesCreator,schema, Constants.CLASSNAME_ACTION_ROUTE_MAP); 73 | } 74 | } 75 | methodActionRulesCreator.addStatement("return routes"); 76 | 77 | MethodSpec.Builder methodCreatorRulesCreator = MethodSpec.overriding(getOverrideMethod(creator, Constants.METHODNAME_CREATE_CREATOR_ROUTER)); 78 | methodCreatorRulesCreator.addStatement("$T routes = new $T<>()",Map.class, creatorRouteMap, HashMap.class); 79 | for (Parser parser : creatorParser ) { 80 | String[] schemaes = parser.getScheme(); 81 | for (String schema : schemaes) { 82 | 83 | appendMethod(parser,methodCreatorRulesCreator,schema, Constants.CLASSNAME_CREATOR_ROUTE_MAP); 84 | } 85 | } 86 | methodCreatorRulesCreator.addStatement("return routes"); 87 | 88 | typeBuilder.addMethod(methodActivityRulesCreator.build()); 89 | typeBuilder.addMethod(methodActionRulesCreator.build()); 90 | typeBuilder.addMethod(methodCreatorRulesCreator.build()); 91 | JavaFile.Builder javaBuilder = JavaFile.builder(clzName.packageName(), typeBuilder.build()); 92 | javaBuilder.build().writeTo(UtilMgr.getMgr().getFiler()); 93 | } 94 | 95 | private void appendMethod(Parser parser, MethodSpec.Builder methodCreator,String schema, String className) { 96 | String target = parser.getType().getQualifiedName().toString(); 97 | TypeElement actType = UtilMgr.getMgr().getElementUtils().getTypeElement(target); 98 | CodeBlock.Builder codeBuilder; 99 | codeBuilder = CodeBlock.builder().add("routes.put($S,new $T($T.class)", 100 | schema, ClassName.bestGuess(className), actType); 101 | 102 | if (Constants.CLASSNAME_ACTION_ROUTE_MAP.equals(className)) { 103 | codeBuilder.add("\r\n\t\t"); 104 | codeBuilder.add(".setExecutorClass($T.class)", parser.getExecutorClass()); 105 | } 106 | 107 | if (parser.getConfigurations().getLauncher() != null) { 108 | codeBuilder.add("\r\n\t\t"); 109 | codeBuilder.add(".setLauncher($T.class)", parser.getConfigurations().getLauncher()); 110 | } 111 | 112 | // add interceptors 113 | TypeName[] interceptors = parser.getConfigurations().getInterceptors(); 114 | if (interceptors.length != 0) { 115 | codeBuilder.add("\r\n\t\t"); 116 | codeBuilder.add(".setInterceptors("); 117 | for (int i = 0; i < interceptors.length; i++) { 118 | TypeName interceptor = interceptors[i]; 119 | if (i > 0) { 120 | codeBuilder.add(","); 121 | } 122 | codeBuilder.add("$T.class", interceptor); 123 | } 124 | codeBuilder.add(")"); 125 | } 126 | 127 | codeBuilder.addStatement(")"); 128 | methodCreator.addCode(codeBuilder.build()); 129 | } 130 | 131 | private String getTypeFromName(TypeMirror name) { 132 | switch (name.toString()) { 133 | case "boolean": 134 | case "java.lang.Boolean": 135 | return "BOOLEAN"; 136 | case "byte": 137 | case "java.lang.Byte": 138 | return "BYTE"; 139 | case "char": 140 | case "java.lang.Character": 141 | return "CHAR"; 142 | case "short": 143 | case "java.lang.Short": 144 | return "SHORT"; 145 | case "int": 146 | case "java.lang.Integer": 147 | return "INT"; 148 | case "long": 149 | case "java.lang.Long": 150 | return "LONG"; 151 | case "float": 152 | case "java.lang.Float": 153 | return "FLOAT"; 154 | case "double": 155 | case "java.lang.Double": 156 | return "DOUBLE"; 157 | case "java.lang.String": 158 | return "STRING"; 159 | } 160 | return "STRING"; 161 | } 162 | 163 | private ExecutableElement getOverrideMethod(ClassName creator, String methodName) { 164 | TypeElement element = UtilMgr.getMgr().getElementUtils().getTypeElement(creator.toString()); 165 | List elements = element.getEnclosedElements(); 166 | for (Element ele : elements) { 167 | if (ele.getKind() != ElementKind.METHOD) continue; 168 | if (methodName.equals(ele.getSimpleName().toString())) { 169 | return (ExecutableElement) ele; 170 | } 171 | } 172 | throw new RuntimeException("method createRouteRules of interface RouteCreator not found"); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/model/BasicConfigurations.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.model; 2 | 3 | import com.lzh.nonview.router.anno.RouteConfig; 4 | import com.lzh.nonview.router.compiler.util.Utils; 5 | 6 | public class BasicConfigurations { 7 | public String baseUrl; 8 | public String pack = "com.lzh.router"; 9 | 10 | public BasicConfigurations(RouteConfig config) { 11 | if (config == null) return; 12 | 13 | if (!Utils.isEmpty(config.pack())) { 14 | this.pack = config.pack(); 15 | } 16 | this.baseUrl = parseBaseUrl(config); 17 | } 18 | 19 | private String parseBaseUrl(RouteConfig config) { 20 | if (!Utils.isEmpty(config.baseUrl())) { 21 | return config.baseUrl(); 22 | } 23 | return ""; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/model/Parser.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.model; 2 | 3 | import com.lzh.nonview.router.anno.RouteExecutor; 4 | import com.lzh.nonview.router.compiler.Constants; 5 | import com.lzh.nonview.router.compiler.exception.RouterException; 6 | import com.lzh.nonview.router.compiler.util.UtilMgr; 7 | import com.squareup.javapoet.ClassName; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | import javax.lang.model.element.TypeElement; 13 | import javax.lang.model.type.MirroredTypeException; 14 | import javax.lang.model.type.TypeMirror; 15 | 16 | public class Parser { 17 | private static Map parsed = new HashMap<>(); 18 | private String[] routers; 19 | private TypeElement type; 20 | private RouteRuleConfig configurations; 21 | private ClassName executorClass; 22 | 23 | public static Parser create (TypeElement element, RouteRuleConfig configurations) { 24 | Parser parser = new Parser(); 25 | parser.type = element; 26 | parser.configurations = configurations; 27 | parser.executorClass = parser.obtainExecutor(); 28 | return parser; 29 | } 30 | 31 | private ClassName obtainExecutor() { 32 | RouteExecutor annotation = type.getAnnotation(RouteExecutor.class); 33 | if (annotation == null) { 34 | return ClassName.bestGuess(Constants.CLASSNAME_MAINTHREADEXECUTOR); 35 | } 36 | try { 37 | return ClassName.get(annotation.value()); 38 | } catch (MirroredTypeException mirrored) { 39 | TypeMirror typeMirror = mirrored.getTypeMirror(); 40 | return ClassName.get((TypeElement) UtilMgr.getMgr().getTypeUtils().asElement(typeMirror)); 41 | } 42 | } 43 | 44 | public void parse () { 45 | routers = configurations.getRoute(); 46 | for (int i = 0; i < routers.length; i++) { 47 | String route = routers[i]; 48 | checkIsDuplicate(route); 49 | } 50 | } 51 | 52 | private void checkIsDuplicate(String route) { 53 | if (route.endsWith("/")) { 54 | route = route.substring(0,route.lastIndexOf("/")); 55 | } 56 | 57 | if (parsed.containsKey(route)) { 58 | throw new RouterException(String.format("A same scheme was double defined on another class %s", parsed.get(route)),type); 59 | } 60 | parsed.put(route,type); 61 | } 62 | 63 | public String[] getScheme() { 64 | return routers; 65 | } 66 | 67 | public TypeElement getType() { 68 | return type; 69 | } 70 | 71 | public ClassName getExecutorClass() { 72 | return executorClass; 73 | } 74 | 75 | public RouteRuleConfig getConfigurations() { 76 | return configurations; 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/model/RouteRuleConfig.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.model; 2 | 3 | import com.lzh.nonview.router.anno.ActionLauncher; 4 | import com.lzh.nonview.router.anno.ActivityLauncher; 5 | import com.lzh.nonview.router.anno.RouteInterceptors; 6 | import com.lzh.nonview.router.anno.RouterRule; 7 | import com.lzh.nonview.router.compiler.Constants; 8 | import com.lzh.nonview.router.compiler.util.UtilMgr; 9 | import com.lzh.nonview.router.compiler.util.Utils; 10 | import com.squareup.javapoet.ClassName; 11 | import com.squareup.javapoet.TypeName; 12 | 13 | import java.net.URI; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import javax.lang.model.element.TypeElement; 18 | import javax.lang.model.type.MirroredTypeException; 19 | import javax.lang.model.type.MirroredTypesException; 20 | import javax.lang.model.type.TypeMirror; 21 | import javax.lang.model.util.Elements; 22 | 23 | /** 24 | * The configuration class links to {@link RouterRule}. 25 | * 26 | *

27 | * This class are one-to-one correspondence to {@link RouterRule} 28 | *

29 | */ 30 | public class RouteRuleConfig { 31 | private String[] routes; 32 | private ClassName launcher; 33 | private TypeName[] interceptors; 34 | 35 | public static RouteRuleConfig create(RouterRule rule, BasicConfigurations basicConfigurations, TypeElement type) { 36 | RouteRuleConfig config = new RouteRuleConfig(); 37 | config.routes = config.combineRoute(rule, basicConfigurations); 38 | config.interceptors = config.combineInterceptors(type); 39 | if (Utils.isSuperClass(type, Constants.CLASSNAME_ACTIVITY)) { 40 | config.launcher = config.combineActivityLauncher(type.getAnnotation(ActivityLauncher.class)); 41 | } else if (Utils.isSuperClass(type, Constants.CLASSNAME_ACTION_SUPPORT)) { 42 | config.launcher = config.combineActionLauncher(type.getAnnotation(ActionLauncher.class)); 43 | } 44 | return config; 45 | } 46 | 47 | private TypeName[] combineInterceptors(TypeElement type) { 48 | ArrayList interceptors = new ArrayList<>(); 49 | RouteInterceptors routeInterceptors = type.getAnnotation(RouteInterceptors.class); 50 | if (routeInterceptors != null) { 51 | try { 52 | Class[] value = routeInterceptors.value(); 53 | for (Class item : value) { 54 | interceptors.add(ClassName.get(item)); 55 | } 56 | } catch (MirroredTypesException mirrored) { 57 | List typeMirrors = mirrored.getTypeMirrors(); 58 | for (TypeMirror mirror : typeMirrors) { 59 | interceptors.add(ClassName.get(mirror)); 60 | } 61 | } 62 | } 63 | return interceptors.toArray(new TypeName[interceptors.size()]); 64 | } 65 | 66 | private String[] combineRoute(RouterRule rule, BasicConfigurations configurations) { 67 | String[] routes = rule.value(); 68 | for (int i = 0; i < routes.length; i++) { 69 | String route = routes[i]; 70 | if (Utils.isEmpty(route)) { 71 | throw new IllegalArgumentException("values of annotation RouteRule can not be null!"); 72 | } 73 | String baseUrl = configurations.baseUrl; 74 | URI uri = URI.create(route); 75 | String scheme = uri.getScheme(); 76 | if (Utils.isEmpty(scheme)) { 77 | if (Utils.isEmpty(baseUrl)) { 78 | throw new IllegalArgumentException("Could not find baseUrl set by RouteConfig to join with the route:" + route); 79 | } 80 | route = baseUrl + route; 81 | } 82 | routes[i] = route; 83 | } 84 | return routes; 85 | } 86 | 87 | private ClassName combineActivityLauncher(ActivityLauncher rule) { 88 | ClassName launcher = null; 89 | try { 90 | if (rule != null) { 91 | launcher = ClassName.get(rule.value()); 92 | } 93 | } catch (MirroredTypeException mirrored) { 94 | TypeMirror typeMirror = mirrored.getTypeMirror(); 95 | launcher = ClassName.get((TypeElement) UtilMgr.getMgr().getTypeUtils().asElement(typeMirror)); 96 | } 97 | 98 | Elements utils = UtilMgr.getMgr().getElementUtils(); 99 | if (launcher != null 100 | && !Utils.isSuperClass(utils.getTypeElement(launcher.toString()), Constants.CLASSNAME_ACTIVITY_LAUNCHER)) { 101 | throw new IllegalArgumentException(String.format( 102 | "The class you set via ActivityLauncher should be a subclass of %s", Constants.CLASSNAME_ACTIVITY_LAUNCHER)); 103 | } 104 | 105 | return launcher; 106 | } 107 | 108 | private ClassName combineActionLauncher(ActionLauncher rule) { 109 | ClassName launcher = null; 110 | try { 111 | if (rule != null) { 112 | launcher = ClassName.get(rule.value()); 113 | } 114 | } catch (MirroredTypeException mirrored) { 115 | TypeMirror typeMirror = mirrored.getTypeMirror(); 116 | launcher = ClassName.get((TypeElement) UtilMgr.getMgr().getTypeUtils().asElement(typeMirror)); 117 | } 118 | 119 | Elements utils = UtilMgr.getMgr().getElementUtils(); 120 | if (launcher != null 121 | && !Utils.isSuperClass(utils.getTypeElement(launcher.toString()), Constants.CLASSNAME_ACTION_LAUNCHER)) { 122 | throw new IllegalArgumentException(String.format( 123 | "The class you set via ActivityLauncher should be a subclass of %s", Constants.CLASSNAME_ACTION_LAUNCHER)); 124 | } 125 | 126 | return launcher; 127 | } 128 | 129 | 130 | 131 | public String[] getRoute() { 132 | return routes == null ? new String[0] : routes; 133 | } 134 | 135 | public ClassName getLauncher() { 136 | return launcher; 137 | } 138 | 139 | public TypeName[] getInterceptors () { 140 | return interceptors; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/util/UtilMgr.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.util; 2 | 3 | import javax.annotation.processing.Filer; 4 | import javax.annotation.processing.Messager; 5 | import javax.annotation.processing.ProcessingEnvironment; 6 | import javax.lang.model.util.Elements; 7 | import javax.lang.model.util.Types; 8 | 9 | public class UtilMgr { 10 | 11 | private Elements elementUtils = null; 12 | private Filer filer = null; 13 | private Messager messager = null; 14 | private Types typeUtils = null; 15 | 16 | private static UtilMgr mgr = new UtilMgr(); 17 | 18 | public void init (ProcessingEnvironment environment) { 19 | setElementUtils(environment.getElementUtils()); 20 | setFiler(environment.getFiler()); 21 | setMessager(environment.getMessager()); 22 | setTypeUtils(environment.getTypeUtils()); 23 | } 24 | 25 | private UtilMgr() { 26 | } 27 | 28 | public static UtilMgr getMgr() { 29 | return mgr; 30 | } 31 | 32 | public Elements getElementUtils() { 33 | return elementUtils; 34 | } 35 | 36 | public void setElementUtils(Elements elementUtils) { 37 | this.elementUtils = elementUtils; 38 | } 39 | 40 | public Filer getFiler() { 41 | return filer; 42 | } 43 | 44 | public void setFiler(Filer filer) { 45 | this.filer = filer; 46 | } 47 | 48 | public Messager getMessager() { 49 | return messager; 50 | } 51 | 52 | public void setMessager(Messager messager) { 53 | this.messager = messager; 54 | } 55 | 56 | public Types getTypeUtils() { 57 | return typeUtils; 58 | } 59 | 60 | public void setTypeUtils(Types typeUtils) { 61 | this.typeUtils = typeUtils; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /router-compiler/src/main/java/com/lzh/nonview/router/compiler/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.compiler.util; 2 | 3 | import com.lzh.nonview.router.compiler.exception.RouterException; 4 | 5 | import java.util.Set; 6 | 7 | import javax.lang.model.element.Modifier; 8 | import javax.lang.model.element.TypeElement; 9 | 10 | public class Utils { 11 | 12 | /** 13 | * Check out if the class are an effective class; 14 | *

15 | * should not be modified by abstract,if set,should be skip
16 | * should not be modified by private,if set,should lead to crash
17 | * should be subclass of android.app.Activity,if not,should lead to crash
18 | *

19 | * @param type A element of class 20 | * @return true if it is a effective class 21 | */ 22 | public static boolean checkTypeValid (TypeElement type) { 23 | Set modifiers = type.getModifiers(); 24 | if (modifiers.contains(Modifier.PRIVATE)) { 25 | throw new RouterException(String.format("The class %s should not be modified by private",type.getSimpleName()),type); 26 | } else return !modifiers.contains(Modifier.ABSTRACT); 27 | } 28 | 29 | /** 30 | * Check out if the class {@code type} is a subclass of {@code superClass} 31 | * @param type the class to check 32 | * @param superClassName the super class name 33 | * @return true if is subclass 34 | */ 35 | public static boolean isSuperClass (TypeElement type,String superClassName) { 36 | if (type == null) { 37 | return false; 38 | } 39 | 40 | do { 41 | type = (TypeElement) UtilMgr.getMgr().getTypeUtils().asElement(type.getSuperclass()); 42 | if (type.getQualifiedName().toString().equals(superClassName)) { 43 | return true; 44 | } 45 | if ("java.lang.Object".equals(type.getQualifiedName().toString())) { 46 | return false; 47 | } 48 | } while (true); 49 | } 50 | 51 | public static boolean isEmpty (String data) { 52 | return data == null || data.length() == 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /router-compiler/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | com.lzh.nonview.router.compiler.Compiler -------------------------------------------------------------------------------- /router-host/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /router-host/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | android { 5 | compileSdkVersion compile_version 6 | buildToolsVersion build_tool 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion target_version 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | sourceSets { 22 | main { 23 | jni.srcDirs = [] //disable automatic ndk-build 24 | } 25 | } 26 | } 27 | 28 | dependencies { 29 | api fileTree(dir: 'libs', include: ['*.jar']) 30 | api project(':router-api') 31 | } 32 | 33 | apply from: '../javadoc.gradle' -------------------------------------------------------------------------------- /router-host/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/haoge/Documents/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 | -------------------------------------------------------------------------------- /router-host/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /router-host/src/main/java/com/lzh/nonview/router/host/DefaultVerify.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.host; 2 | 3 | import android.content.Context; 4 | import android.os.Binder; 5 | import android.util.Log; 6 | 7 | /** 8 | * Default impl for {@link RemoteVerify} 9 | * 10 | *

This class to ensure that the remote-client should have the same package name with service. 11 | */ 12 | final class DefaultVerify implements RemoteVerify{ 13 | 14 | @Override 15 | public boolean verify(Context context) { 16 | String packageName = context.getPackageName(); 17 | int uid = Binder.getCallingUid(); 18 | String[] packages = context.getPackageManager().getPackagesForUid(uid); 19 | if (packages == null) { 20 | packages = new String[0]; 21 | } 22 | for (String pack: packages) { 23 | if (packageName.equals(pack)) { 24 | return true; 25 | } 26 | } 27 | Log.e("DefaultVerify", String.format("The client with uid %s connected failed:", uid)); 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /router-host/src/main/java/com/lzh/nonview/router/host/RemoteVerify.java: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.host; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Provide an interface for security verification. 7 | */ 8 | public interface RemoteVerify { 9 | /** 10 | * Verify the client you are connecting to. 11 | * @param context The application context to provide managers. 12 | * @return returns true if safety 13 | * @throws Exception error occurs 14 | */ 15 | boolean verify(Context context) throws Exception; 16 | } 17 | -------------------------------------------------------------------------------- /router-host/src/main/java/com/lzh/nonview/router/host/RouterHostService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Haoge 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lzh.nonview.router.host; 17 | 18 | import android.app.Service; 19 | import android.content.Intent; 20 | import android.net.Uri; 21 | import android.os.IBinder; 22 | import android.os.Parcel; 23 | 24 | import com.lzh.nonview.router.module.RemoteRule; 25 | import com.lzh.nonview.router.protocol.IService; 26 | 27 | import java.util.ArrayList; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | 32 | /** 33 | * Remote service to store route rules. 34 | * @author haoge 35 | */ 36 | public class RouterHostService extends Service{ 37 | 38 | private static RemoteVerify verify = new DefaultVerify(); 39 | 40 | public static void setVerify(RemoteVerify verify) { 41 | RouterHostService.verify = verify; 42 | } 43 | 44 | IService.Stub stub = new IService.Stub() { 45 | Map activities = new HashMap<>(); 46 | Map actions = new HashMap<>(); 47 | List plugins = new ArrayList<>(); 48 | 49 | @Override 50 | public void register(String pluginName) { 51 | if (!plugins.contains(pluginName)) { 52 | plugins.add(pluginName); 53 | } 54 | } 55 | 56 | @Override 57 | public boolean isRegister(String pluginName) { 58 | return plugins.contains(pluginName); 59 | } 60 | 61 | @Override 62 | public void addActivityRules(Map rules) { 63 | activities.putAll(rules); 64 | } 65 | 66 | @Override 67 | public void addActionRules(Map rules) { 68 | actions.putAll(rules); 69 | } 70 | 71 | @Override 72 | public RemoteRule getActionRule(Uri uri) { 73 | return findRule(uri, actions); 74 | } 75 | 76 | @Override 77 | public RemoteRule getActivityRule(Uri uri) { 78 | return findRule(uri, activities); 79 | } 80 | 81 | @Override 82 | public boolean onTransact(int code, Parcel data, Parcel reply, int flags) { 83 | try { 84 | // check for security verification 85 | if (verify != null && !verify.verify(getApplicationContext())) { 86 | return false; 87 | } 88 | return super.onTransact(code, data, reply, flags); 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | return false; 92 | } 93 | } 94 | }; 95 | 96 | private RemoteRule findRule(Uri uri, Map rules) { 97 | String route = uri.getScheme() + "://" + uri.getHost() + uri.getPath(); 98 | for (String key:rules.keySet()) { 99 | if (format(key).equals(format(route))) { 100 | return rules.get(key); 101 | } 102 | } 103 | return null; 104 | } 105 | 106 | private String format(String url) { 107 | if (url.endsWith("/")){ 108 | return url.substring(0, url.length() - 1); 109 | } 110 | return url; 111 | } 112 | 113 | @Override 114 | public IBinder onBind(Intent intent) { 115 | return stub; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /router-host/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Host 3 | 4 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | 5 | android { 6 | compileSdkVersion compile_version 7 | buildToolsVersion build_tool 8 | lintOptions { 9 | abortOnError false 10 | } 11 | defaultConfig { 12 | applicationId "com.lzh.nonview.router.demo" 13 | minSdkVersion 15 14 | targetSdkVersion target_version 15 | versionCode 1 16 | versionName "1.0" 17 | } 18 | buildTypes { 19 | debug { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | } 29 | 30 | def parceler_version="1.4.0" 31 | def router_version="1a71a61556" 32 | def butterknife_version='8.0.1' 33 | dependencies { 34 | api fileTree(include: ['*.jar'], dir: 'libs') 35 | api 'com.alibaba:fastjson:1.2.47' 36 | api 'com.github.yjfnypeu:EasyAndroid:1.2.5' 37 | 38 | api "com.jakewharton:butterknife:$butterknife_version" 39 | kapt "com.jakewharton:butterknife-compiler:$butterknife_version" 40 | 41 | kapt "com.github.yjfnypeu.Parceler:compiler:$parceler_version" 42 | api "com.github.yjfnypeu.Parceler:api:$parceler_version" 43 | 44 | kapt "com.github.longshihan1.AopBrocad:broca-compiler:1.1.7" 45 | api 'com.github.longshihan1.AopBrocad:broca-api:1.1.7' 46 | 47 | // api "com.github.yjfnypeu.Router:router-api:$router_version" 48 | // kapt "com.github.yjfnypeu.Router:router-compiler:$router_version" 49 | 50 | api project(':router-api') 51 | kapt project(':router-compiler') 52 | api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 53 | } 54 | -------------------------------------------------------------------------------- /sample/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/admin/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 | #添加Parceler框架混淆规则 20 | -dontwarn ** 21 | -keep class com.lzh.compiler.parceler.** 22 | -keep class * implements com.lzh.compiler.parceler.ParcelInjector 23 | 24 | -keepclasseswithmembernames class * { @com.lzh.compiler.parceler.annotation.* ;} 25 | 26 | #添加Parceler框架混淆规则 27 | -keep class butterknife.** { *; } 28 | -keep class **$$ViewBinder { *; } 29 | 30 | -keepclasseswithmembernames class * { @butterknife.* ; } 31 | -keepclasseswithmembernames class * { @butterknife.* ; } 32 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/App.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.app.Application 4 | import com.haoge.easyandroid.EasyAndroid 5 | import com.haoge.studio.RouterRuleCreator 6 | import com.lzh.compiler.parceler.Parceler 7 | import com.lzh.compiler.parceler.annotation.FastJsonConverter 8 | import com.lzh.nonview.router.Router 9 | import com.lzh.nonview.router.RouterConfiguration 10 | import com.lzh.nonview.router.anno.RouteConfig 11 | import com.lzh.nonview.router.demo.interceptors.DefaultInterceptor 12 | 13 | @RouteConfig(baseUrl = "haoge://page/", pack = "com.haoge.studio") 14 | class App : Application() { 15 | 16 | override fun onCreate() { 17 | super.onCreate() 18 | // 注册通过apt生成的路由表 19 | RouterConfiguration.get().addRouteCreator(RouterRuleCreator()) 20 | // 设置默认路由拦截器:所有路由跳转均会被触发(除了需要直接打开浏览器的链接) 21 | RouterConfiguration.get().interceptor = DefaultInterceptor() 22 | 23 | // 开启Router日志打印 24 | Router.DEBUG = true 25 | 26 | // 配置Parceler转换器 27 | Parceler.setDefaultConverter(FastJsonConverter::class.java) 28 | 29 | EasyAndroid.init(this) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/ArgsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.os.Bundle 4 | import android.widget.TextView 5 | import com.lzh.compiler.parceler.annotation.Arg 6 | import com.lzh.nonview.router.anno.RouterRule 7 | import com.lzh.nonview.router.demo.pojo.User 8 | 9 | /** 10 | * 此页面用于介绍如何结合[Parceler](https://github.com/JumeiRdGroup/Parceler)框架的 11 | * Arg注解进行**自动参数类型解析传递** 12 | * 13 | * DATE: 2018/5/8 14 | * 15 | * AUTHOR: haoge 16 | */ 17 | @RouterRule("parceler-args") 18 | class ArgsActivity:BaseActivity() { 19 | 20 | // 基本java数据类型 21 | @Arg 22 | var mBoolean:Boolean? = null 23 | @Arg 24 | var mInt:Int? = null 25 | @Arg 26 | var mByte:Byte? = null 27 | @Arg 28 | var mShort:Short? = null 29 | @Arg 30 | var mChar:Char? = null 31 | @Arg 32 | var mFloat:Float? = null 33 | @Arg 34 | var mLong:Long? = null 35 | @Arg 36 | var mDouble:Double? = null 37 | // 其他类型 38 | @Arg 39 | var mString:String? = null 40 | // 非可序列化对象 41 | @Arg 42 | var mUser: User? = null 43 | @Arg 44 | var mUrl:String? = null 45 | 46 | val mPrinter:TextView by lazy { findViewById(R.id.printer_tv) } 47 | 48 | override fun onCreate(savedInstanceState: Bundle?) { 49 | super.onCreate(savedInstanceState) 50 | setContentView(R.layout.activity_intent_printer) 51 | val message = StringBuilder() 52 | message.append("boolean value is $mBoolean\n") 53 | message.append("int value is $mInt\n") 54 | message.append("byte value is $mByte\n") 55 | message.append("short value is $mShort\n") 56 | message.append("char value is $mChar\n") 57 | message.append("float value is $mFloat\n") 58 | message.append("long value is $mLong\n") 59 | message.append("double value is $mDouble\n") 60 | message.append("string value is $mString\n") 61 | message.append("user value is $mUser\n") 62 | message.append("url value is $mUrl\n") 63 | mPrinter.text = message 64 | } 65 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import butterknife.ButterKnife 7 | import com.lzh.compiler.parceler.BundleFactory 8 | 9 | import com.lzh.compiler.parceler.Parceler 10 | import com.lzh.nonview.router.RouterConfiguration 11 | 12 | abstract class BaseActivity : Activity() { 13 | 14 | protected val bundleFactory by lazy { Parceler.createFactory(intent?.extras) } 15 | 16 | // Parceler基础注入配置 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | Parceler.toEntity(this, intent) 20 | } 21 | 22 | override fun onSaveInstanceState(outState: Bundle?) { 23 | super.onSaveInstanceState(outState) 24 | Parceler.toBundle(this, outState) 25 | } 26 | 27 | override fun onRestoreInstanceState(savedInstanceState: Bundle?) { 28 | super.onRestoreInstanceState(savedInstanceState) 29 | Parceler.toEntity(this, savedInstanceState) 30 | } 31 | 32 | override fun setContentView(layoutResID: Int) { 33 | super.setContentView(layoutResID) 34 | ButterKnife.bind(this) 35 | } 36 | 37 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 38 | super.onActivityResult(requestCode, resultCode, data) 39 | RouterConfiguration.get().dispatchActivityResult(this, requestCode, resultCode, data) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/IntentPrinterActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.os.Bundle 4 | import android.widget.TextView 5 | import com.lzh.nonview.router.anno.RouterRule 6 | 7 | /** 8 | * DATE: 2018/5/8 9 | * AUTHOR: haoge 10 | */ 11 | @RouterRule("intent/printer") 12 | class IntentPrinterActivity:BaseActivity() { 13 | 14 | val mPrinter:TextView by lazy { findViewById(R.id.printer_tv) } 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | setContentView(R.layout.activity_intent_printer) 19 | 20 | var message = StringBuilder() 21 | if (intent == null 22 | || intent.extras == null 23 | || intent.extras.isEmpty) { 24 | message.append("当前页面的Intent中不含有数据") 25 | } else { 26 | val keys = intent.extras.keySet() 27 | message.append("当前页面的intent中含有一下${keys.size}条数据:\n") 28 | for (s in keys) { 29 | message.append("key = $s & value = ${intent.extras[s]}") 30 | message.append("\n") 31 | } 32 | } 33 | mPrinter.text = message 34 | } 35 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.net.Uri 4 | import android.os.Bundle 5 | import butterknife.OnClick 6 | import com.lzh.compiler.parceler.annotation.Arg 7 | import com.lzh.nonview.router.Router 8 | import com.lzh.nonview.router.demo.manager.DataManager 9 | import com.lzh.nonview.router.extras.RouteBundleExtras 10 | 11 | class LoginActivity:BaseActivity() { 12 | 13 | @Arg("uri") 14 | var uri:Uri? = null 15 | @Arg("extras") 16 | var extras:RouteBundleExtras? = null 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_login) 21 | } 22 | 23 | @OnClick(R.id.login) 24 | fun login() { 25 | DataManager.login = true 26 | // 登录完成后恢复路由启动。 27 | Router.resume(uri, extras).open(this) 28 | finish() 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.widget.Toast 7 | import butterknife.OnClick 8 | import com.alibaba.fastjson.JSON 9 | import com.haoge.easyandroid.easy.EasyToast 10 | import com.lzh.compiler.parceler.Parceler 11 | import com.lzh.nonview.router.Router 12 | import com.lzh.nonview.router.anno.RouterRule 13 | import com.lzh.nonview.router.demo.interceptors.LoginInterceptor 14 | import com.lzh.nonview.router.demo.pojo.User 15 | import com.lzh.nonview.router.exception.NotFoundException 16 | import com.lzh.nonview.router.launcher.Launcher 17 | import com.lzh.nonview.router.module.RouteRule 18 | import com.lzh.nonview.router.route.RouteCallback 19 | import java.util.concurrent.ExecutorService 20 | import java.util.concurrent.Executors 21 | 22 | @RouterRule("main") 23 | class MainActivity : BaseActivity() { 24 | 25 | val pool: ExecutorService = Executors.newSingleThreadExecutor { runnable -> 26 | val thread:Thread = Thread(runnable) 27 | thread.name = "action_executor" 28 | return@newSingleThreadExecutor thread 29 | } 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | setContentView(R.layout.activity_main) 34 | } 35 | 36 | // =======http/https自动跳转浏览器======== 37 | @OnClick(R.id.open_browser) 38 | fun openBrowser() { 39 | Router.create("https://www.baidu.com").open(this) 40 | } 41 | 42 | // =======不同拦截器使用方式示例=========== 43 | @OnClick(R.id.toPrinterActivityWithRequestLogin) 44 | fun toPrinterActivityWithRequestLogin() { 45 | Router.create("haoge://page/intent/printer?title=动态登录检查&requestLogin=1").open(this) 46 | } 47 | 48 | @OnClick(R.id.toPrinterActivityWithInterceptor) 49 | fun toPrinterActivityWithInterceptor() { 50 | Router.create("haoge://page/intent/printer?title=使用指定拦截器") 51 | .addInterceptor(LoginInterceptor())// 指定此次跳转使用此拦截器 52 | .open(this) 53 | } 54 | 55 | @OnClick(R.id.toPrinterActivityWithoutInterceptor) 56 | fun toPrinterActivityWithoutInterceptor() { 57 | Router.create("haoge://page/intent/printer?title=不使用拦截器进行跳转").open(this) 58 | } 59 | 60 | @OnClick(R.id.toUserActivity) 61 | fun toUserActivity() { 62 | Router.create("haoge://page/user-info?username=测试账号").open(this) 63 | } 64 | 65 | @OnClick(R.id.toPrinterActivityWithExtras) 66 | fun toPrinterActivityWithExtras() { 67 | val data = Parceler.createFactory(null) 68 | .put("用户名", "测试") 69 | .put("密码", "你猜") 70 | .bundle 71 | 72 | Router.create("haoge://page/intent/printer") 73 | .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)// 添加启动标记位:Intent.addFlag() 74 | .requestCode(1001)// 指定请求码,使用startActivityForResult跳转 75 | .addExtras(data)// 添加额外数据。将放入Intent中进行传递:Intent.putExtras(data) 76 | .addInterceptor(LoginInterceptor())// 添加拦截器,若添加有多个拦截器,将被依次触发 77 | .setCallback(object:RouteCallback {// 添加路由回调 78 | override fun notFound(uri: Uri?, e: NotFoundException?) { 79 | Toast.makeText(this@MainActivity, "没匹配到与此uri所匹配的路由目标", Toast.LENGTH_SHORT).show() 80 | } 81 | 82 | override fun onOpenSuccess(uri: Uri?, rule: RouteRule, out Launcher>?) { 83 | Toast.makeText(this@MainActivity, "打开路由成功", Toast.LENGTH_SHORT).show() 84 | } 85 | 86 | override fun onOpenFailed(uri: Uri?, e: Throwable?) { 87 | Toast.makeText(this@MainActivity, "打开路由失败:${e?.message}", Toast.LENGTH_SHORT).show() 88 | } 89 | }) 90 | .setAnim(R.anim.anim_fade_in, R.anim.anim_fade_out)// 设置转场动画 91 | .open(this) 92 | 93 | } 94 | 95 | @OnClick(R.id.toResultActivity) 96 | fun toResultActivity() { 97 | Router.create("haoge://page/result") 98 | // 指定返回数据回调 99 | .resultCallback { resultCode, data -> Toast.makeText(this, "返回码是$resultCode", Toast.LENGTH_SHORT).show() } 100 | .open(this) 101 | } 102 | 103 | @OnClick(R.id.toArgsActivity) 104 | fun toArgsActivity() { 105 | val url = Uri.parse("haoge://page/parceler-args") 106 | .buildUpon() 107 | // 添加基本数据类型 108 | .appendQueryParameter("mBoolean", "true") 109 | .appendQueryParameter("mByte", "0") 110 | .appendQueryParameter("mShort", "1") 111 | .appendQueryParameter("mChar", "c") 112 | .appendQueryParameter("mInt", "3") 113 | .appendQueryParameter("mFloat", "3.14") 114 | .appendQueryParameter("mDouble", "3.14") 115 | .appendQueryParameter("mLong", "5") 116 | .appendQueryParameter("mString", "HaogeStudio") 117 | // 非可序列化对象可通过json格式传递 118 | .appendQueryParameter("mUser", JSON.toJSONString(User("HaogeStudio"))) 119 | // 转义字符串。比如参数中需要传递网址时 120 | // appendQueryParameter本身会将数据先进行转义后再拼接上。所以此处是转义的链接 121 | .appendQueryParameter("mUrl", "https://www.baidu.com") 122 | .build() 123 | 124 | Router.create(url).open(this) 125 | } 126 | 127 | @OnClick(R.id.launchActionRoute) 128 | fun launchActionRoute() { 129 | Router.create("haoge://page/say/hello").open(this) 130 | } 131 | 132 | @OnClick(R.id.launchActionRouteWithExecutorAnnotation) 133 | fun launchActionRouteWithExecutorAnnotation() { 134 | Router.create("haoge://page/executor/switcher").open(this) 135 | } 136 | 137 | @OnClick(R.id.launchActionRouteWithExecutorConfig) 138 | fun launchActionRouteWithExecutorConfig() { 139 | Router.create("haoge://page/executor/switcher") 140 | .setExecutor(pool) 141 | .open(this) 142 | } 143 | 144 | @OnClick(R.id.createInstanceForJavaBean) 145 | fun createInstanceForJavaBean() { 146 | val user = Router.createInstanceRouter("haoge://page/creator/user?name=CreatorRouter").createInstance() 147 | EasyToast.DEFAULT.show("获取到对象:$user") 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/ResultActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import butterknife.OnClick 6 | import com.lzh.nonview.router.anno.RouterRule 7 | 8 | /** 9 | * 提供resultCode的页面。 10 | * DATE: 2018/5/8 11 | * AUTHOR: haoge 12 | */ 13 | @RouterRule("result") 14 | class ResultActivity : BaseActivity(){ 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | setContentView(R.layout.activity_result) 19 | } 20 | 21 | @OnClick(R.id.backWithoutIntent) 22 | fun backWithIntent() { 23 | finish() 24 | } 25 | 26 | @OnClick(R.id.backWithIntent) 27 | fun backWithoutIntent() { 28 | val intent = Intent() 29 | intent.putExtra("value", "返回数据") 30 | setResult(1001, intent) 31 | finish() 32 | } 33 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/UserActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo 2 | 3 | import android.os.Bundle 4 | import android.widget.TextView 5 | import com.lzh.compiler.parceler.annotation.Arg 6 | import com.lzh.nonview.router.anno.RouteInterceptors 7 | import com.lzh.nonview.router.anno.RouterRule 8 | import com.lzh.nonview.router.demo.interceptors.LoginInterceptor 9 | 10 | /** 11 | * 用户信息展示页 12 | * DATE: 2018/5/8 13 | * AUTHOR: haoge 14 | */ 15 | @RouteInterceptors(LoginInterceptor::class)// 指定所有往此页面跳转的路由,均要进行登录检查 16 | @RouterRule("user-info") 17 | class UserActivity :BaseActivity(){ 18 | 19 | // 使用Parceler自动注入intent数据进行使用 20 | @Arg("username") 21 | var username = "HaogeStudio" 22 | 23 | val userTv:TextView by lazy { findViewById(R.id.username) } 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | setContentView(R.layout.activity_user) 28 | userTv.text = "用户名为【$username】" 29 | } 30 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/action/ExecutorAction.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.action 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import com.haoge.easyandroid.easy.EasyToast 6 | import com.lzh.nonview.router.anno.RouteExecutor 7 | import com.lzh.nonview.router.anno.RouterRule 8 | import com.lzh.nonview.router.demo.executor.TestExecutor 9 | import com.lzh.nonview.router.route.ActionSupport 10 | 11 | /** 12 | * @author haoge on 2018/5/10 13 | */ 14 | @RouteExecutor(TestExecutor::class) 15 | @RouterRule("executor/switcher") 16 | class ExecutorAction : ActionSupport(){ 17 | override fun onRouteTrigger(context: Context?, bundle: Bundle?) { 18 | EasyToast.DEFAULT.show("线程切换器测试动作路由被启动,启动线程为:${Thread.currentThread().name}" ) 19 | } 20 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/action/SayHelloAction.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.action 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import com.haoge.easyandroid.easy.EasyToast 6 | import com.lzh.nonview.router.anno.RouterRule 7 | import com.lzh.nonview.router.route.ActionSupport 8 | 9 | /** 10 | * @author haoge on 2018/5/10 11 | */ 12 | @RouterRule("say/hello") 13 | class SayHelloAction:ActionSupport() { 14 | override fun onRouteTrigger(context: Context?, bundle: Bundle?) { 15 | EasyToast.DEFAULT.show("Hello! this is an action route!") 16 | } 17 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/executor/TestExecutor.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.executor 2 | 3 | import java.util.concurrent.Executor 4 | import java.util.concurrent.ExecutorService 5 | import java.util.concurrent.Executors 6 | 7 | /** 8 | * @author haoge on 2018/5/10 9 | */ 10 | class TestExecutor : Executor{ 11 | 12 | val pool:ExecutorService = Executors.newSingleThreadExecutor { runnable -> 13 | val thread:Thread = Thread(runnable) 14 | thread.name = "action_annotation_executor" 15 | return@newSingleThreadExecutor thread 16 | } 17 | 18 | override fun execute(command: Runnable?) { 19 | pool.execute(command) 20 | } 21 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/interceptors/DefaultInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.interceptors 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import com.lzh.nonview.router.demo.LoginActivity 7 | import com.lzh.nonview.router.demo.manager.DataManager 8 | import com.lzh.nonview.router.extras.RouteBundleExtras 9 | import com.lzh.nonview.router.interceptors.RouteInterceptor 10 | 11 | /** 12 | * 默认拦截器。所有路由(除掉直接以浏览器方式打开的路由)均会触发此拦截器。 13 | * 14 | * 可以用作登录开关控制:为登录拦截添加动态登录控制。 15 | * 16 | * DATE: 2018/5/8 17 | * AUTHOR: haoge 18 | */ 19 | class DefaultInterceptor : RouteInterceptor { 20 | override fun intercept(uri: Uri?, extras: RouteBundleExtras?, context: Context?): Boolean { 21 | // 当路由启动链接为需要进行登录检查时,且当前未登录,进行拦截 22 | return checkRequestLogin(uri) && !DataManager.login 23 | } 24 | 25 | override fun onIntercepted(uri: Uri?, extras: RouteBundleExtras?, context: Context?) { 26 | // 拦截后,将数据传递到登录页去。待登录完成后进行路由恢复 27 | val intent: Intent = Intent(context, LoginActivity::class.java) 28 | intent.putExtra("uri", uri) 29 | intent.putExtra("extras", extras) 30 | context?.startActivity(intent) 31 | } 32 | 33 | // 判断是否为要求进行登录检查的路由链接。 34 | private fun checkRequestLogin(uri: Uri?):Boolean { 35 | return uri?.getQueryParameter("requestLogin") == "1" 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/interceptors/LoginInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.interceptors 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import com.lzh.nonview.router.demo.LoginActivity 7 | import com.lzh.nonview.router.demo.manager.DataManager 8 | import com.lzh.nonview.router.extras.RouteBundleExtras 9 | import com.lzh.nonview.router.interceptors.RouteInterceptor 10 | 11 | /** 12 | * 登录拦截器。 13 | */ 14 | class LoginInterceptor : RouteInterceptor { 15 | 16 | override fun onIntercepted(uri: Uri?, extras: RouteBundleExtras?, context: Context?) { 17 | // 拦截后,将数据传递到登录页去。待登录完成后进行路由恢复 18 | val intent:Intent = Intent(context, LoginActivity::class.java) 19 | intent.putExtra("uri", uri) 20 | intent.putExtra("extras", extras) 21 | context?.startActivity(intent) 22 | } 23 | 24 | override fun intercept(uri: Uri?, extras: RouteBundleExtras?, context: Context?): Boolean { 25 | // 判断是否已登录。已登录:不拦截、登录:拦截 26 | return !DataManager.login 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/manager/DataManager.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.manager 2 | 3 | /** 4 | * 一个本地的内存数据管理容器。提供登录状态进行使用。 5 | * DATE: 2018/5/8 6 | * AUTHOR: haoge 7 | */ 8 | object DataManager { 9 | var username:String = "HaogeStudio" 10 | var login:Boolean = false 11 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/lzh/nonview/router/demo/pojo/User.kt: -------------------------------------------------------------------------------- 1 | package com.lzh.nonview.router.demo.pojo 2 | 3 | import android.os.Bundle 4 | import com.lzh.compiler.parceler.Parceler 5 | import com.lzh.compiler.parceler.annotation.Arg 6 | import com.lzh.nonview.router.anno.RouterRule 7 | import com.lzh.nonview.router.route.ICreatorInjector 8 | 9 | /** 10 | * DATE: 2018/5/8 11 | * AUTHOR: haoge 12 | */ 13 | @RouterRule("creator/user") 14 | class User():ICreatorInjector { 15 | override fun inject(bundle: Bundle?) { 16 | Parceler.toEntity(this, bundle) 17 | } 18 | 19 | @Arg 20 | var name:String? = null 21 | 22 | constructor(name:String?):this() { 23 | this.name = name 24 | } 25 | 26 | override fun toString(): String { 27 | return "User(name=$name)" 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /sample/src/main/res/anim/anim_fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/anim/anim_fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_intent_printer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 |