├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── meepo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── cn │ │ └── nekocode │ │ └── meepo │ │ ├── CallMethod.java │ │ ├── Meepo.java │ │ ├── MeepoUtils.java │ │ ├── adapter │ │ ├── ActivityCallAdapter.java │ │ └── CallAdapter.java │ │ ├── annotation │ │ ├── Action.java │ │ ├── BundleParam.java │ │ ├── Clazz.java │ │ ├── ClazzName.java │ │ ├── Flags.java │ │ ├── Path.java │ │ ├── PathParam.java │ │ ├── QueryMapParam.java │ │ ├── QueryParam.java │ │ ├── RequestCode.java │ │ └── RequestCodeParam.java │ │ ├── config │ │ ├── Config.java │ │ └── UriConfig.java │ │ └── parser │ │ ├── DefaultParser.java │ │ └── Parser.java │ └── test │ ├── AndroidManifest.xml │ └── java │ └── cn │ └── nekocode │ └── meepo │ ├── AActivity.kt │ ├── BActivity.kt │ ├── MeepoTest.kt │ └── MeepoUtilsTest.kt ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── cn │ │ └── nekocode │ │ └── meepo │ │ └── sample │ │ ├── AActivity.java │ │ ├── BActivity.java │ │ ├── MainActivity.java │ │ ├── custom │ │ ├── ModuleCallAdapter.java │ │ ├── ModuleConfig.java │ │ ├── TestModule.java │ │ └── TestModule2.java │ │ └── router │ │ ├── ActivityRouter.java │ │ └── ModuleRouter.java │ └── res │ ├── layout │ ├── activity_child.xml │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | *.iml 10 | *.apk 11 | *.jobf 12 | keystore.properties -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | script: ./gradlew check 4 | 5 | after_success: 6 | - bash <(curl -s https://codecov.io/bash) 7 | 8 | android: 9 | components: 10 | - android-28 11 | - build-tools-28.0.3 12 | 13 | before_cache: 14 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 15 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 16 | 17 | cache: 18 | directories: 19 | - $HOME/.gradle/caches/ 20 | - $HOME/.gradle/wrapper/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meepo 2 | [![Build Status](https://travis-ci.com/nekocode/Meepo.svg?branch=master)](https://travis-ci.com/nekocode/Meepo) [![codecov](https://codecov.io/gh/nekocode/Meepo/branch/master/graph/badge.svg)](https://codecov.io/gh/nekocode/Meepo) 3 | 4 | Meepo is a router generator for android, similar to **[retrofit](https://github.com/square/retrofit)**. You can use it to create routers for Activities, Fragments and even any things. 5 | 6 | 7 | ### Integration 8 | 9 | Replace the `${last-version}` in below code to number [![Release](https://jitpack.io/v/nekocode/Meepo.svg)](https://jitpack.io/#nekocode/Meepo) . 10 | 11 | ```gradle 12 | repositories { 13 | maven { url "https://jitpack.io" } 14 | } 15 | dependencies { 16 | implementation "com.github.nekocode:Meepo:${last-version}" 17 | } 18 | ``` 19 | 20 | 21 | ## Usage 22 | 23 | Firstly, declare a router interface: 24 | 25 | ```java 26 | public interface Router { 27 | @Path("user/{user_id}/detail") 28 | @RequestCode(1) 29 | boolean gotoUserDetail(Context context, @PathParam("user_id") String userId, 30 | @QueryParam("show_title") boolean showTitle); 31 | 32 | @Clazz(StoreActivity.class) 33 | @Flags(Intent.FLAG_ACTIVITY_SINGLE_TOP) 34 | void gotoB(Context context, @BundleParam("title") String title, 35 | @RequestCodeParam int requestCode); 36 | } 37 | ``` 38 | 39 | If you want to open your Activity via URI, you need to add a uri intent filter to the corresponding `` element in the manifest file: 40 | 41 | ```xml 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | ``` 54 | 55 | And then obtain an implementation of your router interface: 56 | 57 | ```java 58 | final Meepo meepo = new Meepo.Builder() 59 | .config(new UriConfig().scheme("meepo").host("meepo.com")) 60 | .build(); 61 | 62 | final Router router = meepo.create(Router.class); 63 | ``` 64 | 65 | Now, you can invoke the router's navigation methods: 66 | 67 | ```java 68 | boolean isSucess = router.gotoUserDetail(this, "123", true); 69 | ``` 70 | 71 | 72 | ## Router Annotation 73 | 74 | This library currently provides the following annotations: 75 | 76 | | Method Annotation | Description | 77 | | :----- | :------ | 78 | | `@Clazz` | Class of target Activity | 79 | | `@ClazzName` | Class name of target Activity | 80 | | `@Path` | URI path and mime type of target Activity | 81 | | `@Action` | Action of Intent | 82 | | `@Flags` | Flags of Intent | 83 | | `@RequestCode` | Request code of Intent | 84 | 85 | | Parameter Annotation | Description | 86 | | :----- | :------ | 87 | | `@BundleParam` | Parameter that will be put into the extra of Intent | 88 | | `@PathParam` | Parameter that will be used to replace the URI path's corresponding replacement block | 89 | | `@QueryParam` | Query parameter of the URI | 90 | | `@QueryMapParam` | Map of Query parameters | 91 | | `@RequestCodeParam` | Request code of Intent | 92 | 93 | 94 | ## Custom Parser and CallAdapter 95 | 96 | You can create custom Parser and CallAdapter. You can reference the **[sample](sample/src/main/java/cn/nekocode/meepo/sample/custom)** module. It means that you can create router for anything. 97 | 98 | ```java 99 | final ModuleRouter moduleRouter = new Meepo.Builder() 100 | .config(new ModuleConfig("TEST")) 101 | .parser(new ModuleParser()) 102 | .adapter(new ModuleCallAdapter()) 103 | .build() 104 | .create(ModuleRouter.class); 105 | ``` 106 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | } 6 | dependencies { 7 | classpath "com.android.tools.build:gradle:3.3.0" 8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20" 9 | classpath "com.github.dcendents:android-maven-gradle-plugin:1.5" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | jcenter() 16 | google() 17 | } 18 | group="com.github.nekocode" 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nekocode/Meepo/4e558cdb5c9d38a935aa9c4c535cf2b0bcdf20ee/gradle.properties -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nekocode/Meepo/4e558cdb5c9d38a935aa9c4c535cf2b0bcdf20ee/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jan 27 11:40:57 CST 2019 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.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /meepo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /meepo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.library" 2 | apply plugin: "kotlin-android" 3 | apply plugin: "com.github.dcendents.android-maven" 4 | apply plugin: "jacoco" 5 | 6 | android { 7 | compileSdkVersion 28 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 28 11 | } 12 | lintOptions { 13 | abortOnError false 14 | } 15 | } 16 | 17 | dependencies { 18 | implementation fileTree(dir: "libs", include: ["*.jar"]) 19 | compileOnly "com.android.support:support-annotations:28.0.0" 20 | 21 | testImplementation "junit:junit:4.12" 22 | testImplementation "org.robolectric:robolectric:4.1" 23 | testImplementation "androidx.test:core:1.1.0" 24 | testImplementation "org.mockito:mockito-core:2.23.4" 25 | testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.20" 26 | } 27 | 28 | task jacocoTestReport(type: JacocoReport, dependsOn: "testReleaseUnitTest") { 29 | reports { 30 | xml.enabled = true 31 | html.enabled = true 32 | } 33 | 34 | def fileFilter = [ 35 | "**/R.class", 36 | '**/R$*.class', 37 | "**/BuildConfig.*", 38 | "**/Manifest*.*", 39 | "**/*Test*.*", 40 | "android/**/*.*" 41 | ] 42 | def classTree = fileTree(dir: "${buildDir}/intermediates/javac", excludes: fileFilter) 43 | def mainSrc = "${project.projectDir}/src/main/java" 44 | 45 | sourceDirectories = files([mainSrc]) 46 | classDirectories = files([classTree]) 47 | executionData = files("${buildDir}/jacoco/testReleaseUnitTest.exec") 48 | } 49 | tasks.withType(Test) { 50 | jacoco.includeNoLocationClasses = true 51 | } 52 | check.dependsOn jacocoTestReport 53 | 54 | task androidSourcesJar(type: Jar) { 55 | classifier = "sources" 56 | baseName = archivesBaseName 57 | from android.sourceSets.main.java.srcDirs 58 | } 59 | 60 | artifacts { 61 | archives androidSourcesJar 62 | } 63 | -------------------------------------------------------------------------------- /meepo/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/nekocode/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /meepo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/CallMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo; 18 | 19 | import android.os.Bundle; 20 | import android.support.annotation.NonNull; 21 | import android.support.annotation.Nullable; 22 | import android.text.TextUtils; 23 | 24 | import java.util.ArrayList; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | /** 29 | * @author nekocode (nekocode.cn@gmail.com) 30 | */ 31 | public class CallMethod { 32 | private Class clazz; 33 | private String clazzName; 34 | private String action; 35 | private Integer flags; 36 | private Integer requestCode; 37 | private String mimeType; 38 | 39 | private ArrayList pathSegments = new ArrayList<>(); // [segmentString, position, ...] 40 | private HashMap queryPositions = new HashMap<>(); // {key: position, ...} 41 | private ArrayList queryMapPositions = new ArrayList<>(); // [position, position, ...] 42 | private HashMap bundlePositions = new HashMap<>(); 43 | private Integer requestCodePosition; 44 | 45 | 46 | @Nullable 47 | public Class getClazz() { 48 | return clazz; 49 | } 50 | 51 | public void setClazz(@Nullable Class clazz) { 52 | this.clazz = clazz; 53 | } 54 | 55 | @Nullable 56 | public String getClazzName() { 57 | return clazzName; 58 | } 59 | 60 | public void setClazzName(@Nullable String clazzName) { 61 | this.clazzName = clazzName; 62 | } 63 | 64 | @Nullable 65 | public String getAction() { 66 | return action; 67 | } 68 | 69 | public void setAction(@Nullable String action) { 70 | this.action = action; 71 | } 72 | 73 | @Nullable 74 | public Integer getFlags() { 75 | return flags; 76 | } 77 | 78 | public void setFlags(int flags) { 79 | this.flags = flags; 80 | } 81 | 82 | public void setRequestCode(int requestCode) { 83 | this.requestCode = requestCode; 84 | } 85 | 86 | public void setRequestCodePosition(@Nullable Integer requestCodePosition) { 87 | this.requestCodePosition = requestCodePosition; 88 | } 89 | 90 | @Nullable 91 | public Integer getRequestCode(@NonNull Object[] args) { 92 | return requestCodePosition == null ? requestCode : (Integer) args[requestCodePosition]; 93 | } 94 | 95 | @Nullable 96 | public String getMimeType() { 97 | return mimeType; 98 | } 99 | 100 | public void setMimeType(@Nullable String mimeType) { 101 | this.mimeType = mimeType; 102 | } 103 | 104 | 105 | 106 | @Nullable 107 | public String getUri(@Nullable String scheme, @Nullable String host, @NonNull Object[] args) { 108 | if (TextUtils.isEmpty(scheme)) { 109 | return null; 110 | } 111 | final String hostUri = scheme + "://" + (TextUtils.isEmpty(host) ? "" : host + "/"); 112 | final String path = getPath(args); 113 | final String queryString = getQueryString(args); 114 | if (TextUtils.isEmpty(path)) { 115 | return null; 116 | } 117 | return hostUri + path + queryString; 118 | } 119 | 120 | public void addPathSegment(@NonNull Object pathSegment) { 121 | this.pathSegments.add(pathSegment); 122 | } 123 | 124 | public void addQueryPositions(@NonNull String key, @NonNull Integer queryPosition) { 125 | this.queryPositions.put(key, queryPosition); 126 | } 127 | 128 | public void addQueryMapPositions(@NonNull Integer queryMapPosition) { 129 | this.queryMapPositions.add(queryMapPosition); 130 | } 131 | 132 | public void addBundlePositions(@NonNull String key, @NonNull Integer bundlePosition) { 133 | this.bundlePositions.put(key, bundlePosition); 134 | } 135 | 136 | @NonNull 137 | private String getPath(@NonNull Object[] args) { 138 | final StringBuilder stringBuilder = new StringBuilder(); 139 | 140 | for (Object segment : pathSegments) { 141 | if (segment instanceof String) { 142 | stringBuilder.append((String) segment); 143 | } else if (segment instanceof Integer) { 144 | stringBuilder.append((String) args[(int) segment]); 145 | } 146 | } 147 | 148 | return stringBuilder.toString(); 149 | } 150 | 151 | @NonNull 152 | private String getQueryString(@NonNull Object[] args) { 153 | final StringBuilder stringBuilder = new StringBuilder("?"); 154 | 155 | int count = 0; 156 | String key, value; 157 | Object arg; 158 | for (Map.Entry entry : queryPositions.entrySet()) { 159 | key = entry.getKey(); 160 | arg = args[entry.getValue()]; 161 | if (arg == null) continue; 162 | value = arg.toString(); 163 | 164 | if (count++ == 0) { 165 | stringBuilder.append(key).append("=").append(value); 166 | } else { 167 | stringBuilder.append("&").append(key).append("=").append(value); 168 | } 169 | } 170 | 171 | Map queryMap; 172 | for (Integer position : queryMapPositions) { 173 | arg = args[position]; 174 | if (arg == null) continue; 175 | queryMap = (Map) arg; 176 | 177 | Object tmpValue; 178 | for (Map.Entry entry : queryMap.entrySet()) { 179 | key = entry.getKey(); 180 | tmpValue = entry.getValue(); 181 | if (tmpValue == null) continue; 182 | value = tmpValue.toString(); 183 | 184 | if (count++ == 0) { 185 | stringBuilder.append(key).append("=").append(value); 186 | } else { 187 | stringBuilder.append("&").append(key).append("=").append(value); 188 | } 189 | } 190 | } 191 | 192 | return count == 0 ? "" : stringBuilder.toString(); 193 | } 194 | 195 | @NonNull 196 | public Bundle getBundle(@NonNull Object[] args) { 197 | final Bundle bundle = new Bundle(); 198 | 199 | String key; 200 | Object value; 201 | for (Map.Entry entry : bundlePositions.entrySet()) { 202 | key = entry.getKey(); 203 | value = args[entry.getValue()]; 204 | if (value == null) continue; 205 | 206 | MeepoUtils.putValueToBundle(bundle, key, value); 207 | } 208 | 209 | return bundle; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/Meepo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo; 18 | 19 | import android.support.annotation.NonNull; 20 | import android.support.annotation.Nullable; 21 | 22 | import java.lang.reflect.InvocationHandler; 23 | import java.lang.reflect.Method; 24 | import java.lang.reflect.Proxy; 25 | import java.util.Map; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | 28 | import cn.nekocode.meepo.adapter.ActivityCallAdapter; 29 | import cn.nekocode.meepo.adapter.CallAdapter; 30 | import cn.nekocode.meepo.config.Config; 31 | import cn.nekocode.meepo.config.UriConfig; 32 | import cn.nekocode.meepo.parser.DefaultParser; 33 | import cn.nekocode.meepo.parser.Parser; 34 | 35 | /** 36 | * @author nekocode (nekocode.cn@gmail.com) 37 | */ 38 | public final class Meepo { 39 | private Config config; 40 | private Parser parser; 41 | private CallAdapter callAdapter; 42 | 43 | 44 | private Meepo(@NonNull Builder builder) { 45 | this.config = builder.config; 46 | this.parser = builder.parser; 47 | this.callAdapter = builder.callAdapter; 48 | } 49 | 50 | @NonNull 51 | public T create(@NonNull Class routerClass) { 52 | return (T) Proxy.newProxyInstance(routerClass.getClassLoader(), 53 | new Class[]{routerClass}, new MeepoInvocationHandler()); 54 | } 55 | 56 | private class MeepoInvocationHandler implements InvocationHandler { 57 | private final Map methodCache = new ConcurrentHashMap<>(); 58 | 59 | 60 | @Override 61 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 62 | return callAdapter.call(config, getCallMethod(method), args); 63 | } 64 | 65 | private CallMethod getCallMethod(Method method) { 66 | CallMethod result = methodCache.get(method); 67 | if (result != null) return result; 68 | 69 | synchronized (methodCache) { 70 | result = parser.parseMethod(config, method); 71 | methodCache.put(method, result); 72 | } 73 | return result; 74 | } 75 | } 76 | 77 | public static class Builder { 78 | private Config config; 79 | private Parser parser; 80 | private CallAdapter callAdapter; 81 | 82 | @NonNull 83 | public Builder config(@NonNull Config config) { 84 | this.config = config; 85 | return this; 86 | } 87 | 88 | @NonNull 89 | public Builder parser(@Nullable Parser parser) { 90 | this.parser = parser; 91 | return this; 92 | } 93 | 94 | @NonNull 95 | public Builder adapter(@Nullable CallAdapter callAdapter) { 96 | this.callAdapter = callAdapter; 97 | return this; 98 | } 99 | 100 | @NonNull 101 | public Meepo build() { 102 | if (config == null) config(new UriConfig()); 103 | if (parser == null) parser(new DefaultParser()); 104 | if (callAdapter == null) adapter(new ActivityCallAdapter()); 105 | return new Meepo(this); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/MeepoUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo; 18 | 19 | import android.content.Context; 20 | import android.os.Build; 21 | import android.os.Bundle; 22 | import android.os.IBinder; 23 | import android.os.Parcelable; 24 | import android.support.annotation.NonNull; 25 | import android.support.annotation.Nullable; 26 | import android.util.Size; 27 | import android.util.SizeF; 28 | import android.util.SparseArray; 29 | 30 | import java.io.Serializable; 31 | import java.util.ArrayList; 32 | import java.util.Locale; 33 | 34 | /** 35 | * @author nekocode (nekocode.cn@gmail.com) 36 | */ 37 | public class MeepoUtils { 38 | 39 | public static boolean isTextNotEmpty(@Nullable CharSequence str) { 40 | return str != null && str.length() > 0; 41 | } 42 | 43 | @Nullable 44 | public static Context getContextFromFirstParameter(Object[] parameters) { 45 | final boolean hasContext = (parameters.length > 0) && 46 | (parameters[0] instanceof Context || parameters[0] == null); 47 | if (hasContext) { 48 | return (Context) parameters[0]; 49 | } else { 50 | throw new RuntimeException("First parameter must be context."); 51 | } 52 | } 53 | 54 | public static void putValueToBundle( 55 | @NonNull Bundle bundle, @NonNull String key, @NonNull Object value) { 56 | if (value instanceof String) { 57 | bundle.putString(key, (String) value); 58 | } else if (value instanceof Integer) { 59 | bundle.putInt(key, (int) value); 60 | } else if (value instanceof Boolean) { 61 | bundle.putBoolean(key, (boolean) value); 62 | } else if (value instanceof Long) { 63 | bundle.putLong(key, (long) value); 64 | } else if (value instanceof Short) { 65 | bundle.putShort(key, (short) value); 66 | } else if (value instanceof Double) { 67 | bundle.putDouble(key, (double) value); 68 | } else if (value instanceof Float) { 69 | bundle.putFloat(key, (float) value); 70 | } else if (value instanceof Character) { 71 | bundle.putChar(key, (char) value); 72 | } else if (value instanceof Byte) { 73 | bundle.putByte(key, (byte) value); 74 | } else if (value instanceof CharSequence) { 75 | bundle.putCharSequence(key, (CharSequence) value); 76 | } else if (value instanceof Bundle) { 77 | bundle.putBundle(key, (Bundle) value); 78 | } else if (value instanceof Parcelable) { 79 | bundle.putParcelable(key, (Parcelable) value); 80 | } else if (value instanceof String[]) { 81 | bundle.putStringArray(key, (String[]) value); 82 | } else if (value instanceof int[]) { 83 | bundle.putIntArray(key, (int[]) value); 84 | } else if (value instanceof boolean[]) { 85 | bundle.putBooleanArray(key, (boolean[]) value); 86 | } else if (value instanceof long[]) { 87 | bundle.putLongArray(key, (long[]) value); 88 | } else if (value instanceof short[]) { 89 | bundle.putShortArray(key, (short[]) value); 90 | } else if (value instanceof double[]) { 91 | bundle.putDoubleArray(key, (double[]) value); 92 | } else if (value instanceof float[]) { 93 | bundle.putFloatArray(key, (float[]) value); 94 | } else if (value instanceof char[]) { 95 | bundle.putCharArray(key, (char[]) value); 96 | } else if (value instanceof byte[]) { 97 | bundle.putByteArray(key, (byte[]) value); 98 | } else if (value instanceof CharSequence[]) { 99 | bundle.putCharSequenceArray(key, (CharSequence[]) value); 100 | } else if (value instanceof Parcelable[]) { 101 | bundle.putParcelableArray(key, (Parcelable[]) value); 102 | } else if (value instanceof ArrayList) { 103 | bundle.putIntegerArrayList(key, (ArrayList) value); 104 | } else if (value instanceof SparseArray) { 105 | bundle.putSparseParcelableArray(key, (SparseArray) value); 106 | } else { 107 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 108 | if (value instanceof IBinder) { 109 | bundle.putBinder(key, (IBinder) value); 110 | return; 111 | } 112 | } 113 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 114 | if (value instanceof Size) { 115 | bundle.putSize(key, (Size) value); 116 | return; 117 | } else if (value instanceof SizeF) { 118 | bundle.putSizeF(key, (SizeF) value); 119 | return; 120 | } 121 | } 122 | if (value instanceof Serializable) { 123 | bundle.putSerializable(key, (Serializable) value); 124 | return; 125 | } 126 | 127 | throw new RuntimeException(String.format(Locale.getDefault(), 128 | "Arguments extra %s has wrong type %s.", key, value.getClass().getName())); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/adapter/ActivityCallAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.adapter; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.net.Uri; 23 | import android.support.annotation.NonNull; 24 | import android.support.annotation.Nullable; 25 | 26 | import cn.nekocode.meepo.CallMethod; 27 | import cn.nekocode.meepo.config.Config; 28 | import cn.nekocode.meepo.MeepoUtils; 29 | import cn.nekocode.meepo.config.UriConfig; 30 | 31 | /** 32 | * @author nekocode (nekocode.cn@gmail.com) 33 | */ 34 | public class ActivityCallAdapter implements CallAdapter { 35 | 36 | @Nullable 37 | @Override 38 | public Boolean call(@NonNull Config config, @NonNull CallMethod method, @NonNull Object[] args) { 39 | final Context context = MeepoUtils.getContextFromFirstParameter(args); 40 | if (context == null) { 41 | return false; 42 | } 43 | 44 | String uri = null; 45 | if (config instanceof UriConfig) { 46 | final UriConfig uriConfig = (UriConfig) config; 47 | uri = method.getUri(uriConfig.getScheme(), uriConfig.getHost(), args); 48 | } 49 | 50 | final Class clazz = method.getClazz(); 51 | final Intent intent = new Intent(); 52 | if (clazz != null) { 53 | intent.setClass(context, clazz); 54 | } 55 | final String clazzName = method.getClazzName(); 56 | if (clazzName != null) { 57 | intent.setClassName(context, clazzName); 58 | } 59 | if (uri != null) { 60 | intent.setDataAndType(Uri.parse(uri), method.getMimeType()); 61 | } 62 | intent.putExtras(method.getBundle(args)); 63 | final Integer flags = method.getFlags(); 64 | if (flags != null) { 65 | intent.setFlags(flags); 66 | } 67 | intent.setAction(method.getAction()); 68 | 69 | if (intent.resolveActivity(context.getPackageManager()) != null) { 70 | final Integer requestCode = method.getRequestCode(args); 71 | 72 | if (requestCode != null && context instanceof Activity) { 73 | ((Activity) context).startActivityForResult(intent, requestCode); 74 | 75 | } else { 76 | context.startActivity(intent); 77 | } 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/adapter/CallAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.adapter; 18 | 19 | import android.support.annotation.NonNull; 20 | import android.support.annotation.Nullable; 21 | 22 | import cn.nekocode.meepo.CallMethod; 23 | import cn.nekocode.meepo.config.Config; 24 | 25 | /** 26 | * @author nekocode (nekocode.cn@gmail.com) 27 | */ 28 | public interface CallAdapter { 29 | 30 | @Nullable 31 | T call(@NonNull Config config, @NonNull CallMethod method, @NonNull Object[] args); 32 | } 33 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/Action.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Action { 33 | String value(); 34 | } 35 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/BundleParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.PARAMETER; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(PARAMETER) 31 | @Retention(RUNTIME) 32 | public @interface BundleParam { 33 | String value(); 34 | } -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/Clazz.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Clazz { 33 | java.lang.Class value(); 34 | } 35 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/ClazzName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface ClazzName { 33 | String value(); 34 | } 35 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/Flags.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Flags { 33 | int value(); 34 | } 35 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/Path.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface Path { 33 | String value(); 34 | String mimeType() default ""; 35 | } 36 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/PathParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.PARAMETER; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(PARAMETER) 31 | @Retention(RUNTIME) 32 | public @interface PathParam { 33 | String value(); 34 | } -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/QueryMapParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.PARAMETER; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(PARAMETER) 31 | @Retention(RUNTIME) 32 | public @interface QueryMapParam { 33 | } -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/QueryParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.PARAMETER; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(PARAMETER) 31 | @Retention(RUNTIME) 32 | public @interface QueryParam { 33 | String value(); 34 | } -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/RequestCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.METHOD; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(METHOD) 31 | @Retention(RUNTIME) 32 | public @interface RequestCode { 33 | int value(); 34 | } 35 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/annotation/RequestCodeParam.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.PARAMETER; 24 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | @Documented 30 | @Target(PARAMETER) 31 | @Retention(RUNTIME) 32 | public @interface RequestCodeParam { 33 | } 34 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/config/Config.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.config; 18 | 19 | /** 20 | * @author nekocode (nekocode.cn@gmail.com) 21 | */ 22 | public interface Config { 23 | } 24 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/config/UriConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.config; 18 | 19 | import android.support.annotation.Nullable; 20 | 21 | /** 22 | * @author nekocode (nekocode.cn@gmail.com) 23 | */ 24 | public class UriConfig implements Config { 25 | private String scheme; 26 | private String host; 27 | 28 | 29 | public UriConfig scheme(@Nullable String scheme) { 30 | this.scheme = scheme; 31 | return this; 32 | } 33 | 34 | public UriConfig host(@Nullable String host) { 35 | this.host = host; 36 | return this; 37 | } 38 | 39 | public String getScheme() { 40 | return scheme; 41 | } 42 | 43 | public String getHost() { 44 | return host; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/parser/DefaultParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.parser; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import java.lang.annotation.Annotation; 22 | import java.lang.reflect.Method; 23 | import java.util.HashMap; 24 | import java.util.Locale; 25 | 26 | import cn.nekocode.meepo.CallMethod; 27 | import cn.nekocode.meepo.annotation.RequestCode; 28 | import cn.nekocode.meepo.annotation.RequestCodeParam; 29 | import cn.nekocode.meepo.annotation.ClazzName; 30 | import cn.nekocode.meepo.config.Config; 31 | import cn.nekocode.meepo.MeepoUtils; 32 | import cn.nekocode.meepo.annotation.BundleParam; 33 | import cn.nekocode.meepo.annotation.PathParam; 34 | import cn.nekocode.meepo.annotation.QueryParam; 35 | import cn.nekocode.meepo.annotation.QueryMapParam; 36 | import cn.nekocode.meepo.annotation.Action; 37 | import cn.nekocode.meepo.annotation.Clazz; 38 | import cn.nekocode.meepo.annotation.Flags; 39 | import cn.nekocode.meepo.annotation.Path; 40 | 41 | /** 42 | * @author nekocode (nekocode.cn@gmail.com) 43 | */ 44 | public class DefaultParser implements Parser { 45 | 46 | @NonNull 47 | @Override 48 | public CallMethod parseMethod(@NonNull Config config, @NonNull Method method) { 49 | final Annotation[] methodAnnotations = method.getAnnotations(); 50 | final Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations(); 51 | 52 | final CallMethod callMethod = new CallMethod(); 53 | parseMethodAnnotations(callMethod, methodAnnotations, parameterAnnotationsArray); 54 | parseParameterAnnotation(callMethod, parameterAnnotationsArray); 55 | 56 | return callMethod; 57 | } 58 | 59 | protected void parseMethodAnnotations( 60 | @NonNull CallMethod callMethod, @NonNull Annotation[] methodAnnotations, @NonNull Annotation[][] parameterAnnotationsArray) { 61 | 62 | final HashMap positions = new HashMap<>(); 63 | for (int i = 0; i < parameterAnnotationsArray.length; i++) { 64 | final Annotation[] annotations = parameterAnnotationsArray[i]; 65 | 66 | for (Annotation annotation : annotations) { 67 | if (annotation instanceof PathParam) { 68 | positions.put(((PathParam) annotation).value(), i); 69 | } 70 | } 71 | } 72 | 73 | for (Annotation annotation : methodAnnotations) { 74 | if (annotation instanceof Clazz) { 75 | callMethod.setClazz(((Clazz) annotation).value()); 76 | 77 | } else if (annotation instanceof ClazzName) { 78 | callMethod.setClazzName(((ClazzName) annotation).value()); 79 | 80 | } else if (annotation instanceof Path) { 81 | final Path path = (Path) annotation; 82 | final String segments[] = path.value().split("[{}]"); 83 | 84 | for (int i = 0; i < segments.length; i++) { 85 | final String segment = segments[i]; 86 | 87 | if (i % 2 == 0) { 88 | if (MeepoUtils.isTextNotEmpty(segment)) { 89 | callMethod.addPathSegment(segment); 90 | } 91 | } else { 92 | final Integer position = positions.get(segment); 93 | if (position != null) { 94 | callMethod.addPathSegment(position); 95 | } else { 96 | throw new RuntimeException(String.format(Locale.getDefault(), 97 | "@Path(\"%s\") not found.", segment)); 98 | } 99 | } 100 | } 101 | 102 | if (MeepoUtils.isTextNotEmpty(path.mimeType())) { 103 | callMethod.setMimeType(path.mimeType()); 104 | } 105 | 106 | } else if (annotation instanceof Flags) { 107 | callMethod.setFlags(((Flags) annotation).value()); 108 | 109 | } else if (annotation instanceof Action) { 110 | callMethod.setAction(((Action) annotation).value()); 111 | 112 | } else if (annotation instanceof RequestCode) { 113 | callMethod.setRequestCode(((RequestCode) annotation).value()); 114 | } 115 | } 116 | } 117 | 118 | protected void parseParameterAnnotation(@NonNull CallMethod callMethod, @NonNull Annotation[][] parameterAnnotationsArray) { 119 | for (int i = 0; i < parameterAnnotationsArray.length; i++) { 120 | final Annotation[] annotations = parameterAnnotationsArray[i]; 121 | 122 | for (Annotation annotation : annotations) { 123 | if (annotation instanceof BundleParam) { 124 | callMethod.addBundlePositions(((BundleParam) annotation).value(), i); 125 | 126 | } else if (annotation instanceof QueryParam) { 127 | callMethod.addQueryPositions(((QueryParam) annotation).value(), i); 128 | 129 | } else if (annotation instanceof QueryMapParam) { 130 | callMethod.addQueryMapPositions(i); 131 | 132 | } else if (annotation instanceof RequestCodeParam) { 133 | callMethod.setRequestCodePosition(i); 134 | } 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /meepo/src/main/java/cn/nekocode/meepo/parser/Parser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo.parser; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import java.lang.reflect.Method; 22 | 23 | import cn.nekocode.meepo.CallMethod; 24 | import cn.nekocode.meepo.config.Config; 25 | 26 | /** 27 | * @author nekocode (nekocode.cn@gmail.com) 28 | */ 29 | public interface Parser { 30 | @NonNull 31 | CallMethod parseMethod(@NonNull Config config, @NonNull Method method); 32 | } 33 | -------------------------------------------------------------------------------- /meepo/src/test/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /meepo/src/test/java/cn/nekocode/meepo/AActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo 18 | 19 | import android.app.Activity 20 | 21 | /** 22 | * @author nekocode (nekocode.cn@gmail.com) 23 | */ 24 | class AActivity : Activity() -------------------------------------------------------------------------------- /meepo/src/test/java/cn/nekocode/meepo/BActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo 18 | 19 | import android.app.Activity 20 | 21 | /** 22 | * @author nekocode (nekocode.cn@gmail.com) 23 | */ 24 | class BActivity : Activity() -------------------------------------------------------------------------------- /meepo/src/test/java/cn/nekocode/meepo/MeepoTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo 18 | 19 | import android.content.Context 20 | import android.content.Intent 21 | import cn.nekocode.meepo.annotation.* 22 | import cn.nekocode.meepo.config.UriConfig 23 | import org.junit.Assert 24 | import org.junit.Test 25 | import org.junit.runner.RunWith 26 | import org.robolectric.Robolectric 27 | import org.robolectric.RobolectricTestRunner 28 | import org.robolectric.Shadows 29 | import org.robolectric.annotation.Config 30 | import org.robolectric.shadows.ShadowActivity 31 | 32 | /** 33 | * @author nekocode (nekocode.cn@gmail.com) 34 | */ 35 | @RunWith(RobolectricTestRunner::class) 36 | @Config(sdk = [21], manifest = "src/test/AndroidManifest.xml") 37 | class MeepoTest { 38 | companion object { 39 | const val SCHEME = "test" 40 | const val HOST = "test.com" 41 | } 42 | 43 | interface TestRouter { 44 | @Clazz(BActivity::class) 45 | @Flags(Intent.FLAG_ACTIVITY_SINGLE_TOP) 46 | fun clazz(context: Context): Boolean 47 | 48 | @ClazzName("cn.nekocode.meepo.BActivity") 49 | @RequestCode(110) 50 | fun clazzName(context: Context): Boolean 51 | 52 | @Action("testAction") 53 | fun action(context: Context, 54 | @RequestCodeParam requestCode: Int, 55 | @BundleParam("i") i: Int, 56 | @BundleParam("b") b: Boolean, 57 | @BundleParam("s") s: String? 58 | ): Boolean 59 | 60 | @Path(value = "testUri/{id}/end", mimeType = "text/plain") 61 | fun uri(context: Context, 62 | @PathParam("id") id: String, 63 | @QueryParam("on") on: Boolean, 64 | @QueryParam("s") s: String?, 65 | @QueryMapParam queries: Map 66 | ): Boolean 67 | 68 | @Path("x") 69 | fun special(context: Context?): Boolean 70 | 71 | @Path("x/{x}") 72 | fun special2(context: Context): Boolean 73 | } 74 | 75 | @Test 76 | fun test() { 77 | val a = Robolectric.setupActivity(AActivity::class.java) 78 | val shadowA = Shadows.shadowOf(a) 79 | 80 | fun nextActivity() = shadowA.nextStartedActivityForResult 81 | val bClassName = BActivity::class.java.name 82 | var next: ShadowActivity.IntentForResult 83 | 84 | val meepo = Meepo.Builder() 85 | .config(UriConfig().scheme(SCHEME).host(HOST)) 86 | .build() 87 | val router = meepo.create(TestRouter::class.java) 88 | 89 | Assert.assertTrue(router.clazz(a)) 90 | next = nextActivity() 91 | Assert.assertEquals(bClassName, next.intent.component!!.className) 92 | Assert.assertEquals(Intent.FLAG_ACTIVITY_SINGLE_TOP, next.intent.flags) 93 | 94 | Assert.assertTrue(router.clazzName(a)) 95 | next = nextActivity() 96 | Assert.assertEquals(bClassName, next.intent.component!!.className) 97 | Assert.assertEquals(110, next.requestCode) 98 | 99 | Assert.assertTrue(router.action(a, 101, 1, true, null)) 100 | next = nextActivity() 101 | Assert.assertEquals("testAction", next.intent.action) 102 | Assert.assertEquals(101, next.requestCode) 103 | Assert.assertEquals(1, next.intent.getIntExtra("i", 0)) 104 | Assert.assertEquals(true, next.intent.getBooleanExtra("b", false)) 105 | Assert.assertEquals(null, next.intent.getStringExtra("s")) 106 | 107 | val queries = mapOf("test" to 111) 108 | Assert.assertTrue(router.uri(a, "id0", true, null, queries)) 109 | next = nextActivity() 110 | Assert.assertEquals("test://test.com/testUri/id0/end?on=true&test=111", 111 | next.intent.data!!.toString()) 112 | Assert.assertEquals("text/plain", next.intent.type) 113 | 114 | // Special cases 115 | Assert.assertFalse(router.special(null)) 116 | Assert.assertFalse(router.special(a)) 117 | 118 | val e = try { 119 | router.special2(a) 120 | null 121 | } catch (exception: RuntimeException) { 122 | Assert.assertTrue( 123 | exception.message!!.startsWith("@Path(") && 124 | exception.message!!.endsWith(") not found.") 125 | ) 126 | exception 127 | } 128 | Assert.assertNotNull(e) 129 | } 130 | } -------------------------------------------------------------------------------- /meepo/src/test/java/cn/nekocode/meepo/MeepoUtilsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019. nekocode (nekocode.cn@gmail.com) 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 | 17 | package cn.nekocode.meepo 18 | 19 | import android.os.* 20 | import android.text.SpannableString 21 | import android.text.style.AbsoluteSizeSpan 22 | import android.util.Size 23 | import android.util.SizeF 24 | import android.util.SparseArray 25 | import org.junit.Assert 26 | import org.junit.Test 27 | import org.junit.runner.RunWith 28 | import org.robolectric.RobolectricTestRunner 29 | import org.robolectric.annotation.Config 30 | import java.io.Serializable 31 | import android.os.Parcel 32 | import org.robolectric.RuntimeEnvironment 33 | import java.util.* 34 | 35 | /** 36 | * @author nekocode (nekocode.cn@gmail.com) 37 | */ 38 | @RunWith(RobolectricTestRunner::class) 39 | @Config(sdk = [21]) 40 | class MeepoUtilsTest { 41 | 42 | @Test 43 | fun isTextNotEmpty() { 44 | Assert.assertFalse(MeepoUtils.isTextNotEmpty(null)) 45 | Assert.assertFalse(MeepoUtils.isTextNotEmpty("")) 46 | Assert.assertTrue(MeepoUtils.isTextNotEmpty("1")) 47 | } 48 | 49 | @Test 50 | fun getContextFromFirstParameter() { 51 | Assert.assertNull(MeepoUtils.getContextFromFirstParameter(arrayOf(null))) 52 | Assert.assertNotNull(MeepoUtils.getContextFromFirstParameter( 53 | arrayOf(RuntimeEnvironment.systemContext))) 54 | 55 | var e = try { 56 | MeepoUtils.getContextFromFirstParameter(emptyArray()) 57 | null 58 | } catch (exception: RuntimeException) { 59 | Assert.assertEquals("First parameter must be context.", exception.message) 60 | exception 61 | } 62 | Assert.assertNotNull(e) 63 | 64 | e = try { 65 | MeepoUtils.getContextFromFirstParameter(arrayOf(Any())) 66 | null 67 | } catch (exception: RuntimeException) { 68 | Assert.assertEquals("First parameter must be context.", exception.message) 69 | exception 70 | } 71 | Assert.assertNotNull(e) 72 | } 73 | 74 | @Test 75 | fun putValueToBundle() { 76 | val bundle = Bundle() 77 | 78 | class TestBinder : Binder(), Serializable 79 | 80 | val values = arrayOf( 81 | "0", 82 | 0, 83 | true, 84 | 0L, 85 | 0.toShort(), 86 | 0.0, 87 | 0f, 88 | '0', 89 | '0'.toByte(), 90 | SpannableString("0"), // CharSequence 91 | Bundle(), 92 | AbsoluteSizeSpan(0), // Parcelable 93 | 94 | arrayOf("0"), 95 | intArrayOf(0), 96 | booleanArrayOf(true), 97 | longArrayOf(0L), 98 | shortArrayOf(0), 99 | doubleArrayOf(0.0), 100 | floatArrayOf(0f), 101 | charArrayOf('0'), 102 | byteArrayOf('0'.toByte()), 103 | arrayOf(SpannableString("0")), 104 | arrayOf(AbsoluteSizeSpan(0)), 105 | 106 | arrayListOf(0), 107 | SparseArray().also { it.append(0, AbsoluteSizeSpan(0)) }, 108 | TestBinder(), 109 | Size(0, 0), 110 | SizeF(0f, 0f), 111 | Date() // Serializable 112 | ) 113 | 114 | values.forEachIndexed { i, value -> 115 | MeepoUtils.putValueToBundle(bundle, i.toString(), value) 116 | } 117 | 118 | val e = try { 119 | MeepoUtils.putValueToBundle(bundle, "any", Any()) 120 | null 121 | } catch (exception: RuntimeException) { 122 | Assert.assertTrue(exception.message?.contains("has wrong type") ?: false) 123 | exception 124 | } 125 | Assert.assertNotNull(e) 126 | 127 | try { 128 | val parcel = Parcel.obtain() 129 | bundle.writeToParcel(parcel, 0) 130 | parcel.marshall() 131 | parcel.recycle() 132 | } catch (throwable: Throwable) { 133 | Assert.fail() 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "cn.nekocode.meepo.sample" 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | def SCHEME = "meepo_sample" 13 | buildConfigField "String", "SCHEME", "\"$SCHEME\"" 14 | manifestPlaceholders = [ 15 | APPLICATION_ID: applicationId, 16 | SCHEME: "$SCHEME", 17 | ] 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 23 | } 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: "libs", include: ["*.jar"]) 29 | implementation project(":meepo") 30 | implementation "com.android.support:appcompat-v7:28.0.0" 31 | implementation "com.android.support.constraint:constraint-layout:1.1.3" 32 | } 33 | -------------------------------------------------------------------------------- /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/nekocode/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/AActivity.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import cn.nekocode.meepo.sample.router.ActivityRouter; 7 | 8 | /** 9 | * @author nekocode (nekocode.cn@gmail.com) 10 | */ 11 | public class AActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_child); 17 | 18 | setTitle(getIntent().getData().getQueryParameter(ActivityRouter.ARG_TITLE)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/BActivity.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import cn.nekocode.meepo.sample.router.ActivityRouter; 7 | 8 | /** 9 | * @author nekocode (nekocode.cn@gmail.com) 10 | */ 11 | public class BActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_child); 17 | 18 | setTitle(getIntent().getStringExtra(ActivityRouter.ARG_TITLE)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.View; 6 | 7 | import cn.nekocode.meepo.Meepo; 8 | import cn.nekocode.meepo.sample.custom.ModuleCallAdapter; 9 | import cn.nekocode.meepo.sample.custom.ModuleConfig; 10 | import cn.nekocode.meepo.sample.router.ActivityRouter; 11 | import cn.nekocode.meepo.sample.router.ModuleRouter; 12 | 13 | /** 14 | * @author nekocode (nekocode.cn@gmail.com) 15 | */ 16 | public class MainActivity extends AppCompatActivity { 17 | final ModuleRouter moduleRouter = new Meepo.Builder() 18 | .config(new ModuleConfig("TEST")) 19 | .adapter(new ModuleCallAdapter()) 20 | .build() 21 | .create(ModuleRouter.class); 22 | 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | 29 | findViewById(R.id.button_a).setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View v) { 32 | ActivityRouter.IMPL.gotoA(MainActivity.this, "AActivity Title", null); 33 | } 34 | }); 35 | 36 | findViewById(R.id.button_b).setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View v) { 39 | ActivityRouter.IMPL.gotoB(MainActivity.this, "BActivity Title"); 40 | } 41 | }); 42 | 43 | findViewById(R.id.button_module).setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View v) { 46 | moduleRouter.gotoTestModule(MainActivity.this); 47 | } 48 | }); 49 | 50 | findViewById(R.id.button_module2).setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | moduleRouter.gotoTestModule2(MainActivity.this); 54 | } 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/custom/ModuleCallAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.custom; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | 7 | import cn.nekocode.meepo.CallMethod; 8 | import cn.nekocode.meepo.MeepoUtils; 9 | import cn.nekocode.meepo.adapter.CallAdapter; 10 | import cn.nekocode.meepo.config.Config; 11 | 12 | /** 13 | * @author nekocode (nekocode.cn@gmail.com) 14 | */ 15 | public class ModuleCallAdapter implements CallAdapter { 16 | 17 | @Nullable 18 | @Override 19 | public Object call(@NonNull Config config, @NonNull CallMethod method, @NonNull Object[] args) { 20 | final Context context = MeepoUtils.getContextFromFirstParameter(args); 21 | final Class targetClass = method.getClazz(); 22 | 23 | String textPrefix = ""; 24 | if (config instanceof ModuleConfig) { 25 | textPrefix = ((ModuleConfig) config).getTextPrefix(); 26 | } 27 | 28 | if (targetClass != null && 29 | (targetClass == TestModule.class || targetClass.getSuperclass() == TestModule.class)) { 30 | try { 31 | TestModule module = (TestModule) targetClass.getConstructor(String.class).newInstance(textPrefix); 32 | module.showToast(context); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/custom/ModuleConfig.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.custom; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import cn.nekocode.meepo.config.Config; 6 | 7 | /** 8 | * @author nekocode (nekocode.cn@gmail.com) 9 | */ 10 | public class ModuleConfig implements Config { 11 | private String textPrefix; 12 | 13 | public ModuleConfig(@NonNull String textPrefix) { 14 | this.textPrefix = textPrefix; 15 | } 16 | 17 | public String getTextPrefix() { 18 | return textPrefix; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/custom/TestModule.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.custom; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | /** 7 | * @author nekocode (nekocode.cn@gmail.com) 8 | */ 9 | public class TestModule { 10 | protected String textPrefix; 11 | 12 | 13 | public TestModule(String textPrefix) { 14 | this.textPrefix = textPrefix; 15 | } 16 | 17 | public void showToast(Context context) { 18 | Toast.makeText(context, textPrefix + ": TestModule!", Toast.LENGTH_SHORT).show(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/custom/TestModule2.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.custom; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | /** 7 | * @author nekocode (nekocode.cn@gmail.com) 8 | */ 9 | public class TestModule2 extends TestModule { 10 | 11 | public TestModule2(String textPrefix) { 12 | super(textPrefix); 13 | } 14 | 15 | public void showToast(Context context) { 16 | Toast.makeText(context, textPrefix + ": TestModule2!", Toast.LENGTH_SHORT).show(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/router/ActivityRouter.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.router; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | 8 | import cn.nekocode.meepo.Meepo; 9 | import cn.nekocode.meepo.annotation.BundleParam; 10 | import cn.nekocode.meepo.annotation.QueryParam; 11 | import cn.nekocode.meepo.annotation.Clazz; 12 | import cn.nekocode.meepo.annotation.Flags; 13 | import cn.nekocode.meepo.annotation.Path; 14 | import cn.nekocode.meepo.config.UriConfig; 15 | import cn.nekocode.meepo.sample.BActivity; 16 | import cn.nekocode.meepo.sample.BuildConfig; 17 | 18 | /** 19 | * @author nekocode (nekocode.cn@gmail.com) 20 | */ 21 | public interface ActivityRouter { 22 | ActivityRouter IMPL = new Meepo.Builder() 23 | .config(new UriConfig().scheme(BuildConfig.SCHEME).host(BuildConfig.APPLICATION_ID)) 24 | .build().create(ActivityRouter.class); 25 | 26 | String ARG_TITLE = "title"; 27 | String ARG_NULLABLE = "nullable"; 28 | 29 | 30 | @Path("a") 31 | boolean gotoA( 32 | @NonNull Context context, 33 | @QueryParam(ARG_TITLE) @NonNull String title, 34 | @QueryParam(ARG_NULLABLE) @Nullable String nullable 35 | ); 36 | 37 | @Clazz(BActivity.class) 38 | @Flags(Intent.FLAG_ACTIVITY_SINGLE_TOP) 39 | void gotoB( 40 | @NonNull Context context, 41 | @BundleParam(ARG_TITLE) @NonNull String title 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/nekocode/meepo/sample/router/ModuleRouter.java: -------------------------------------------------------------------------------- 1 | package cn.nekocode.meepo.sample.router; 2 | 3 | import android.content.Context; 4 | 5 | import cn.nekocode.meepo.annotation.Clazz; 6 | import cn.nekocode.meepo.sample.custom.TestModule; 7 | import cn.nekocode.meepo.sample.custom.TestModule2; 8 | 9 | /** 10 | * @author nekocode (nekocode.cn@gmail.com) 11 | */ 12 | public interface ModuleRouter { 13 | 14 | @Clazz(TestModule.class) 15 | void gotoTestModule(Context context); 16 | 17 | @Clazz(TestModule2.class) 18 | void gotoTestModule2(Context context); 19 | } 20 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_child.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |