├── .gitignore
├── .travis.yml
├── LICENSE
├── bintrayUpload.gradle
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── okdeeplink-annotation
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── okdeeplink
│ ├── Action.java
│ ├── Activity.java
│ ├── AppLink.java
│ ├── Intercept.java
│ ├── Path.java
│ ├── Query.java
│ ├── RequestCode.java
│ ├── Service.java
│ ├── Uri.java
│ └── UriReplace.java
├── okdeeplink-api
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── okdeeplink
│ │ ├── Address.java
│ │ ├── BundleCompact.java
│ │ ├── DeepLinkActivity.java
│ │ ├── DeepLinkClient.java
│ │ ├── Interceptor.java
│ │ ├── LogInterceptor.java
│ │ ├── RealCall.java
│ │ ├── RealCallChain.java
│ │ ├── Request.java
│ │ └── Response.java
│ └── res
│ └── values
│ └── strings.xml
├── okdeeplink-gradle
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── groovy
│ └── okdeeplink
│ │ └── OkDeepLinkPlugin.groovy
│ └── resources
│ └── META-INF
│ └── gradle-plugins
│ └── okdeeplink.plugin.properties
├── okdeeplink-processor
├── .gitignore
├── build.gradle
├── libs
│ └── android-support-v4.jar
└── src
│ └── main
│ └── java
│ └── okdeeplink
│ ├── DeepLinkInjectProcessor.java
│ ├── DeepLinkInterceptorProcessor.java
│ ├── DeepLinkServiceProcessor.java
│ ├── element
│ ├── AddressElement.java
│ ├── InterceptorElement.java
│ └── ServiceElement.java
│ └── util
│ ├── ElementUtils.java
│ ├── Logger.java
│ └── MethodGenerator.java
├── pom-evaluator.gradle
├── readme.md
├── rxactivityresult
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── rxactivityresult
│ │ ├── ActivityResult.java
│ │ ├── IActivityObservable.java
│ │ ├── RxActivityResult.java
│ │ ├── RxResultHoldContext.java
│ │ ├── RxResultHoldEmpty.java
│ │ ├── RxResultHoldFragment.java
│ │ └── RxResultHoldFragmentV4.java
│ └── res
│ └── values
│ └── styles.xml
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── okdeeplink
│ │ └── sample
│ │ ├── MainActivity.java
│ │ ├── SampleService.java
│ │ └── SecondInterceptor.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── second
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── okdeeplink
│ │ └── second
│ │ ├── SecondActivity.java
│ │ └── SecondService.java
│ └── res
│ ├── layout
│ └── activity_second.xml
│ └── values
│ ├── dimens.xml
│ └── strings.xml
├── settings.gradle
└── snapshot
└── intercept_preview.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/dictionaries
41 | .idea/libraries
42 |
43 | # Keystore files
44 | *.jks
45 |
46 | # External native build folder generated in Android Studio 2.2 and later
47 | .externalNativeBuild
48 |
49 | # Google Services (e.g. APIs or Firebase)
50 | google-services.json
51 |
52 | # Freeline
53 | freeline.py
54 | freeline/
55 | freeline_project_description.json
56 | .idea
57 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk:
3 | - oraclejdk8
4 | notifications: # 每次构建的时候是否通知,如果不想收到通知邮箱(个人感觉邮件贼烦),那就设置false吧
5 | email: true
6 | android:
7 | components:
8 | - tools
9 | - build-tools-25.0.2
10 | - android-25
11 | - extra-android-m2repository # Android Support Repository
12 | - extra-android-support # Support Library
13 | before_install:
14 | - chmod +x gradlew # 改变gradlew的访问权限
15 | script: # 执行:下面的命令
16 | - ./gradlew assembleRelease
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/bintrayUpload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 | // load properties
5 | Properties properties = new Properties()
6 | DataInputStream localDataInputStream = null;
7 | DataInputStream gradleDataInputStream = null;
8 |
9 | if (project.rootProject.file('local.properties').canRead()) {
10 | File localPropertiesFile = project.rootProject.file('local.properties');
11 | localDataInputStream = localPropertiesFile.newDataInputStream();
12 | properties.load(localDataInputStream);
13 | }
14 |
15 | if (project.rootProject.file("gradle.properties").canRead()) {
16 | File projectPropertiesFile = project.rootProject.file("gradle.properties");
17 | gradleDataInputStream = projectPropertiesFile.newDataInputStream();
18 | properties.load(gradleDataInputStream);
19 | }
20 |
21 | // read properties
22 | def projectDescription = properties.getProperty("description")
23 | def projectGroupId = properties.getProperty("groupId")
24 | def projectArtifactId = properties.getProperty("artifactId")
25 | def projectVersionName = properties.getProperty("versionName")
26 | def projectPackaging = properties.getProperty("packaging")
27 | def projectSiteUrl = properties.getProperty("siteUrl")
28 | def projectGitUrl = properties.getProperty("gitUrl")
29 |
30 | def developerId = properties.getProperty("developer.id")
31 | def developerName = properties.getProperty("developer.name")
32 | def developerEmail = properties.getProperty("developer.email")
33 |
34 | def bintrayUser = properties.getProperty("bintray.user")
35 | def bintrayApikey = properties.getProperty("bintray.apikey")
36 | if (localDataInputStream != null) {
37 | localDataInputStream.close();
38 | }
39 | if (gradleDataInputStream != null) {
40 | gradleDataInputStream.close();
41 | }
42 |
43 | version = projectVersionName
44 | group = projectGroupId
45 |
46 |
47 |
48 | install {
49 | repositories.mavenInstaller {
50 | // This generates POM.xml with proper parameters
51 | pom {
52 | project {
53 | packaging projectPackaging
54 | // Add your description here
55 | name projectDescription //项目描述
56 | url projectSiteUrl
57 | // Set your license
58 | licenses {
59 | license {
60 | name 'The Apache Software License, Version 2.0'
61 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
62 | }
63 | }
64 | developers {
65 | developer {
66 | id developerId //填写的一些基本信息
67 | name developerName
68 | email developerEmail
69 | }
70 | }
71 | scm {
72 | connection projectGitUrl
73 | developerConnection projectGitUrl
74 | url projectSiteUrl
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
81 | if (project.hasProperty("android")) { // Android libraries
82 | task sourcesJar(type: Jar) {
83 | classifier = 'sources'
84 | from android.sourceSets.main.java.srcDirs
85 | }
86 |
87 | task javadoc(type: Javadoc) {
88 | source = android.sourceSets.main.java.srcDirs
89 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
90 |
91 | }
92 | } else { // Java libraries
93 | task sourcesJar(type: Jar, dependsOn: classes) {
94 | classifier = 'sources'
95 | from sourceSets.main.allSource
96 | }
97 | }
98 |
99 | task javadocJar(type: Jar, dependsOn: javadoc) {
100 | classifier = 'javadoc'
101 | from javadoc.destinationDir
102 | }
103 |
104 | javadoc {
105 | options {
106 | encoding "UTF-8"
107 | charSet 'UTF-8'
108 | }
109 | }
110 |
111 |
112 | artifacts {
113 | archives javadocJar
114 | archives sourcesJar
115 | }
116 |
117 | bintray {
118 | user = bintrayUser
119 | key = bintrayApikey
120 | configurations = ['archives']
121 | pkg {
122 | repo = "maven"
123 | name = project.archivesBaseName //发布到JCenter上的项目名字
124 | websiteUrl = projectGitUrl
125 | vcsUrl = projectGitUrl
126 | licenses = ["Apache-2.0"]
127 | publish = true
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:2.2.2'
10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 | classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10'
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 |
19 | jcenter()
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | groupId=com.hongjun
15 | description=OkDeepLink provides a annotation-based api to manipulate app deep links.
16 | versionName=1.0.0
17 | packaging=aar
18 | siteUrl=https://github.com/HongJun2046/OkDeepLink
19 | gitUrl=https://github.com/HongJun2046/OkDeepLink.git
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 13 20:37:13 PST 2016
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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows 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 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | sourceCompatibility = 1.7
3 |
4 | dependencies {
5 | }
6 |
7 | apply from: "${rootDir}/pom-evaluator.gradle"
8 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Action.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Target(ElementType.METHOD)
11 | @Retention(RetentionPolicy.CLASS)
12 | public @interface Action {
13 | String value();
14 | }
15 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Activity.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | @Target(ElementType.METHOD)
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface Activity {
12 | Class> value();
13 | }
14 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/AppLink.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Target(ElementType.TYPE)
11 | @Retention(RetentionPolicy.CLASS)
12 | public @interface AppLink {
13 | String host();
14 | String scheme();
15 | }
16 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Intercept.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | @Target({ElementType.TYPE, ElementType.METHOD})
10 | @Retention(RetentionPolicy.CLASS)
11 | public @interface Intercept {
12 | Class>[] value() default Object.class;
13 |
14 | String path() default "";
15 | }
16 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Path.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Target(ElementType.METHOD)
11 | @Retention(RetentionPolicy.CLASS)
12 | public @interface Path {
13 | String[] value();
14 | }
15 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Query.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Inherited;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Inherited
11 | @Target({ElementType.FIELD,ElementType.PARAMETER})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface Query {
14 | String value();
15 | }
16 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/RequestCode.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Created by zhangqijun on 2017/5/1.
10 | */
11 |
12 | @Target(ElementType.PARAMETER)
13 | @Retention(RetentionPolicy.CLASS)
14 | public @interface RequestCode {
15 | }
16 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Service.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target({ElementType.FIELD})
9 | @Retention(RetentionPolicy.CLASS)
10 | public @interface Service {
11 | }
12 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/Uri.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Target(ElementType.METHOD)
11 | @Retention(RetentionPolicy.CLASS)
12 | public @interface Uri {
13 | String value();
14 | }
15 |
--------------------------------------------------------------------------------
/okdeeplink-annotation/src/main/java/okdeeplink/UriReplace.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Inherited;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 |
10 | @Inherited
11 | @Target({ElementType.PARAMETER})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface UriReplace {
14 | String value();
15 | }
16 |
--------------------------------------------------------------------------------
/okdeeplink-api/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okdeeplink-api/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | consumerProguardFiles 'proguard-rules.pro'
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile "com.android.support:appcompat-v7:25.0.0"
30 | compile project(":rxactivityresult")
31 | compile project(":okdeeplink-annotation")
32 | compile 'org.aspectj:aspectjrt:1.8.9'
33 | testCompile 'junit:junit:4.12'
34 | }
35 | apply from: "${rootDir}/pom-evaluator.gradle"
36 |
--------------------------------------------------------------------------------
/okdeeplink-api/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/sunshine/Documents/AndroidStudio/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 |
20 |
21 | -keep class okdeeplink.** {*;}
22 | -dontwarn okdeeplink.**
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/Address.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 |
4 | import android.net.Uri;
5 |
6 | public final class Address {
7 |
8 | private final Class> activityClass;
9 | private final String path;
10 |
11 | public Address(String path, Class> activityClass) {
12 | this.path = path;
13 | this.activityClass = activityClass;
14 |
15 | }
16 |
17 | public Class> getActivityClass() {
18 | return activityClass;
19 | }
20 |
21 |
22 | public boolean isUri(){
23 | boolean isUri = false;
24 | try {
25 | Uri uri = Uri.parse(path);
26 | isUri = true;
27 | return isUri;
28 | } catch (Exception e) {
29 | e.printStackTrace();
30 | }
31 | return isUri;
32 |
33 | }
34 |
35 | public String getPath() {
36 | return path;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/BundleCompact.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.os.Bundle;
6 | import android.text.TextUtils;
7 |
8 | /**
9 | * Created by zhangqijun on 2017/4/26.
10 | */
11 |
12 | public class BundleCompact {
13 |
14 |
15 | public static T getValue(Bundle dataBundle, String key, Class valueClass) {
16 | Object value = getValue(dataBundle, key);
17 | if (value != null) {
18 | try {
19 | if (value instanceof String) {
20 | String strValue = (String) value;
21 | return (T) parseString(strValue, valueClass);
22 | } else {
23 | return valueClass.cast(value);
24 | }
25 | } catch (Exception e) {
26 | e.printStackTrace();
27 | }
28 |
29 | }
30 | return (T) value;
31 | }
32 |
33 | public static Bundle getSupportBundle(Object target) {
34 | if (target instanceof Activity) {
35 | return getBundle((Activity) target);
36 | }
37 | if (target instanceof Fragment) {
38 | return getBundle((Fragment) target);
39 | }
40 | if (target instanceof android.support.v4.app.Fragment) {
41 | return getBundle((android.support.v4.app.Fragment) target);
42 | }
43 | return null;
44 | }
45 |
46 |
47 | public static Object getValue(Bundle bundle, String query) {
48 | if (bundle != null && !TextUtils.isEmpty(query)) {
49 | return bundle.get(query);
50 | }
51 | return null;
52 | }
53 |
54 |
55 | private static Bundle getBundle(Activity activity) {
56 |
57 | if (activity == null || activity.getIntent() == null) {
58 | return null;
59 | }
60 | return activity.getIntent().getExtras();
61 | }
62 |
63 | private static Bundle getBundle(Fragment fragment) {
64 |
65 | if (fragment == null || fragment.getArguments() == null) {
66 | return null;
67 | }
68 | return fragment.getArguments();
69 |
70 | }
71 |
72 | private static Bundle getBundle(android.support.v4.app.Fragment fragment) {
73 | if (fragment == null || fragment.getArguments() == null) {
74 | return null;
75 | }
76 | return fragment.getArguments();
77 | }
78 |
79 | private static Object parseString(String value, Class clazz) {
80 | if (Boolean.class == clazz || Boolean.TYPE == clazz) return Boolean.parseBoolean(value);
81 | if (Byte.class == clazz || Byte.TYPE == clazz) return Byte.parseByte(value);
82 | if (Short.class == clazz || Short.TYPE == clazz) return Short.parseShort(value);
83 | if (Integer.class == clazz || Integer.TYPE == clazz) return Integer.parseInt(value);
84 | if (Long.class == clazz || Long.TYPE == clazz) return Long.parseLong(value);
85 | if (Float.class == clazz || Float.TYPE == clazz) return Float.parseFloat(value);
86 | if (Double.class == clazz || Double.TYPE == clazz) return Double.parseDouble(value);
87 | return value;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/DeepLinkActivity.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import rx.Subscriber;
8 |
9 | public class DeepLinkActivity extends Activity {
10 |
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | dispatchFrom(getIntent());
16 | }
17 |
18 |
19 | public void dispatchFrom(Intent intent) {
20 | new DeepLinkClient(this)
21 | .buildRequest(intent)
22 | .dispatch()
23 | .subscribe(new Subscriber() {
24 | @Override
25 | public void onCompleted() {
26 | finish();
27 | }
28 |
29 | @Override
30 | public void onError(Throwable e) {
31 | finish();
32 | }
33 |
34 | @Override
35 | public void onNext(Request request) {
36 | Intent dispatchIntent = request.getIntent();
37 | startActivity(dispatchIntent);
38 | }
39 | });
40 | }
41 |
42 | @Override
43 | protected void onNewIntent(Intent intent) {
44 | super.onNewIntent(intent);
45 | dispatchFrom(intent);
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/DeepLinkClient.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import android.support.v4.app.Fragment;
9 | import android.util.Log;
10 |
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 | import java.util.Hashtable;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | import rx.Observable;
18 | import rx.Subscriber;
19 |
20 |
21 | /**
22 | * Created by zhangqijun on 2017/3/8.
23 | */
24 |
25 | public class DeepLinkClient {
26 |
27 |
28 | public static final String TAG = "OkDeepLink";
29 |
30 | private static Map addresses = new Hashtable<>();
31 |
32 | private List interceptors = new ArrayList<>();
33 |
34 |
35 | private Context context;
36 |
37 | private int interceptTimeOut = 0;
38 |
39 | private static boolean debug = true;
40 |
41 |
42 | public DeepLinkClient(Context context) {
43 | this.context = context;
44 | }
45 |
46 | public DeepLinkClient(Fragment fragment) {
47 | this.context = fragment.getActivity();
48 | }
49 |
50 | public static void setDebug(boolean debugFlag) {
51 | debug = debugFlag;
52 | }
53 |
54 | public static boolean isDebug() {
55 | return debug;
56 | }
57 |
58 | /**
59 | * 每个matcher都会通过aop往这里注册路由表
60 | */
61 | public void init() {
62 |
63 | }
64 |
65 | public DeepLinkClient setInterceptTimeOut(int interceptTimeOut) {
66 | this.interceptTimeOut = interceptTimeOut;
67 | return this;
68 | }
69 |
70 | public int getInterceptTimeOut() {
71 | return interceptTimeOut;
72 | }
73 |
74 | public T build(Class service) {
75 | return null;
76 | }
77 |
78 |
79 | public Observable createResponse(Request request) {
80 | return new RealCall(request).createResponse();
81 | }
82 |
83 | public Observable createRequest(Request request) {
84 | return new RealCall(request).createRequest();
85 | }
86 |
87 | public void start(Request request) {
88 | createResponse(request)
89 | .subscribe(new Subscriber() {
90 | @Override
91 | public void onCompleted() {
92 |
93 | }
94 |
95 | @Override
96 | public void onError(Throwable e) {
97 |
98 | }
99 |
100 | @Override
101 | public void onNext(Response response) {
102 |
103 | }
104 | });
105 | }
106 |
107 | public Observable dispatch(Request request) {
108 | return new RealCall(request).dispatchRequest();
109 | }
110 |
111 | public Intent buildIntent(String url) {
112 | Intent intent = new Intent();
113 | intent.setData(Uri.parse(url));
114 | return buildRequest(intent).getIntent();
115 | }
116 |
117 | public Request buildRequest(String url) {
118 | Intent intent = new Intent();
119 | intent.setData(Uri.parse(url));
120 | return buildRequest(intent);
121 | }
122 |
123 | public Request buildRequest(Intent sourceIntent) {
124 | if (sourceIntent == null) {
125 | return null;
126 | }
127 | Intent newIntent = new Intent(sourceIntent);
128 | Uri uri = newIntent.getData();
129 |
130 | addNewTaskFlag(newIntent);
131 |
132 | if (uri != null) {
133 | addBundleQuery(newIntent, uri);
134 |
135 | Address entry = new DeepLinkClient(context).matchUrl(uri.toString());
136 | if (entry == null || entry.getActivityClass() == null) {
137 | return new Request(newIntent, this).setDeepLink(false);
138 | }
139 | newIntent.setComponent(new ComponentName(context, entry.getActivityClass()));
140 |
141 | return new Request(newIntent, this);
142 | }
143 | return new Request(newIntent, this).setDeepLink(false);
144 |
145 | }
146 |
147 | private void addNewTaskFlag(Intent newIntent) {
148 | if (context.getClass() == Context.class) {
149 | newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
150 | }
151 | }
152 |
153 | private void addBundleQuery(Intent newIntent, Uri uri) {
154 | Map uriParams = new HashMap<>();
155 | try {
156 | for (String queryParameter : uri.getQueryParameterNames()) {
157 | for (String queryParameterValue : uri.getQueryParameters(queryParameter)) {
158 | if (uriParams.containsKey(queryParameter)) {
159 | Log.w(TAG, "Duplicate parameter name in path and query param: " + queryParameter);
160 | }
161 | uriParams.put(queryParameter, queryParameterValue);
162 | }
163 | }
164 | } catch (Exception e) {
165 | e.printStackTrace();
166 | }
167 |
168 | Bundle bundle = newIntent.getExtras();
169 | if (bundle == null) {
170 | bundle = new Bundle();
171 | }
172 | for (Map.Entry parameterEntry : uriParams.entrySet()) {
173 | String value = parameterEntry.getValue();
174 | bundle.putString(parameterEntry.getKey(), value);
175 | }
176 | newIntent.putExtras(bundle);
177 | }
178 |
179 |
180 | public DeepLinkClient addInterceptor(Interceptor interceptor) {
181 | interceptors.add(interceptor);
182 | return this;
183 | }
184 |
185 |
186 | public List getInterceptors() {
187 | return interceptors;
188 | }
189 |
190 | public List getGlobalInterceptors() {
191 | return new ArrayList<>();
192 | }
193 |
194 | public Map getPathInterceptors() {
195 | return new Hashtable<>();
196 | }
197 |
198 |
199 | public Context getContext() {
200 | return context;
201 | }
202 |
203 | public DeepLinkClient setContext(Context context) {
204 | this.context = context;
205 | return this;
206 | }
207 |
208 | public Address matchUrl(String url) {
209 | if (DeepLinkClient.isEmpty()) {
210 | init();
211 | }
212 | String path = url;
213 | try {
214 | Uri uri = Uri.parse(url);
215 | path = uri.getEncodedPath();
216 | } catch (Exception e) {
217 | e.printStackTrace();
218 | }
219 | for (Address entry : addresses.values()) {
220 | if (entry.getPath().equals(path)) {
221 | return entry;
222 | }
223 | }
224 | return null;
225 | }
226 |
227 | public static boolean isEmpty() {
228 | return addresses.isEmpty();
229 | }
230 |
231 |
232 | public static void addAddress(Address address) {
233 | addresses.put(address.getPath(), address);
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/Interceptor.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 |
4 | /**
5 | * Created by zhangqijun on 2017/5/1.
6 | */
7 |
8 | public abstract class Interceptor {
9 |
10 |
11 | public abstract void intercept(Call call);
12 |
13 | public void onCall(Request request) {
14 |
15 | }
16 |
17 | public void onNotFound(Request request) {
18 |
19 | }
20 |
21 | public void onError(Request request, Throwable throwable) {
22 |
23 | }
24 |
25 | public interface Call {
26 | Request getRequest();
27 |
28 | void proceed(Request request);
29 |
30 | void proceed();
31 |
32 | void cancel();
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * Created by zhangqijun on 2017/5/7.
7 | */
8 |
9 | public class LogInterceptor extends Interceptor {
10 |
11 |
12 | @Override
13 | public void intercept(Call call) {
14 | Request request = call.getRequest();
15 | log("deep link is : " + request.getUrl());
16 | call.proceed();
17 | }
18 |
19 | @Override
20 | public void onNotFound(Request request) {
21 | super.onNotFound(request);
22 | log("deep link is not found : " + request.getUrl());
23 |
24 | }
25 |
26 | @Override
27 | public void onError(Request request, Throwable throwable) {
28 | super.onError(request, throwable);
29 | log("deep link is throw throwable : [" + request.getUrl() + "] -------->" + throwable.getMessage());
30 | }
31 |
32 | public void log(String msg) {
33 | if (DeepLinkClient.isDebug()) {
34 | Log.v(DeepLinkClient.TAG, msg);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/RealCall.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.app.Activity;
4 | import android.app.FragmentManager;
5 | import android.content.ActivityNotFoundException;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.os.Build;
9 | import android.support.v4.app.FragmentActivity;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | import rx.Observable;
16 | import rx.functions.Action1;
17 | import rx.functions.Func1;
18 | import rxactivityresult.ActivityResult;
19 | import rxactivityresult.RxActivityResult;
20 |
21 | /**
22 | * Created by zhangqijun on 2017/5/5.
23 | */
24 |
25 | public final class RealCall {
26 |
27 |
28 | private Request request;
29 | private DeepLinkClient deepLinkClient;
30 |
31 | private List interceptors;
32 | private int interceptTimeOut;
33 |
34 | public RealCall(Request request) {
35 | this.request = request;
36 | this.deepLinkClient = request.getDeepLinkClient();
37 | List interceptorList = new ArrayList<>();
38 |
39 | interceptorList.addAll(request.getInterceptors());
40 | interceptorList.addAll(deepLinkClient.getInterceptors());
41 | interceptorList.addAll(getPathInterceptors(request));
42 | interceptorList.addAll(deepLinkClient.getGlobalInterceptors());
43 |
44 | interceptorList.add(new LogInterceptor());
45 | this.interceptors = interceptorList;
46 | this.interceptTimeOut = deepLinkClient.getInterceptTimeOut();
47 | }
48 |
49 | private List getPathInterceptors(Request request) {
50 | String path = request.getPath();
51 | List list = new ArrayList<>();
52 | for (Map.Entry pathInterceptors : deepLinkClient.getPathInterceptors().entrySet()) {
53 | String pathKey = pathInterceptors.getKey();
54 | Interceptor interceptor = pathInterceptors.getValue();
55 | if (pathKey.equals(path)) {
56 | list.add(interceptor);
57 | }
58 | }
59 | return list;
60 | }
61 |
62 |
63 | public Observable createRequest() {
64 |
65 | return buildRequest()
66 | .doOnError(new Action1() {
67 | @Override
68 | public void call(Throwable throwable) {
69 | callThrowable(throwable);
70 | }
71 | });
72 | }
73 |
74 |
75 | private Observable buildRequest() {
76 | RealCallChain chain = new RealCallChain(interceptors, 0, request);
77 | chain.setTimeout(interceptTimeOut);
78 | chain.call();
79 | return chain
80 | .getRequestObservable()
81 | .map(new Func1() {
82 | @Override
83 | public Request call(Request request) {
84 | if (interceptors != null) {
85 | for (Interceptor interceptor : interceptors) {
86 | interceptor.onCall(request);
87 | }
88 | }
89 | return request;
90 | }
91 | });
92 | }
93 |
94 |
95 | public Observable createResponse() {
96 |
97 | return buildRequest()
98 | .flatMap(new Func1>() {
99 | @Override
100 | public Observable call(final Request request) {
101 |
102 | Context context = getStartContext(request.getContext());
103 |
104 | return RxActivityResult
105 | .on(context)
106 | .startIntent(request.getIntent())
107 | .map(new Func1() {
108 | @Override
109 | public Response call(ActivityResult activityActivityResult) {
110 | return new Response(request, activityActivityResult.getResultCode(), activityActivityResult.getData());
111 | }
112 | });
113 | }
114 | }).doOnError(new Action1() {
115 | @Override
116 | public void call(Throwable throwable) {
117 | callThrowable(throwable);
118 | }
119 | });
120 | }
121 |
122 |
123 | private Context getStartContext(Context context) {
124 | if (context instanceof Activity) {
125 | Activity activity = (Activity) context;
126 | boolean isDestroyed = false;
127 | if (activity.isFinishing()) {
128 | isDestroyed = true;
129 | }
130 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
131 | if (activity.isDestroyed()) {
132 | isDestroyed = true;
133 | }
134 |
135 | }
136 | FragmentManager fragmentManager = activity.getFragmentManager();
137 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
138 | if (fragmentManager.isDestroyed()) {
139 | isDestroyed = true;
140 | }
141 | }
142 | if (context instanceof FragmentActivity) {
143 | FragmentActivity fragmentActivity = (FragmentActivity) context;
144 | android.support.v4.app.FragmentManager fragmentManagerV4 = fragmentActivity.getSupportFragmentManager();
145 |
146 | if (fragmentManagerV4.isDestroyed()) {
147 | isDestroyed = true;
148 | }
149 | }
150 | if (isDestroyed) {
151 | return context.getApplicationContext();
152 | }
153 | }
154 | return context;
155 | }
156 |
157 | private void callThrowable(Throwable throwable) {
158 | if (throwable instanceof ActivityNotFoundException) {
159 | if (interceptors != null) {
160 | for (Interceptor interceptor : interceptors) {
161 | interceptor.onNotFound(request);
162 | }
163 | }
164 | }
165 | if (interceptors != null) {
166 | for (Interceptor interceptor : interceptors) {
167 | interceptor.onError(request, throwable);
168 | }
169 | }
170 | }
171 |
172 | public Observable dispatchRequest() {
173 | return buildRequest()
174 | .flatMap(new Func1>() {
175 | @Override
176 | public Observable call(Request request) {
177 | if (!request.isDeepLink()) {
178 | return Observable.error(new ActivityNotFoundException());
179 | }
180 | Context context = request.getContext();
181 | Intent intent = request.getIntent();
182 | if (context instanceof android.app.Activity) {
183 | android.app.Activity activity = (android.app.Activity) context;
184 | if (activity.getCallingActivity() != null) {
185 | intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
186 | }
187 | }
188 | if (context != null && context.getClass() == Context.class) {
189 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
190 | }
191 | return Observable.just(request);
192 | }
193 | })
194 | .onErrorResumeNext(new Func1>() {
195 | @Override
196 | public Observable extends Request> call(Throwable throwable) {
197 | callThrowable(throwable);
198 | return Observable.error(throwable);
199 | }
200 | });
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/RealCallChain.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.app.PendingIntent;
4 |
5 | import java.util.List;
6 | import java.util.concurrent.TimeUnit;
7 | import java.util.concurrent.TimeoutException;
8 |
9 | import rx.Observable;
10 | import rx.Subscriber;
11 | import rx.android.schedulers.AndroidSchedulers;
12 | import rx.functions.Action1;
13 | import rx.schedulers.Schedulers;
14 | import rx.subjects.AsyncSubject;
15 | import rx.subjects.BehaviorSubject;
16 |
17 | /**
18 | * Created by zhangqijun on 2017/5/5.
19 | */
20 |
21 | public class RealCallChain implements Interceptor.Call {
22 |
23 |
24 | private final List interceptors;
25 | private int index;
26 | private Request request;
27 |
28 | public final BehaviorSubject interceptorSubject = BehaviorSubject.create();
29 |
30 | public final AsyncSubject requestSubject = AsyncSubject.create();
31 |
32 | private int timeout = 0;
33 |
34 | public RealCallChain(List interceptors, int index, Request request) {
35 | this.interceptors = interceptors;
36 | this.index = index;
37 | this.request = request;
38 | }
39 |
40 | public RealCallChain setTimeout(int timeout) {
41 | this.timeout = timeout;
42 | return this;
43 | }
44 |
45 | public void call() {
46 |
47 | Observable.just(1)
48 | .observeOn(Schedulers.io())
49 | .subscribe(new Action1() {
50 | @Override
51 | public void call(Integer integer) {
52 | proceed();
53 | }
54 | });
55 |
56 |
57 | Observable observable = interceptorSubject;
58 | if (timeout > 0) {
59 | observable = interceptorSubject.timeout(timeout, TimeUnit.SECONDS);
60 | }
61 | observable.subscribe(new Subscriber() {
62 | @Override
63 | public void onCompleted() {
64 |
65 | }
66 |
67 | @Override
68 | public void onError(Throwable e) {
69 |
70 | requestSubject.onError(new TimeoutException());
71 | }
72 |
73 | @Override
74 | public void onNext(Interceptor interceptor) {
75 |
76 | }
77 | });
78 | }
79 |
80 |
81 | @Override
82 | public Request getRequest() {
83 | return request;
84 | }
85 |
86 |
87 | @Override
88 | public void proceed(Request request) {
89 | this.request = request;
90 | proceed();
91 | }
92 |
93 | public Observable getRequestObservable() {
94 | return requestSubject
95 | .asObservable()
96 | .subscribeOn(Schedulers.io())
97 | .observeOn(AndroidSchedulers.mainThread());
98 | }
99 |
100 | public void realCall() {
101 | requestSubject.onNext(request);
102 | requestSubject.onCompleted();
103 | }
104 |
105 | @Override
106 | public void proceed() {
107 |
108 |
109 | if (index >= interceptors.size()) {
110 | realCall();
111 | return;
112 | }
113 | final Interceptor interceptor = interceptors.get(index);
114 | Observable
115 | .just(1)
116 | .observeOn(AndroidSchedulers.mainThread())
117 | .subscribe(new Action1() {
118 | @Override
119 | public void call(Integer integer) {
120 | interceptor.intercept(RealCallChain.this);
121 | }
122 | });
123 |
124 | interceptorSubject.onNext(interceptor);
125 | index = index + 1;
126 | }
127 |
128 | @Override
129 | public void cancel() {
130 | requestSubject.onError(new PendingIntent.CanceledException());
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/Request.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import java.util.ArrayList;
8 | import java.util.HashMap;
9 | import java.util.Iterator;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Set;
13 |
14 | import rx.Observable;
15 |
16 | /**
17 | * Created by zhangqijun on 2017/5/2.
18 | */
19 |
20 | public class Request {
21 |
22 |
23 | private Intent intent;
24 | private Context context;
25 | private DeepLinkClient deepLinkClient;
26 | private int requestCode = -1;
27 |
28 | private boolean isDeepLink = true;
29 |
30 | private List interceptors = new ArrayList<>();
31 |
32 |
33 | public Request(Intent intent, DeepLinkClient deepLinkClient) {
34 | this.intent = intent;
35 | this.context = deepLinkClient.getContext();
36 | this.deepLinkClient = deepLinkClient;
37 | }
38 |
39 |
40 | public Request addInterceptor(Interceptor interceptor) {
41 | interceptors.add(interceptor);
42 | return this;
43 | }
44 |
45 | public List getInterceptors() {
46 | return interceptors;
47 | }
48 |
49 | public Request(Intent intent, DeepLinkClient deepLinkClient, int requestCode) {
50 | this.requestCode = requestCode;
51 | this.intent = intent;
52 | this.context = deepLinkClient.getContext();
53 | this.deepLinkClient = deepLinkClient;
54 | }
55 |
56 |
57 | public Request setDeepLink(boolean deepLink) {
58 | isDeepLink = deepLink;
59 | return this;
60 | }
61 |
62 | public boolean isDeepLink() {
63 | return isDeepLink;
64 | }
65 |
66 | public Request setIntent(Intent intent) {
67 | this.intent = intent;
68 | return this;
69 | }
70 |
71 | public Request setRequestCode(int requestCode) {
72 | this.requestCode = requestCode;
73 | return this;
74 | }
75 |
76 | public int getRequestCode() {
77 | return requestCode;
78 | }
79 |
80 | public Intent getIntent() {
81 | return intent;
82 | }
83 |
84 |
85 | public String getUrl() {
86 | return getUrl(intent);
87 | }
88 |
89 | public String getScheme() {
90 | if (intent != null && intent.getData() != null) {
91 | return intent.getData().getScheme();
92 | }
93 | return "";
94 | }
95 |
96 | public String getHost() {
97 | if (intent != null && intent.getData() != null) {
98 | return intent.getData().getHost();
99 | }
100 | return "";
101 | }
102 |
103 | public String getPath() {
104 | if (intent != null && intent.getData() != null) {
105 | return intent.getData().getEncodedPath();
106 | }
107 | return "";
108 | }
109 |
110 |
111 | public static String getUrl(Intent intent) {
112 | if (intent != null && intent.getData() != null) {
113 | return intent.getData().toString();
114 | }
115 | return "";
116 | }
117 |
118 | public Map getQuery() {
119 | return getQuery(intent);
120 | }
121 |
122 |
123 | public static Map getQuery(Intent intent) {
124 | Map query = new HashMap<>();
125 | if (intent != null) {
126 | Bundle bundle = intent.getExtras();
127 | if (bundle != null) {
128 | Set keys = bundle.keySet();
129 | Iterator it = keys.iterator();
130 | while (it.hasNext()) {
131 | String key = it.next();
132 |
133 | bundle.get(key);
134 | query.put(key, bundle.get(key));
135 |
136 | }
137 | }
138 | }
139 | return query;
140 | }
141 |
142 | public T build(Class service) {
143 | if (deepLinkClient != null && context != null) {
144 | return deepLinkClient.build(service);
145 | }
146 | return null;
147 | }
148 |
149 | public Context getContext() {
150 | return context;
151 | }
152 |
153 |
154 | public Request setContext(Context context) {
155 | this.context = context;
156 | if (deepLinkClient != null) {
157 | deepLinkClient.setContext(context);
158 | }
159 | return this;
160 | }
161 |
162 | public DeepLinkClient getDeepLinkClient() {
163 | return deepLinkClient;
164 | }
165 |
166 |
167 | public Observable createResponse() {
168 | return deepLinkClient.createResponse(this);
169 | }
170 |
171 | public Observable createRequest() {
172 | return deepLinkClient.createRequest(this);
173 | }
174 |
175 | public void start() {
176 | deepLinkClient.start(this);
177 | }
178 |
179 | public Observable dispatch() {
180 | return deepLinkClient.dispatch(this);
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/java/okdeeplink/Response.java:
--------------------------------------------------------------------------------
1 | package okdeeplink;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 |
6 | /**
7 | * Created by zhangqijun on 2017/5/2.
8 | */
9 |
10 | public class Response {
11 |
12 | private Request request;
13 | private int resultCode = Activity.RESULT_CANCELED;
14 | private Intent data;
15 |
16 |
17 | public Response(Request request, int resultCode, Intent data) {
18 | this.request = request;
19 | this.resultCode = resultCode;
20 | this.data = data;
21 | }
22 |
23 | public Request getRequest() {
24 | return request;
25 | }
26 |
27 | public int getResultCode() {
28 | return resultCode;
29 | }
30 |
31 |
32 | public Intent getData() {
33 | return data;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/okdeeplink-api/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Router
3 |
4 |
--------------------------------------------------------------------------------
/okdeeplink-gradle/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okdeeplink-gradle/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'groovy'
2 | apply from: "${rootDir}/pom-evaluator.gradle"
3 |
4 | dependencies {
5 | compile gradleApi()
6 | compile localGroovy()
7 | compile 'com.android.tools.build:gradle:2.1.3'
8 | compile 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10'
9 |
10 | }
11 | sourceCompatibility = "1.7"
12 | targetCompatibility = "1.7"
13 | //compileGroovy {
14 | // sourceCompatibility = 1.6
15 | // targetCompatibility = 1.6
16 | // options.encoding = 'UTF-8'
17 | //}
18 |
19 | sourceSets {
20 | main {
21 | groovy {
22 | srcDirs = ['src/main/groovy']
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/okdeeplink-gradle/src/main/groovy/okdeeplink/OkDeepLinkPlugin.groovy:
--------------------------------------------------------------------------------
1 | package okdeeplink
2 |
3 | import com.android.build.gradle.AppPlugin
4 | import com.android.build.gradle.LibraryPlugin
5 | import org.gradle.api.Plugin
6 | import org.gradle.api.Project
7 |
8 | /**
9 | * Created by zhangqijun on 2017/5/16.
10 | */
11 |
12 | public class OkDeepLinkPlugin implements Plugin {
13 |
14 | @Override
15 | public void apply(Project project) {
16 |
17 |
18 | def hasApp = project.plugins.withType(AppPlugin)
19 | def hasLib = project.plugins.withType(LibraryPlugin)
20 | def hasApt = project.plugins.hasPlugin('com.neenbedankt.android-apt')
21 | def usesAndroidAspectJxPlugin = project.plugins.hasPlugin('android-aspectjx')
22 | if (hasApp || hasLib) {
23 | if (hasApp && !usesAndroidAspectJxPlugin) {
24 | project.pluginManager.apply(com.hujiang.gradle.plugin.android.aspectjx.AndroidAspectJXPlugin);
25 | }
26 | project.dependencies {
27 | compile 'org.aspectj:aspectjrt:1.8.9'
28 | compile 'com.hongjun:okdeeplink-api:1.0.0'
29 | if (hasApt){
30 | apt 'com.hongjun:okdeeplink-processor:1.0.0'
31 | }else {
32 | annotationProcessor 'com.hongjun:okdeeplink-processor:1.0.0'
33 | }
34 |
35 | }
36 | }
37 | project.configurations.all {
38 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
39 | }
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/okdeeplink-gradle/src/main/resources/META-INF/gradle-plugins/okdeeplink.plugin.properties:
--------------------------------------------------------------------------------
1 | implementation-class=okdeeplink.OkDeepLinkPlugin
--------------------------------------------------------------------------------
/okdeeplink-processor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/okdeeplink-processor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | sourceCompatibility = 1.7
4 |
5 | repositories {
6 |
7 | jcenter()
8 |
9 | }
10 |
11 | dependencies {
12 | compile project(':okdeeplink-annotation')
13 | compile 'org.aspectj:aspectjrt:1.8.9'
14 | compile 'com.google.auto.service:auto-service:1.0-rc2'
15 | compile 'com.squareup:javapoet:1.8.0'
16 | compile 'com.google.auto:auto-common:0.6'
17 |
18 | }
19 |
20 | apply from: "${rootDir}/pom-evaluator.gradle"
21 |
--------------------------------------------------------------------------------
/okdeeplink-processor/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/okdeeplink-processor/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/DeepLinkInjectProcessor.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import com.google.auto.service.AutoService;
5 | import com.squareup.javapoet.AnnotationSpec;
6 | import com.squareup.javapoet.ClassName;
7 | import com.squareup.javapoet.CodeBlock;
8 | import com.squareup.javapoet.JavaFile;
9 | import com.squareup.javapoet.MethodSpec;
10 | import com.squareup.javapoet.TypeName;
11 | import com.squareup.javapoet.TypeSpec;
12 |
13 | import org.aspectj.lang.JoinPoint;
14 | import org.aspectj.lang.ProceedingJoinPoint;
15 | import org.aspectj.lang.annotation.After;
16 | import org.aspectj.lang.annotation.Around;
17 | import org.aspectj.lang.annotation.Aspect;
18 |
19 | import java.io.IOException;
20 | import java.util.ArrayList;
21 | import java.util.HashMap;
22 | import java.util.HashSet;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.Set;
26 |
27 | import javax.annotation.processing.AbstractProcessor;
28 | import javax.annotation.processing.Filer;
29 | import javax.annotation.processing.ProcessingEnvironment;
30 | import javax.annotation.processing.Processor;
31 | import javax.annotation.processing.RoundEnvironment;
32 | import javax.lang.model.SourceVersion;
33 | import javax.lang.model.element.Element;
34 | import javax.lang.model.element.ElementKind;
35 | import javax.lang.model.element.Modifier;
36 | import javax.lang.model.element.PackageElement;
37 | import javax.lang.model.element.TypeElement;
38 | import javax.lang.model.type.TypeMirror;
39 | import javax.lang.model.util.Elements;
40 | import javax.lang.model.util.Types;
41 |
42 | import okdeeplink.util.ElementUtils;
43 | import okdeeplink.util.Logger;
44 |
45 | import static com.squareup.javapoet.MethodSpec.methodBuilder;
46 | import static javax.lang.model.element.ElementKind.CLASS;
47 | import static javax.lang.model.element.Modifier.PUBLIC;
48 |
49 | @AutoService(Processor.class)
50 | public class DeepLinkInjectProcessor extends AbstractProcessor {
51 |
52 | private static final String PACKAGE_NAME = DeepLinkInjectProcessor.class.getPackage().getName();
53 |
54 | private static final ClassName BUNDLE = ClassName.get("android.os", "Bundle");
55 | private static final ClassName INTENT = ClassName.get("android.content", "Intent");
56 | private static final ClassName BUNDLE_COMPACT = ClassName.get(PACKAGE_NAME, "BundleCompact");
57 |
58 | private static final String ACTIVITY = "android.app.Activity";
59 |
60 |
61 | private static final String INJECTOR_SUFFIX = "$$Injector";
62 |
63 | private static final List SUPPORT_INJECT = new ArrayList<>();
64 |
65 | static {
66 | SUPPORT_INJECT.add(ACTIVITY);
67 | SUPPORT_INJECT.add("android.app.Fragment");
68 | SUPPORT_INJECT.add("android.support.v4.app.Fragment");
69 | }
70 |
71 |
72 | private Filer filer;
73 | private Logger logger;
74 |
75 | private Map> targetInjectElements;
76 | private Elements elements;
77 | private Types types;
78 |
79 | @Override
80 | public synchronized void init(ProcessingEnvironment processingEnv) {
81 | super.init(processingEnv);
82 | logger = new Logger(processingEnv.getMessager());
83 | filer = processingEnv.getFiler();
84 | elements = processingEnv.getElementUtils();
85 | types = processingEnv.getTypeUtils();
86 | }
87 |
88 | @Override
89 | public Set getSupportedAnnotationTypes() {
90 | Set ret = new HashSet<>();
91 | ret.add(Query.class.getCanonicalName());
92 | ret.add(Service.class.getCanonicalName());
93 | return ret;
94 | }
95 |
96 | @Override
97 | public SourceVersion getSupportedSourceVersion() {
98 | return SourceVersion.latestSupported();
99 | }
100 |
101 | @Override
102 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
103 |
104 | List injectElements = new ArrayList<>();
105 | List queryElements = generateQueryElements(roundEnv);
106 | List serviceElements = generateServiceElements(roundEnv);
107 | injectElements.addAll(queryElements);
108 | injectElements.addAll(serviceElements);
109 | if (ElementUtils.isEmpty(injectElements)) {
110 | return false;
111 | }
112 | targetInjectElements = findInjectElements(injectElements);
113 | if (ElementUtils.isEmpty(targetInjectElements)) {
114 | return false;
115 | }
116 | for (Map.Entry> injectElementEntrySet : targetInjectElements.entrySet()) {
117 | TypeElement targetElement = injectElementEntrySet.getKey();
118 | List fieldElements = injectElementEntrySet.getValue();
119 |
120 | MethodSpec injectQueryMethod = geneOnCreateQueryMethod(targetElement, fieldElements);
121 |
122 | MethodSpec injectServiceMethod = geneInjectServiceMethod(targetElement, fieldElements);
123 |
124 | MethodSpec saveInstanceMethod = geneSaveInstanceMethod(targetElement, fieldElements);
125 |
126 |
127 | MethodSpec newIntentMethod = geneOnNewIntentQueryMethod(targetElement, fieldElements);
128 |
129 | String fileName = targetElement.getSimpleName() + INJECTOR_SUFFIX;
130 | TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
131 | .addModifiers(PUBLIC)
132 | .addAnnotation(AnnotationSpec.builder(Aspect.class).build())
133 | .addMethod(injectQueryMethod)
134 | .addMethod(injectServiceMethod)
135 | .addMethod(saveInstanceMethod);
136 |
137 | TypeMirror typeMirror = elements.getTypeElement(ACTIVITY).asType();
138 | if (types.isSubtype(targetElement.asType(), typeMirror)) {
139 | helper.addMethod(newIntentMethod);
140 | }
141 |
142 | try {
143 | PackageElement packageElement = (PackageElement) targetElement.getEnclosingElement();
144 | JavaFile.builder(packageElement.getQualifiedName().toString(), helper.build()).build().writeTo(filer);
145 | } catch (IOException e) {
146 | logger.error("Error creating inject file", targetElement);
147 | }
148 |
149 | }
150 | return true;
151 | }
152 |
153 | private MethodSpec geneOnCreateQueryMethod(TypeElement targetElement, List fieldElements) {
154 |
155 | MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder("onCreate")
156 | .addModifiers(PUBLIC)
157 | .addException(Throwable.class)
158 | .addAnnotation(AnnotationSpec.builder(Around.class).addMember("value", "$S", "execution(* " + targetElement.getQualifiedName() + ".onCreate(..))").build())
159 | .addParameter(ProceedingJoinPoint.class, "joinPoint");
160 |
161 | CodeBlock.Builder injectQueryCodeBuilder = geneOnCreateCodeBuilder(targetElement);
162 |
163 | List queryKeys = new ArrayList<>();
164 |
165 | for (Element queryElement : fieldElements) {
166 | if (queryElement.getAnnotation(Query.class) != null) {
167 | String queryKey = queryElement.getAnnotation(Query.class).value();
168 | if (queryKeys.contains(queryKey)) {
169 | logger.error("The inject query key cannot be Duplicate" + Query.class.getCanonicalName(), queryElement);
170 | }
171 | queryKeys.add(queryKey);
172 |
173 | injectQueryCodeBuilder
174 | .beginControlFlow("try")
175 | .add("target.$L= $T.getValue(dataBundle,$S,$T.class);\n", queryElement, BUNDLE_COMPACT, queryKey, queryElement)
176 | .nextControlFlow("catch ($T e)", Exception.class)
177 | .addStatement("e.printStackTrace()")
178 | .endControlFlow();
179 |
180 | }
181 | }
182 | injectQueryCodeBuilder.add("joinPoint.proceed();\n");
183 | injectMethodBuilder.addCode(injectQueryCodeBuilder.build());
184 |
185 | return injectMethodBuilder.build();
186 | }
187 |
188 |
189 | private MethodSpec geneOnNewIntentQueryMethod(TypeElement targetElement, List fieldElements) {
190 |
191 | MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder("onNewIntent")
192 | .addModifiers(PUBLIC)
193 | .addException(Throwable.class)
194 | .addAnnotation(AnnotationSpec.builder(Around.class).addMember("value", "$S", "execution(* " + targetElement.getQualifiedName() + ".onNewIntent(..))").build())
195 | .addParameter(ProceedingJoinPoint.class, "joinPoint");
196 |
197 | CodeBlock.Builder injectQueryCodeBuilder = geneOnNewIntentCodeBuilder(targetElement);
198 |
199 | List queryKeys = new ArrayList<>();
200 |
201 | for (Element queryElement : fieldElements) {
202 | if (queryElement.getAnnotation(Query.class) != null) {
203 | String queryKey = queryElement.getAnnotation(Query.class).value();
204 | if (queryKeys.contains(queryKey)) {
205 | logger.error("The inject query key cannot be Duplicate" + Query.class.getCanonicalName(), queryElement);
206 | }
207 | queryKeys.add(queryKey);
208 |
209 | injectQueryCodeBuilder
210 | .beginControlFlow("try")
211 | .add("target.$L= $T.getValue(dataBundle,$S,$T.class);\n", queryElement, BUNDLE_COMPACT, queryKey, queryElement)
212 | .nextControlFlow("catch ($T e)", Exception.class)
213 | .addStatement("e.printStackTrace()")
214 | .endControlFlow();
215 |
216 | }
217 | }
218 | injectQueryCodeBuilder.add("joinPoint.proceed();\n");
219 | injectMethodBuilder.addCode(injectQueryCodeBuilder.build());
220 |
221 | return injectMethodBuilder.build();
222 | }
223 |
224 |
225 | private MethodSpec geneInjectServiceMethod(TypeElement targetElement, List fieldElements) {
226 |
227 | MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder("onCreateService")
228 | .addModifiers(PUBLIC)
229 | .addException(Throwable.class)
230 | .addAnnotation(AnnotationSpec.builder(Around.class).addMember("value", "$S", "execution(* " + targetElement.getQualifiedName() + ".onCreate(..))").build())
231 | .addParameter(ProceedingJoinPoint.class, "joinPoint");
232 |
233 | CodeBlock.Builder injectServiceCodeBuilder = CodeBlock.builder();
234 | injectServiceCodeBuilder.add("$T target = ($T)joinPoint.getTarget();\n", targetElement, targetElement);
235 | List serviceTypeNames = new ArrayList<>();
236 |
237 | for (Element queryElement : fieldElements) {
238 | if (queryElement.getAnnotation(Service.class) != null) {
239 | TypeName className = TypeName.get(queryElement.asType());
240 | if (serviceTypeNames.contains(className)) {
241 | logger.error("The inject " + className + " cannot be Duplicate", queryElement);
242 | }
243 | serviceTypeNames.add(className);
244 | injectServiceCodeBuilder.add("target.$L= new $T(target).build($T.class);\n ", queryElement, DeepLinkServiceProcessor.DEEP_LINK_CLIENT, queryElement);
245 |
246 | }
247 | }
248 | injectServiceCodeBuilder.add("joinPoint.proceed();\n");
249 | injectMethodBuilder.addCode(injectServiceCodeBuilder.build());
250 |
251 | return injectMethodBuilder.build();
252 | }
253 |
254 |
255 | private MethodSpec geneSaveInstanceMethod(TypeElement targetElement, List fieldElements) {
256 |
257 | MethodSpec.Builder saveInstanceMethodBuilder = methodBuilder("onSaveInstanceState")
258 | .addModifiers(PUBLIC)
259 | .addException(Throwable.class)
260 | .addAnnotation(AnnotationSpec
261 | .builder(After.class)
262 | .addMember("value", "$S", "execution(* " + targetElement.getQualifiedName() + ".onSaveInstanceState(..))")
263 | .build())
264 | .addParameter(JoinPoint.class, "joinPoint");
265 |
266 | CodeBlock.Builder saveInstanceCodeBuilder = geneSaveInstanceCodeBuilder(targetElement);
267 |
268 | List queryKeys = new ArrayList<>();
269 |
270 | for (Element queryElement : fieldElements) {
271 | if (queryElement.getAnnotation(Query.class) != null) {
272 |
273 | String queryKey = queryElement.getAnnotation(Query.class).value();
274 | if (queryKeys.contains(queryKey)) {
275 | logger.error("The inject query key cannot be Duplicate" + Query.class.getCanonicalName(), queryElement);
276 | }
277 | queryKeys.add(queryKey);
278 | saveInstanceCodeBuilder.add("intent.putExtra($S,target.$L);\n", queryKey, queryElement);
279 | }
280 | }
281 |
282 | saveInstanceCodeBuilder.add("saveBundle.putAll(intent.getExtras());\n");
283 |
284 | saveInstanceMethodBuilder.addCode(saveInstanceCodeBuilder.build());
285 |
286 | return saveInstanceMethodBuilder.build();
287 | }
288 |
289 | private CodeBlock.Builder geneSaveInstanceCodeBuilder(TypeElement targetElement) {
290 | CodeBlock.Builder blockBuilderSave = CodeBlock.builder();
291 | blockBuilderSave.add("$T target = ($T)joinPoint.getTarget();\n", targetElement, targetElement);
292 | blockBuilderSave.add("$T saveBundle = ($T)joinPoint.getArgs()[0];\n", BUNDLE, BUNDLE);
293 | blockBuilderSave.add("$T intent = new $T();\n", INTENT, INTENT);
294 | return blockBuilderSave;
295 | }
296 |
297 | private CodeBlock.Builder geneOnCreateCodeBuilder(TypeElement targetElement) {
298 | CodeBlock.Builder injectQueryCodeBuilder = CodeBlock.builder();
299 | injectQueryCodeBuilder.add("$T target = ($T)joinPoint.getTarget();\n", targetElement, targetElement);
300 | injectQueryCodeBuilder.add("$T dataBundle = new $T();\n", BUNDLE, BUNDLE);
301 | injectQueryCodeBuilder.add("$T saveBundle = ($T)joinPoint.getArgs()[0];\n", BUNDLE, BUNDLE);
302 | injectQueryCodeBuilder.add("$T targetBundle = $T.getSupportBundle(target);\n", BUNDLE, BUNDLE_COMPACT);
303 | injectQueryCodeBuilder.beginControlFlow("if(targetBundle != null)");
304 | injectQueryCodeBuilder.add("dataBundle.putAll(targetBundle);\n");
305 | injectQueryCodeBuilder.endControlFlow();
306 | injectQueryCodeBuilder.beginControlFlow("if(saveBundle != null)");
307 | injectQueryCodeBuilder.add("dataBundle.putAll(saveBundle);\n");
308 | injectQueryCodeBuilder.endControlFlow();
309 | return injectQueryCodeBuilder;
310 | }
311 |
312 | private CodeBlock.Builder geneOnNewIntentCodeBuilder(TypeElement targetElement) {
313 | CodeBlock.Builder injectQueryCodeBuilder = CodeBlock.builder();
314 | injectQueryCodeBuilder.add("$T target = ($T)joinPoint.getTarget();\n", targetElement, targetElement);
315 | injectQueryCodeBuilder.add("$T targetIntent = ($T)joinPoint.getArgs()[0];\n", INTENT, INTENT);
316 | injectQueryCodeBuilder.add("$T dataBundle = targetIntent.getExtras();\n", BUNDLE);
317 |
318 | return injectQueryCodeBuilder;
319 | }
320 |
321 |
322 | private List generateQueryElements(RoundEnvironment roundEnv) {
323 | Set extends Element> deepLinkPathElements = roundEnv.getElementsAnnotatedWith(Query.class);
324 | List queryElements = new ArrayList<>();
325 | for (Element element : deepLinkPathElements) {
326 | Query deepLinkPathAnnotation = element.getAnnotation(Query.class);
327 | ElementKind kind = element.getKind();
328 | if (kind != ElementKind.PARAMETER && kind != ElementKind.FIELD) {
329 | logger.error("Only classes and methods can be annotated with @" + Query.class.getCanonicalName(), element);
330 | }
331 | String queryKey = deepLinkPathAnnotation.value();
332 | if (queryKey == null || queryKey.length() == 0) {
333 | logger.error("The inject query cannot be null @" + Query.class.getCanonicalName(), element);
334 | }
335 |
336 | if (kind == ElementKind.FIELD) {
337 | Element enclosingElement = element.getEnclosingElement();
338 | if (enclosingElement.getKind() != CLASS) {
339 | logger.error("@" + Query.class.getCanonicalName() + "only be contained in classes", element);
340 | }
341 | TypeElement typeElement = (TypeElement) enclosingElement;
342 | boolean support = isSupportInject(typeElement);
343 | if (!support) {
344 | logger.error("@" + Query.class.getCanonicalName() + "only support inject in activity or fragment", element);
345 | }
346 | if (element.getModifiers().contains(Modifier.PRIVATE)) {
347 | logger.error("The inject query fields can not be private, please check field @" + Query.class.getCanonicalName() + "in class" + typeElement.getQualifiedName(), element);
348 | }
349 | queryElements.add(element);
350 | }
351 | }
352 | return queryElements;
353 | }
354 |
355 |
356 | private List generateServiceElements(RoundEnvironment roundEnv) {
357 | Set extends Element> deepLinkServiceElements = roundEnv.getElementsAnnotatedWith(Service.class);
358 | List serviceElements = new ArrayList<>();
359 | for (Element element : deepLinkServiceElements) {
360 | serviceElements.add(element);
361 | }
362 | return serviceElements;
363 | }
364 |
365 | private Map> findInjectElements(List queryInjectElements) {
366 |
367 | Map> map = new HashMap<>();
368 |
369 | for (Element queryInjectElement : queryInjectElements) {
370 | TypeElement enclosingElement = (TypeElement) queryInjectElement.getEnclosingElement();
371 | List builder = map.get(enclosingElement);
372 | if (builder == null) {
373 | builder = new ArrayList<>();
374 | map.put(enclosingElement, builder);
375 | }
376 | builder.add(queryInjectElement);
377 | }
378 | return map;
379 | }
380 |
381 |
382 | private boolean isSupportInject(TypeElement typeElement) {
383 | for (String supportClass : SUPPORT_INJECT) {
384 | TypeMirror typeMirror = elements.getTypeElement(supportClass).asType();
385 | if (types.isSubtype(typeElement.asType(), typeMirror)) {
386 | return true;
387 | }
388 | }
389 | return false;
390 | }
391 |
392 |
393 | }
394 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/DeepLinkInterceptorProcessor.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import com.google.auto.service.AutoService;
5 | import com.squareup.javapoet.AnnotationSpec;
6 | import com.squareup.javapoet.ClassName;
7 | import com.squareup.javapoet.CodeBlock;
8 | import com.squareup.javapoet.JavaFile;
9 | import com.squareup.javapoet.MethodSpec;
10 | import com.squareup.javapoet.ParameterizedTypeName;
11 | import com.squareup.javapoet.TypeName;
12 | import com.squareup.javapoet.TypeSpec;
13 |
14 | import org.aspectj.lang.ProceedingJoinPoint;
15 | import org.aspectj.lang.annotation.Around;
16 | import org.aspectj.lang.annotation.Aspect;
17 |
18 | import java.io.IOException;
19 | import java.util.ArrayList;
20 | import java.util.HashSet;
21 | import java.util.List;
22 | import java.util.Map;
23 | import java.util.Set;
24 |
25 | import javax.annotation.processing.AbstractProcessor;
26 | import javax.annotation.processing.Filer;
27 | import javax.annotation.processing.ProcessingEnvironment;
28 | import javax.annotation.processing.Processor;
29 | import javax.annotation.processing.RoundEnvironment;
30 | import javax.lang.model.SourceVersion;
31 | import javax.lang.model.element.Element;
32 | import javax.lang.model.element.Modifier;
33 | import javax.lang.model.element.TypeElement;
34 |
35 | import okdeeplink.element.InterceptorElement;
36 | import okdeeplink.util.ElementUtils;
37 | import okdeeplink.util.Logger;
38 |
39 | import static javax.lang.model.element.ElementKind.CLASS;
40 | import static okdeeplink.DeepLinkServiceProcessor.DEEP_LINK_CLIENT;
41 | import static okdeeplink.DeepLinkServiceProcessor.PACKAGE_NAME;
42 |
43 |
44 | @AutoService(Processor.class)
45 | public class DeepLinkInterceptorProcessor extends AbstractProcessor {
46 |
47 | public static final String GLOBAL_INTERCEPTORS_METHOD_NAME = ElementUtils.getName(DEEP_LINK_CLIENT) + ".getGlobalInterceptors(..)";
48 |
49 | public static final String PATH_INTERCEPTORS_METHOD_NAME = ElementUtils.getName(DEEP_LINK_CLIENT) + ".getPathInterceptors(..)";
50 |
51 | public static final ClassName INTERCEPTOR = ClassName.get(PACKAGE_NAME, "Interceptor");
52 |
53 |
54 | private Filer filer;
55 | private Logger logger;
56 |
57 | @Override
58 | public synchronized void init(ProcessingEnvironment processingEnv) {
59 | super.init(processingEnv);
60 | logger = new Logger(processingEnv.getMessager());
61 | filer = processingEnv.getFiler();
62 | }
63 |
64 | @Override
65 | public Set getSupportedAnnotationTypes() {
66 | Set ret = new HashSet<>();
67 | ret.add(Intercept.class.getCanonicalName());
68 | return ret;
69 | }
70 |
71 | @Override
72 | public SourceVersion getSupportedSourceVersion() {
73 | return SourceVersion.latestSupported();
74 | }
75 |
76 | @Override
77 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
78 |
79 | List interceptorElements = generateInterceptorElements(roundEnv);
80 | if (ElementUtils.isEmpty(interceptorElements)) {
81 | return false;
82 | }
83 |
84 | for (InterceptorElement interceptorElement : interceptorElements) {
85 | String path = interceptorElement.getPath();
86 | MethodSpec.Builder methodBuilder;
87 | if (path == null || path.length() == 0) {
88 | methodBuilder = geneGlobalInterceptorsBuilder(interceptorElement);
89 | }else {
90 | methodBuilder = genePathInterceptorsBuilder(interceptorElement);
91 | }
92 |
93 | try {
94 | TypeSpec.Builder interceptorInitBuilder = TypeSpec.classBuilder(interceptorElement.getInitClassName())
95 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
96 | .addAnnotation(AnnotationSpec
97 | .builder(Aspect.class)
98 | .build())
99 | .addMethod(methodBuilder.build());
100 | JavaFile.builder(interceptorElement.getPackageName(), interceptorInitBuilder.build())
101 | .build()
102 | .writeTo(filer);
103 | } catch (IOException e) {
104 | logger.error("Error creating matcher file", interceptorElement.getElement());
105 | }
106 | }
107 |
108 |
109 | return true;
110 | }
111 |
112 |
113 | private MethodSpec.Builder genePathInterceptorsBuilder(InterceptorElement interceptorElement) {
114 | CodeBlock.Builder builder = CodeBlock.builder();
115 | TypeName typeName = ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class), INTERCEPTOR);
116 | builder.add("$T result = ($T)joinPoint.proceed();\n", typeName, typeName);
117 | String path = interceptorElement.getPath();
118 | builder.add("result.put($S,new $T());\n",
119 | path,
120 | interceptorElement.getClassName());
121 | builder.add("return result;\n");
122 | return MethodSpec.methodBuilder("getPathInterceptors")
123 | .addModifiers(Modifier.PUBLIC)
124 | .addParameter(ProceedingJoinPoint.class, "joinPoint")
125 | .returns(typeName)
126 | .addException(Throwable.class)
127 | .addAnnotation(AnnotationSpec
128 | .builder(Around.class)
129 | .addMember("value", "$S", "execution(* " + PATH_INTERCEPTORS_METHOD_NAME + ")").build())
130 | .addCode(builder.build());
131 | }
132 |
133 |
134 | private MethodSpec.Builder geneGlobalInterceptorsBuilder(InterceptorElement interceptorElement) {
135 | CodeBlock.Builder builder = CodeBlock.builder();
136 | TypeName typeName = ParameterizedTypeName.get(ClassName.get(List.class), INTERCEPTOR);
137 | builder.add("$T result = ($T)joinPoint.proceed();\n", typeName, typeName);
138 | builder.add("result.add(new $T());\n",
139 | interceptorElement.getClassName());
140 | builder.add("return result;\n");
141 | return MethodSpec.methodBuilder("getGlobalInterceptors")
142 | .addModifiers(Modifier.PUBLIC)
143 | .addParameter(ProceedingJoinPoint.class, "joinPoint")
144 | .returns(typeName)
145 | .addException(Throwable.class)
146 | .addAnnotation(AnnotationSpec
147 | .builder(Around.class)
148 | .addMember("value", "$S", "execution(* " + GLOBAL_INTERCEPTORS_METHOD_NAME + ")").build())
149 | .addCode(builder.build());
150 | }
151 |
152 |
153 | private List generateInterceptorElements(RoundEnvironment roundEnv) {
154 | Set extends Element> interceptorElements = roundEnv.getElementsAnnotatedWith(Intercept.class);
155 | List serviceElements = new ArrayList<>();
156 | for (Element element : interceptorElements) {
157 | if (element.getKind() == CLASS) {
158 | InterceptorElement serviceElement = new InterceptorElement(element);
159 | String name = serviceElement.getClassName().simpleName();
160 | if (!name.endsWith("Interceptor")) {
161 | logger.error(name + "must be end with Interceptor", element);
162 | }
163 | serviceElements.add(serviceElement);
164 | }
165 | }
166 | return serviceElements;
167 | }
168 |
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/DeepLinkServiceProcessor.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink;
3 |
4 | import com.google.auto.service.AutoService;
5 | import com.squareup.javapoet.AnnotationSpec;
6 | import com.squareup.javapoet.ClassName;
7 | import com.squareup.javapoet.CodeBlock;
8 | import com.squareup.javapoet.FieldSpec;
9 | import com.squareup.javapoet.JavaFile;
10 | import com.squareup.javapoet.MethodSpec;
11 | import com.squareup.javapoet.ParameterizedTypeName;
12 | import com.squareup.javapoet.TypeName;
13 | import com.squareup.javapoet.TypeSpec;
14 |
15 | import org.aspectj.lang.ProceedingJoinPoint;
16 | import org.aspectj.lang.annotation.After;
17 | import org.aspectj.lang.annotation.Around;
18 | import org.aspectj.lang.annotation.Aspect;
19 |
20 | import java.io.IOException;
21 | import java.util.ArrayList;
22 | import java.util.HashMap;
23 | import java.util.HashSet;
24 | import java.util.List;
25 | import java.util.Map;
26 | import java.util.Set;
27 |
28 | import javax.annotation.processing.AbstractProcessor;
29 | import javax.annotation.processing.Filer;
30 | import javax.annotation.processing.ProcessingEnvironment;
31 | import javax.annotation.processing.Processor;
32 | import javax.annotation.processing.RoundEnvironment;
33 | import javax.lang.model.SourceVersion;
34 | import javax.lang.model.element.Element;
35 | import javax.lang.model.element.ElementKind;
36 | import javax.lang.model.element.ExecutableElement;
37 | import javax.lang.model.element.Modifier;
38 | import javax.lang.model.element.TypeElement;
39 | import javax.lang.model.element.VariableElement;
40 | import javax.lang.model.type.TypeMirror;
41 | import javax.lang.model.util.Elements;
42 | import javax.lang.model.util.Types;
43 |
44 | import okdeeplink.element.AddressElement;
45 | import okdeeplink.util.ElementUtils;
46 | import okdeeplink.util.Logger;
47 | import okdeeplink.util.MethodGenerator;
48 |
49 | import static okdeeplink.DeepLinkInterceptorProcessor.INTERCEPTOR;
50 |
51 |
52 | @AutoService(Processor.class)
53 | public class DeepLinkServiceProcessor extends AbstractProcessor {
54 |
55 | private static final String INTERNAL_HOST = "app://deeplink";
56 |
57 | private static final ClassName INTENT = ClassName.get("android.content", "Intent");
58 | private static final ClassName URI = ClassName.get("android.net", "Uri");
59 |
60 |
61 | public static final String PACKAGE_NAME = DeepLinkServiceProcessor.class.getPackage().getName();
62 |
63 | private static final ClassName DEEP_LINK_ENTRY = ClassName.get(PACKAGE_NAME, "Address");
64 |
65 | public static final ClassName DEEP_LINK_CLIENT = ClassName.get(PACKAGE_NAME, "DeepLinkClient");
66 |
67 | public static final String INIT_METHOD_NAME = ElementUtils.getName(DEEP_LINK_CLIENT) + ".init(..)";
68 |
69 |
70 | public static final String BUILD_METHOD_NAME = ElementUtils.getName(DEEP_LINK_CLIENT) + ".build(..)";
71 |
72 | public static final String BUILD_REQUEST_METHOD_NAME = "buildRequest";
73 |
74 | private static final String PROVIDER_SUFFIX = "$$Provider";
75 |
76 |
77 | private static final ClassName DEEP_LINK_REQUEST = ClassName.get(PACKAGE_NAME, "Request");
78 |
79 | private static final TypeName DEEP_LINK_OBSERVABLE = ParameterizedTypeName.get(ClassName.get("rx", "Observable"), ClassName.get(PACKAGE_NAME, "Response"));
80 |
81 |
82 | private static final List SUPPORT_RETURN_TYPE = new ArrayList<>();
83 |
84 | private static final String ACTIVITY = "android.app.Activity";
85 |
86 |
87 | static {
88 | SUPPORT_RETURN_TYPE.add(DEEP_LINK_REQUEST);
89 | SUPPORT_RETURN_TYPE.add(TypeName.VOID);
90 | SUPPORT_RETURN_TYPE.add(DEEP_LINK_OBSERVABLE);
91 | }
92 |
93 |
94 | private List addresses = new ArrayList<>();
95 |
96 | private Filer filer;
97 | private Logger logger;
98 | private Types types;
99 | private Elements elements;
100 |
101 | @Override
102 | public synchronized void init(ProcessingEnvironment processingEnv) {
103 | super.init(processingEnv);
104 | logger = new Logger(processingEnv.getMessager());
105 | filer = processingEnv.getFiler();
106 | types = processingEnv.getTypeUtils();
107 | elements = processingEnv.getElementUtils();
108 | }
109 |
110 | @Override
111 | public Set getSupportedAnnotationTypes() {
112 | Set ret = new HashSet<>();
113 | ret.add(Path.class.getCanonicalName());
114 | ret.add(Action.class.getCanonicalName());
115 | ret.add(Activity.class.getCanonicalName());
116 | ret.add(Uri.class.getCanonicalName());
117 | return ret;
118 | }
119 |
120 | @Override
121 | public SourceVersion getSupportedSourceVersion() {
122 | return SourceVersion.latestSupported();
123 | }
124 |
125 | @Override
126 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
127 |
128 |
129 | List addressElements = generateAddressElements(roundEnv);
130 |
131 | if (ElementUtils.isEmpty(addressElements)) {
132 | return false;
133 | }
134 | Map> serviceElements = findServiceElements(addressElements);
135 | if (ElementUtils.isEmpty(serviceElements)) {
136 | return false;
137 | }
138 | for (Map.Entry> serviceElementEntrySet : serviceElements.entrySet()) {
139 | TypeElement serviceElement = serviceElementEntrySet.getKey();
140 | List serviceAddressElements = serviceElementEntrySet.getValue();
141 | if (ElementUtils.isEmpty(serviceAddressElements)) {
142 | break;
143 | }
144 | try {
145 | generateDeepLinkService(serviceElement, serviceAddressElements);
146 | } catch (IOException e) {
147 | logger.error("Error creating matcher file", serviceElement);
148 | }
149 | }
150 |
151 | return true;
152 | }
153 |
154 |
155 | private List generateAddressElements(RoundEnvironment roundEnv) {
156 | List annotationElements = new ArrayList<>();
157 | for (String annotationType : getSupportedAnnotationTypes()) {
158 | TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(annotationType);
159 | Set extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(typeElement);
160 | for (Element annotatedElement : annotatedElements) {
161 | if (!annotationElements.contains(annotatedElement)) {
162 | annotationElements.add(annotatedElement);
163 | }
164 | }
165 | }
166 |
167 | List serviceElements = new ArrayList<>();
168 | for (Element element : annotationElements) {
169 | ElementKind kind = element.getKind();
170 | if (kind != ElementKind.METHOD) {
171 | logger.error("Only classes and methods can be with " + getSupportedAnnotationTypes(), element);
172 | }
173 | if (!isSupportReturnType((ExecutableElement) element)) {
174 | logger.error("method only support return type is " + SUPPORT_RETURN_TYPE.toString(), element);
175 | }
176 |
177 | Element enclosingElement = element.getEnclosingElement();
178 | String name = enclosingElement.getSimpleName().toString();
179 | if (!name.endsWith("Service")) {
180 | logger.error(name + "this class must be in end with Service", enclosingElement);
181 | }
182 |
183 | if (enclosingElement.getKind() != ElementKind.INTERFACE) {
184 |
185 | logger.error(name + "this class must be interface", enclosingElement);
186 | }
187 | serviceElements.add(new AddressElement(element));
188 | }
189 | return serviceElements;
190 | }
191 |
192 |
193 | private Map> findServiceElements(List queryInjectElements) {
194 |
195 | Map> map = new HashMap<>();
196 |
197 | for (AddressElement queryInjectElement : queryInjectElements) {
198 | TypeElement enclosingElement = (TypeElement) queryInjectElement.getElement().getEnclosingElement();
199 | List builder = map.get(enclosingElement);
200 | if (builder == null) {
201 | builder = new ArrayList<>();
202 | map.put(enclosingElement, builder);
203 | }
204 | builder.add(queryInjectElement);
205 | }
206 | return map;
207 | }
208 |
209 |
210 | private void generateDeepLinkService(TypeElement serviceElements,
211 | List deepLinkMatchElements)
212 | throws IOException {
213 |
214 | ClassName providerClassName = getServiceProviderClassName(serviceElements);
215 |
216 | MethodSpec initMethod = generateInitMethod(deepLinkMatchElements);
217 |
218 |
219 | FieldSpec activity = FieldSpec
220 | .builder(DEEP_LINK_CLIENT, "deepLinkClient",
221 | Modifier.PUBLIC)
222 | .build();
223 |
224 |
225 | MethodSpec activityConstructor = MethodSpec.constructorBuilder()
226 | .addModifiers(Modifier.PUBLIC)
227 | .addParameter(DEEP_LINK_CLIENT, "deepLinkClient")
228 | .addCode("this.deepLinkClient= deepLinkClient;\n")
229 | .build();
230 | TypeSpec.Builder serviceProviderBuilder = TypeSpec.classBuilder(providerClassName)
231 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
232 | .addAnnotation(AnnotationSpec.builder(Aspect.class).build())
233 | .addSuperinterface(ClassName.get(serviceElements))
234 | .addField(activity)
235 | .addMethod(activityConstructor)
236 | .addMethod(initMethod);
237 |
238 |
239 | for (AddressElement matchElement : deepLinkMatchElements) {
240 | ExecutableElement element = (ExecutableElement) matchElement.getElement();
241 | serviceProviderBuilder.addMethod(geneOverServiceMethod(element));
242 | }
243 |
244 | MethodSpec buildMethodSpec = generateBuildMethod(serviceElements);
245 | serviceProviderBuilder.addMethod(buildMethodSpec);
246 | JavaFile.builder(ClassName.get(serviceElements).packageName(), serviceProviderBuilder.build())
247 | .build()
248 | .writeTo(filer);
249 | }
250 |
251 |
252 | private MethodSpec generateInitMethod(List addressElements) {
253 |
254 | CodeBlock.Builder initializer = CodeBlock.builder();
255 | for (AddressElement element : addressElements) {
256 | List deepLinkPaths = element.getDeepLinkPaths();
257 | if (!element.isPathsEmpty()) {
258 | for (String deepLinkPath : deepLinkPaths) {
259 | TypeMirror activityTypeMirror = element.getActivityTypeMirror();
260 | TypeMirror supportTypeMirror = elements.getTypeElement(ACTIVITY).asType();
261 | if (activityTypeMirror != null) {
262 | if (!types.isSubtype(activityTypeMirror, supportTypeMirror)) {
263 | logger.error(Activity.class.getName() + " only support class which extends " + ACTIVITY, element.getElement());
264 | }
265 | }
266 | ClassName activityClassName = element.getActivityClassName();
267 | if (activityClassName != null) {
268 | initializer.add("$T.addAddress(new $T($S, $T.class));\n",
269 | DEEP_LINK_CLIENT, DEEP_LINK_ENTRY, deepLinkPath, activityClassName);
270 | }
271 | }
272 | }
273 |
274 | }
275 | MethodSpec.Builder initMethod = MethodSpec.methodBuilder("init")
276 | .addModifiers(Modifier.PUBLIC)
277 | .addAnnotation(AnnotationSpec.builder(After.class).addMember("value", "$S", "execution(* " + INIT_METHOD_NAME + ")").build())
278 | .addCode(initializer.build());
279 |
280 | return initMethod.build();
281 | }
282 |
283 |
284 | private MethodSpec geneOverServiceMethod(ExecutableElement element) {
285 |
286 | TypeName returnType = ClassName.get(element.getReturnType());
287 |
288 | MethodSpec.Builder serviceMethodBuilder = new MethodGenerator(element)
289 | .overMethod(element.getSimpleName().toString());
290 | CodeBlock.Builder serviceStartMethodBuilder = CodeBlock
291 | .builder()
292 | .add("$T intent = new $T();\n", INTENT, INTENT);
293 |
294 |
295 | List extends VariableElement> params = element.getParameters();
296 |
297 | String requestCode = null;
298 |
299 | Map uriReplaces = new HashMap<>();
300 |
301 | if (params != null) {
302 | for (int i = 0; i < params.size(); i++) {
303 | VariableElement elem = params.get(i);
304 | Query query = elem.getAnnotation(Query.class);
305 | RequestCode requestCodeAnnotation = elem.getAnnotation(RequestCode.class);
306 | UriReplace uriReplaceAnnotation = elem.getAnnotation(UriReplace.class);
307 | if (uriReplaceAnnotation != null) {
308 |
309 | if (!ClassName.get(elem.asType()).equals(ClassName.get(String.class))) {
310 | logger.error(UriReplace.class + "must be annotation " + String.class, elem);
311 | }
312 | uriReplaces.put(uriReplaceAnnotation.value(), elem);
313 | }
314 | if (query != null) {
315 | serviceStartMethodBuilder.add("intent.putExtra($S,$L);\n", query.value(), elem);
316 | } else if (requestCodeAnnotation != null) {
317 | if (requestCode != null) {
318 | logger.error("Method Must have only one @" + RequestCode.class, elem);
319 | }
320 | TypeName requestCodeTypeName = TypeName.get(elem.asType());
321 | if (TypeName.INT.equals(requestCodeTypeName)) {
322 | requestCode = elem.getSimpleName().toString();
323 | } else {
324 | logger.error("@" + RequestCode.class + " must be annotation int variable", elem);
325 | }
326 | }
327 | }
328 | }
329 |
330 | AddressElement addressElement = new AddressElement(element);
331 |
332 | List pathList = addressElement.getDeepLinkPaths();
333 | List interceptorList = addressElement.getInterceptors();
334 |
335 | if (!addressElement.isPathsEmpty()) {
336 | if (!addressElement.isUriEmpty()) {
337 | logger.error("path or uri not use in same time ", element);
338 | }
339 | for (String path : pathList) {
340 | if (!path.startsWith("/")) {
341 | if (addressElement.getActivityClassName() == null) {
342 | logger.error("if you what start activity may be use " + Uri.class + " replace " + Path.class, element);
343 | }
344 | logger.error("path must be start with / ", element);
345 | }
346 | if (addresses.contains(path)) {
347 | logger.error("Duplicate path: " + path, element);
348 | }
349 | }
350 | addresses.addAll(pathList);
351 | String path = pathList.get(0);
352 | String url = path.startsWith("/") ? INTERNAL_HOST + path : path;
353 | serviceStartMethodBuilder.add(String.format("intent.setData($T.parse(\"%s\"));\n", url), URI);
354 | }
355 | if (!addressElement.isUriEmpty()) {
356 | if (addressElement.getActivityClassName() != null) {
357 | logger.error("uri not need activity annotation", element);
358 | }
359 | serviceStartMethodBuilder.add("$T uri = $S;\n", String.class, addressElement.getUri());
360 | for (String uriReplace : uriReplaces.keySet()) {
361 | serviceStartMethodBuilder.add("uri = uri.replace($S,$L);\n", "{" + uriReplace + "}", uriReplaces.get(uriReplace));
362 | }
363 | serviceStartMethodBuilder.add("intent.setData($T.parse(uri));\n", URI);
364 | }
365 |
366 |
367 | if (!addressElement.isActionEmpty()) {
368 | serviceStartMethodBuilder.add("intent.setAction($S);\n", addressElement.getIntentAction());
369 | }
370 | serviceStartMethodBuilder.add("$T request = deepLinkClient.$L(intent);\n", DEEP_LINK_REQUEST, BUILD_REQUEST_METHOD_NAME);
371 | serviceStartMethodBuilder.beginControlFlow("if (request != null)");
372 | if (requestCode != null) {
373 | serviceStartMethodBuilder.add("request.setRequestCode($L);\n", requestCode);
374 | }
375 | if (!ElementUtils.isEmpty(interceptorList)) {
376 | for (TypeMirror interceptorTypeMirror : interceptorList) {
377 | TypeMirror supportTypeMirror = elements.getTypeElement(ElementUtils.getName(INTERCEPTOR)).asType();
378 | TypeName typeName = ElementUtils.getClassName(interceptorTypeMirror);
379 | if (!types.isSubtype(interceptorTypeMirror, supportTypeMirror) || typeName.equals(TypeName.OBJECT)) {
380 | logger.error(Intercept.class.getName() + " only support class which extends " + INTERCEPTOR, element);
381 | }
382 | serviceStartMethodBuilder.add("request.addInterceptor(new $T());\n", ElementUtils.getClassName(interceptorTypeMirror));
383 | }
384 | }
385 | if (DEEP_LINK_REQUEST.equals(returnType)) {
386 | serviceStartMethodBuilder.endControlFlow();
387 | serviceStartMethodBuilder.add("return request;\n");
388 |
389 |
390 | } else if (TypeName.VOID.equals(returnType)) {
391 | serviceStartMethodBuilder.add("request.start();\n");
392 | serviceStartMethodBuilder.endControlFlow();
393 |
394 | } else if (DEEP_LINK_OBSERVABLE.equals(returnType)) {
395 |
396 | if (requestCode != null) {
397 | logger.error(returnType + " not need " + RequestCode.class, element);
398 | }
399 | serviceStartMethodBuilder.endControlFlow();
400 | serviceStartMethodBuilder.add("return request.createResponse();\n");
401 | }
402 |
403 |
404 | serviceMethodBuilder.addCode(serviceStartMethodBuilder.build());
405 | return serviceMethodBuilder.build();
406 | }
407 |
408 | private ClassName getServiceProviderClassName(TypeElement serviceElements) {
409 | String className = serviceElements.getSimpleName().toString();
410 | String packageName = ClassName.get(serviceElements).packageName();
411 | String serviceProviderName = className + PROVIDER_SUFFIX;
412 | return ClassName.get(packageName, serviceProviderName);
413 | }
414 |
415 |
416 | private MethodSpec generateBuildMethod(TypeElement deepLinkServiceElement) {
417 |
418 | CodeBlock.Builder codeBlockBuilder = CodeBlock.builder();
419 | codeBlockBuilder.add("$T target = ($T)joinPoint.getTarget();\n", DEEP_LINK_CLIENT, DEEP_LINK_CLIENT);
420 | codeBlockBuilder.beginControlFlow("if (joinPoint.getArgs() == null || joinPoint.getArgs().length != 1)");
421 | codeBlockBuilder.add("return joinPoint.proceed();\n");
422 | codeBlockBuilder.endControlFlow();
423 | codeBlockBuilder.add("$T arg = joinPoint.getArgs()[0];\n", Object.class);
424 | codeBlockBuilder.beginControlFlow("if (arg instanceof Class)");
425 | codeBlockBuilder.add("$T buildClass = ($T) arg;\n", Class.class, Class.class);
426 | codeBlockBuilder.beginControlFlow("if (buildClass.isAssignableFrom(getClass()))");
427 | codeBlockBuilder.add("return new $T(target);\n", getServiceProviderClassName(deepLinkServiceElement));
428 | codeBlockBuilder.endControlFlow();
429 | codeBlockBuilder.endControlFlow();
430 | codeBlockBuilder.add("return joinPoint.proceed();\n");
431 |
432 | MethodSpec.Builder initMethod = MethodSpec.methodBuilder("aroundBuildMethod")
433 | .addModifiers(Modifier.PUBLIC)
434 | .addParameter(ProceedingJoinPoint.class, "joinPoint")
435 | .returns(Object.class)
436 | .addException(Throwable.class)
437 | .addAnnotation(AnnotationSpec.builder(Around.class).addMember("value", "$S", "execution(* " + BUILD_METHOD_NAME + ")").build())
438 | .addCode(codeBlockBuilder.build());
439 |
440 | return initMethod.build();
441 | }
442 |
443 |
444 | private boolean isSupportReturnType(ExecutableElement executableElement) {
445 | if (executableElement == null) {
446 | return false;
447 | }
448 | TypeName matchReturnType = ClassName.get(executableElement.getReturnType());
449 | for (TypeName supportClass : SUPPORT_RETURN_TYPE) {
450 | if (supportClass.equals(matchReturnType)) {
451 | return true;
452 | }
453 | }
454 | return false;
455 | }
456 |
457 | }
458 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/element/AddressElement.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink.element;
3 |
4 | import com.squareup.javapoet.ClassName;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | import javax.lang.model.element.Element;
11 | import javax.lang.model.type.MirroredTypeException;
12 | import javax.lang.model.type.MirroredTypesException;
13 | import javax.lang.model.type.TypeMirror;
14 |
15 | import okdeeplink.Action;
16 | import okdeeplink.Activity;
17 | import okdeeplink.Intercept;
18 | import okdeeplink.Path;
19 | import okdeeplink.Uri;
20 | import okdeeplink.util.ElementUtils;
21 |
22 | public final class AddressElement {
23 |
24 | private TypeMirror activityTypeMirror;
25 | List deepLinkPaths = new ArrayList<>();
26 | List interceptorClassNames = new ArrayList<>();
27 |
28 | ClassName activityClassName;
29 | String intentAction;
30 | String uri;
31 |
32 | Element element;
33 |
34 |
35 | public AddressElement(Element element) {
36 | this.element = element;
37 | Path deepLinkPathAnnotation = element.getAnnotation(Path.class);
38 | Activity deepLinkActivityAnnotation = element.getAnnotation(Activity.class);
39 | Intercept interceptAnnotation = element.getAnnotation(Intercept.class);
40 | Action actionAnnotation = element.getAnnotation(Action.class);
41 | Uri uriAnnotation = element.getAnnotation(Uri.class);
42 | if (deepLinkPathAnnotation != null) {
43 | deepLinkPaths.addAll(Arrays.asList(deepLinkPathAnnotation.value()));
44 | }
45 | if (deepLinkActivityAnnotation != null) {
46 | try {
47 | deepLinkActivityAnnotation.value();
48 | } catch (MirroredTypeException mte) {
49 | activityTypeMirror = mte.getTypeMirror();
50 | activityClassName = ElementUtils.getClassName(activityTypeMirror);
51 | }
52 | }
53 | if (actionAnnotation != null) {
54 | intentAction = actionAnnotation.value();
55 | }
56 |
57 | if (uriAnnotation != null) {
58 | uri = uriAnnotation.value();
59 | }
60 |
61 | if (interceptAnnotation != null) {
62 | try {
63 | interceptAnnotation.value();
64 | } catch (MirroredTypesException mte) {
65 | List extends TypeMirror> typeMirrors = mte.getTypeMirrors();
66 | if (!ElementUtils.isEmpty(typeMirrors)) {
67 | for (TypeMirror typeMirror : typeMirrors) {
68 | interceptorClassNames.add(typeMirror);
69 | }
70 | }
71 |
72 | }
73 | }
74 |
75 | }
76 |
77 | public TypeMirror getActivityTypeMirror() {
78 | return activityTypeMirror;
79 | }
80 |
81 | public List getDeepLinkPaths() {
82 | return deepLinkPaths;
83 | }
84 |
85 | public boolean isPathsEmpty() {
86 | return ElementUtils.isEmpty(getDeepLinkPaths());
87 | }
88 |
89 | public boolean isActionEmpty() {
90 | return intentAction == null || intentAction.length() == 0;
91 | }
92 |
93 | public boolean isUriEmpty() {
94 | return uri == null || uri.length() == 0;
95 | }
96 |
97 | public List getInterceptors() {
98 | return interceptorClassNames;
99 | }
100 |
101 | public ClassName getActivityClassName() {
102 | return activityClassName;
103 | }
104 |
105 | public Element getElement() {
106 | return element;
107 | }
108 |
109 | public String getIntentAction() {
110 | return intentAction;
111 | }
112 |
113 | public String getUri() {
114 | return uri;
115 | }
116 |
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/element/InterceptorElement.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink.element;
3 |
4 | import com.squareup.javapoet.ClassName;
5 |
6 | import javax.lang.model.element.Element;
7 | import javax.lang.model.element.PackageElement;
8 |
9 | import okdeeplink.Intercept;
10 |
11 | public final class InterceptorElement {
12 |
13 |
14 | private final ClassName initClassName;
15 | ClassName interceptorClassName;
16 | String packageName;
17 | Element element;
18 | String path;
19 |
20 | public InterceptorElement(Element serviceElement) {
21 | element = serviceElement;
22 | String className = serviceElement.getSimpleName().toString();
23 | PackageElement packageElement = (PackageElement) serviceElement.getEnclosingElement();
24 | packageName = packageElement.getQualifiedName().toString();
25 | interceptorClassName = ClassName.get(packageName, className);
26 | String serviceProviderName = className + "$$Injector";
27 | initClassName = ClassName.get(packageName, serviceProviderName);
28 | Intercept intercept = serviceElement.getAnnotation(Intercept.class);
29 | if (intercept != null) {
30 | path = intercept.path();
31 | }
32 | }
33 |
34 |
35 | public ClassName getInitClassName() {
36 | return initClassName;
37 | }
38 |
39 | public String getPackageName() {
40 | return packageName;
41 | }
42 |
43 |
44 | public ClassName getClassName() {
45 | return interceptorClassName;
46 | }
47 |
48 | public Element getElement() {
49 | return element;
50 | }
51 |
52 | public String getPath() {
53 | return path;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/element/ServiceElement.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink.element;
3 |
4 | import com.squareup.javapoet.ClassName;
5 |
6 | import java.util.List;
7 |
8 | import javax.lang.model.element.Element;
9 | import javax.lang.model.element.PackageElement;
10 |
11 | public final class ServiceElement {
12 |
13 |
14 | ClassName serviceClassName;
15 | String packageName;
16 | ClassName providerClassName;
17 | List extends Element> enclosedElements;
18 | Element element;
19 |
20 | public ServiceElement(Element serviceElement) {
21 | element = serviceElement;
22 | String className = serviceElement.getSimpleName().toString();
23 | PackageElement packageElement = (PackageElement) serviceElement.getEnclosingElement();
24 | packageName = packageElement.getQualifiedName().toString();
25 | serviceClassName = ClassName.get(packageName, className);
26 | enclosedElements = serviceElement.getEnclosedElements();
27 | String serviceProviderName = className +"$$Provider";
28 | providerClassName = ClassName.get(packageName, serviceProviderName);
29 |
30 | }
31 |
32 |
33 | public String getPackageName() {
34 | return packageName;
35 | }
36 |
37 | public ClassName getProviderClassName() {
38 | return providerClassName;
39 | }
40 |
41 | public ClassName getClassName() {
42 | return serviceClassName;
43 | }
44 |
45 | public List extends Element> getEnclosedElements() {
46 | return enclosedElements;
47 | }
48 |
49 | public Element getElement() {
50 | return element;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/util/ElementUtils.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.util;
2 |
3 | import com.squareup.javapoet.ClassName;
4 |
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import javax.lang.model.type.TypeMirror;
9 |
10 | /**
11 | * Created by zhangqijun on 2017/4/24.
12 | */
13 |
14 | public class ElementUtils {
15 |
16 |
17 | public static ClassName getClassName(TypeMirror typeMirror) {
18 | String fullyQualifiedClassName = typeMirror.toString();
19 | String simpleClassName = getSimpleName(fullyQualifiedClassName);
20 | String packageName = getPackageName(fullyQualifiedClassName);
21 | return ClassName.get(packageName, simpleClassName);
22 | }
23 |
24 |
25 | public static String getName(ClassName className) {
26 | return className.packageName()+"."+ className.simpleName();
27 | }
28 |
29 |
30 |
31 | private static String getPackageName(String fullyQualifiedClassName) {
32 | int dotIndex = fullyQualifiedClassName.lastIndexOf(".");
33 | return fullyQualifiedClassName.substring(0, dotIndex);
34 | }
35 |
36 |
37 | private static String getSimpleName(String fullyQualifiedClassName) {
38 | int dotIndex = fullyQualifiedClassName.lastIndexOf(".");
39 | return fullyQualifiedClassName.substring(dotIndex + 1, fullyQualifiedClassName.length());
40 | }
41 |
42 | public static boolean isEmpty(List list) {
43 | return list == null || list.size() == 0;
44 | }
45 |
46 | public static boolean isEmpty(Map map) {
47 | return map == null || map.size() == 0;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/util/Logger.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.util;
2 |
3 | import javax.annotation.processing.Messager;
4 | import javax.lang.model.element.Element;
5 | import javax.tools.Diagnostic;
6 |
7 | /**
8 | * Simplify the messager.
9 | *
10 | * @author Alex Contact me.
11 | * @version 1.0
12 | * @since 16/8/22 上午11:48
13 | */
14 | public class Logger {
15 | private Messager msg;
16 |
17 | public Logger(Messager messager) {
18 | msg = messager;
19 | }
20 |
21 |
22 | public void info(CharSequence info, Element element) {
23 | msg.printMessage(Diagnostic.Kind.NOTE, info, element);
24 | }
25 |
26 | public void error(CharSequence error, Element element) {
27 | msg.printMessage(Diagnostic.Kind.ERROR, error, element);
28 | }
29 |
30 |
31 | public void error(Throwable error, Element element) {
32 | msg.printMessage(Diagnostic.Kind.ERROR, "An exception is encountered, [" + error.getMessage() + "]" + "\n" + formatStackTrace(error.getStackTrace()), element);
33 |
34 | }
35 |
36 | public void warning(CharSequence warning, Element element) {
37 | msg.printMessage(Diagnostic.Kind.WARNING, warning, element);
38 |
39 | }
40 |
41 | private String formatStackTrace(StackTraceElement[] stackTrace) {
42 | StringBuilder sb = new StringBuilder();
43 | for (StackTraceElement element : stackTrace) {
44 | sb.append(" at ").append(element.toString());
45 | sb.append("\n");
46 | }
47 | return sb.toString();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/okdeeplink-processor/src/main/java/okdeeplink/util/MethodGenerator.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.util;
2 |
3 | import com.squareup.javapoet.AnnotationSpec;
4 | import com.squareup.javapoet.ClassName;
5 | import com.squareup.javapoet.MethodSpec;
6 |
7 | import java.util.List;
8 |
9 | import javax.lang.model.element.ExecutableElement;
10 | import javax.lang.model.element.Modifier;
11 | import javax.lang.model.element.VariableElement;
12 | import javax.lang.model.type.TypeMirror;
13 |
14 | /**
15 | * Created by zhangqijun on 2017/4/28.
16 | */
17 |
18 | public class MethodGenerator {
19 |
20 | private ExecutableElement executableElement;
21 |
22 | public MethodGenerator(ExecutableElement executableElement) {
23 | this.executableElement = executableElement;
24 | }
25 |
26 | public MethodSpec.Builder overMethod(String name) {
27 |
28 |
29 | MethodSpec.Builder builder = MethodSpec.methodBuilder(getValidMethodName(name));
30 |
31 | addModifiers(builder);
32 |
33 | addAnnotation(builder);
34 |
35 | checkParameters(executableElement, builder);
36 |
37 | addReturnType(executableElement, builder);
38 |
39 | addExceptions(executableElement, builder);
40 |
41 | return builder;
42 | }
43 |
44 |
45 |
46 | MethodGenerator addModifiers(MethodSpec.Builder builder) {
47 | builder.addModifiers(Modifier.PUBLIC);
48 | return this;
49 | }
50 |
51 | void addAnnotation(MethodSpec.Builder builder) {
52 | builder.addAnnotation(AnnotationSpec.builder(Override.class).build());
53 | }
54 |
55 | String getValidMethodName(String name) {
56 | return name.replace(' ', '_');
57 | }
58 |
59 | void addExceptions(ExecutableElement annotatedMtd, MethodSpec.Builder builder) {
60 | List extends TypeMirror> exceptions = annotatedMtd.getThrownTypes();
61 | if (exceptions != null){
62 | for (TypeMirror exc : exceptions) {
63 | builder.addException(ClassName.get(exc));
64 | }
65 | }
66 | }
67 |
68 | void addReturnType(ExecutableElement annotatedMtd, MethodSpec.Builder builder) {
69 | builder.returns(ClassName.get(annotatedMtd.getReturnType()));
70 | }
71 |
72 | void checkParameters(ExecutableElement annotatedMtd, MethodSpec.Builder builder) {
73 | List extends VariableElement> params = annotatedMtd.getParameters();
74 | if (params != null){
75 | for (int i = 0; i < params.size(); i++) {
76 | VariableElement elem = params.get(i);
77 | builder.addParameter(ClassName.get(elem.asType()), elem.getSimpleName().toString());
78 | }
79 | }
80 |
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/pom-evaluator.gradle:
--------------------------------------------------------------------------------
1 | apply from: "${rootDir}/bintrayUpload.gradle"
2 | afterEvaluate {
3 | install {
4 | repositories.mavenInstaller {
5 | pom.groupId = rootProject.groupId
6 | pom.version = rootProject.versionName
7 |
8 | pom.whenConfigured { pom ->
9 | pom.dependencies.findAll { dep -> dep.groupId == rootProject.name }.collect { dep ->
10 | dep.groupId = pom.groupId = rootProject.groupId
11 | dep.version = pom.version = rootProject.versionName
12 | }
13 | }
14 | }
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # OkDeepLink
2 | [](https://travis-ci.org/HongJun2046/OkDeepLink)
3 | [  ](https://bintray.com/zmanchina/maven/okdeeplink-gradle/_latestVersion)
4 |
5 | OkDeepLink provides a annotation-based api to manipulate app deep links.
6 |
7 | - register deep links with annotation `@Path`、`@Activity`
8 | - start deep links by service which generates an implementation by `Annotation-processor`, auto inject to activity with annotation `@Service`
9 | - url or bundle parameters auto inject to activity , restore when activity recreate by annotation `@Query`
10 | - async intercept deep links in ui thread with annotation `@Intercept`
11 | - support activity result with `rxJava`
12 |
13 |
14 | ### Config
15 | **In Root Gradle**
16 |
17 | ```groovy
18 | repositories {
19 | jcenter()
20 | }
21 | dependencies {
22 | classpath 'com.hongjun:okdeeplink-gradle:1.0.0'
23 | }
24 | ```
25 |
26 | **In App Or Lib Gradle**
27 |
28 | ```groovy
29 | apply plugin: 'okdeeplink.plugin'
30 | ```
31 | if use multiple apt lib, you must use
32 |
33 | ```groovy
34 | packagingOptions {
35 | exclude 'META-INF/services/javax.annotation.processing.Processor'
36 | }
37 | ```
38 |
39 | ### Example
40 |
41 | If you want define `old://app/main?key=value` uri, you can do like this
42 |
43 | #### Define Host And Scheme
44 |
45 | you can define dispatch activity which receive deep links in your `AndroidManifest.xml` file (using `odl` as an example):
46 |
47 | **In App AndroidManifest**
48 | ```xml
49 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
61 |
62 |
63 | ```
64 | In the future, I will use annotation `@AppLink` which define scheme and host instead of `AndroidManifest.xml`. I already have a simple way.
65 |
66 | **In Service File**
67 |
68 | ```java
69 | public interface SampleService {
70 |
71 |
72 | @Path("/main")
73 | @Activity(MainActivity.class)
74 | void startMainActivity(@Query("key") String key);
75 | }
76 | ```
77 | path must start with "/"
78 | when app receive uri like `old://app/main?key=value`, `DeepLinkActivity` will start ,then dispatch the deep link to the appropriate `Activity`.
79 |
80 |
81 | **In Activity Or Fragment File**
82 |
83 | You also start MainActivity by service in app.
84 | ```java
85 | public class SecondActivity extends AppCompatActivity {
86 |
87 | @Service
88 | SampleService sampleService;
89 | @Query("key")
90 | String key;
91 |
92 |
93 | sampleService.startMainActivity("value");
94 | }
95 |
96 | ```
97 |
98 | ### Intercept
99 | If you want Intercept `old://app/second`, you can use `@Intercept`
100 |
101 | ```java
102 | @Intercept(path = "/second")
103 | public class SecondInterceptor extends Interceptor {
104 | @Override
105 | public void intercept(final Call call) {
106 | Request request = call.getRequest();
107 | final Intent intent = request.getIntent();
108 | Context context = request.getContext();
109 |
110 | StringBuffer stringBuffer = new StringBuffer();
111 | stringBuffer.append("Intercept\n");
112 | stringBuffer.append("URL: " + request.getUrl() + "\n");
113 |
114 | AlertDialog.Builder builder = new AlertDialog.Builder(context,R.style.Theme_AppCompat_Dialog_Alert);
115 | builder.setTitle("Notice");
116 | builder.setMessage(stringBuffer);
117 | builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
118 | @Override
119 | public void onClick(DialogInterface dialog, int which) {
120 | call.cancel();
121 | }
122 | });
123 | builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
124 | @Override
125 | public void onClick(DialogInterface dialog, int which) {
126 | intent.putExtra("key1", "value3");
127 | call.proceed();
128 | }
129 | });
130 | builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
131 | @Override
132 | public void onDismiss(DialogInterface dialog) {
133 | call.cancel();
134 | }
135 | });
136 | builder.show();
137 | }
138 | }
139 | ```
140 |
141 | 
142 |
143 |
144 | ### Log
145 | I define `LogInterceptor`, this can log deep links which start、notFound、error , log tag is `OkDeepLink`
146 |
147 | ### Other Way
148 | You can start intent action by service
149 |
150 | ```java
151 | public interface SampleService {
152 |
153 | @Action(MediaStore.ACTION_IMAGE_CAPTURE)
154 | Observable startImageCapture();
155 |
156 | @Action(Intent.ACTION_DIAL)
157 | @Uri("tel:{phone}")
158 | void startTel(@UriReplace("phone") String phone);
159 | }
160 |
161 | ```
162 | ```java
163 | public void startImageCapture(){
164 | sampleService
165 | .startImageCapture()
166 | .subscribe(new Action1() {
167 | @Override
168 | public void call(Response response) {
169 | Intent data = response.getData();
170 | int resultCode = response.getResultCode();
171 | if (resultCode == RESULT_OK) {
172 | Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
173 | ImageView imageView = (ImageView) findViewById(R.id.ImageView_Capture_Image);
174 | imageView.setImageBitmap(imageBitmap);
175 | }
176 | }
177 | });
178 | }
179 |
180 | public void startTel(String phone){
181 | sampleService
182 | .startTel(phone);
183 | }
184 | ```
185 |
186 | ### Words
187 |
188 | It is so simple,then you just do it like `sample`
189 |
190 | License
191 | -------
192 |
193 | Copyright 2017 Hongjun2046
194 |
195 | Licensed under the Apache License, Version 2.0 (the "License");
196 | you may not use this file except in compliance with the License.
197 | You may obtain a copy of the License at
198 |
199 | http://www.apache.org/licenses/LICENSE-2.0
200 |
201 | Unless required by applicable law or agreed to in writing, software
202 | distributed under the License is distributed on an "AS IS" BASIS,
203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
204 | See the License for the specific language governing permissions and
205 | limitations under the License.
206 |
207 |
208 |
--------------------------------------------------------------------------------
/rxactivityresult/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/rxactivityresult/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | consumerProguardFiles 'proguard-rules.pro'
13 |
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(dir: 'libs', include: ['*.jar'])
25 | compile 'com.android.support:appcompat-v7:25.0.0'
26 | compile 'io.reactivex:rxjava:1.1.5'
27 | compile 'io.reactivex:rxandroid:1.2.1'
28 | testCompile 'junit:junit:4.12'
29 | compile 'com.android.support:support-fragment:25.0.0'
30 | }
31 |
32 | apply from: "${rootDir}/pom-evaluator.gradle"
33 |
--------------------------------------------------------------------------------
/rxactivityresult/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/sunshine/Documents/AndroidStudio/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 |
27 |
28 | #--- rxjava start
29 |
30 | -keep class sun.misc.Unsafe { *; }
31 | -keepattributes SourceFile,LineNumberTable
32 | -dontwarn sun.misc.**
33 |
34 | -keep class rx.schedulers.Schedulers {
35 | public static ;
36 | }
37 | -keep class rx.schedulers.ImmediateScheduler {
38 | public ;
39 | }
40 | -keep class rx.schedulers.TestScheduler {
41 | public ;
42 | }
43 | -keep class rx.schedulers.Schedulers {
44 | public static ** test();
45 | }
46 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
47 | long producerIndex;
48 | long consumerIndex;
49 | }
50 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
51 | long producerNode;
52 | long consumerNode;
53 | }
54 | -dontnote rx.internal.util.PlatformDependent
55 |
56 | #--- rxjava end
--------------------------------------------------------------------------------
/rxactivityresult/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/ActivityResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Copyright 2016 Víctor Albertos
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 rxactivityresult;
18 |
19 | import android.content.Intent;
20 |
21 | public class ActivityResult {
22 | private final int resultCode;
23 | private final Intent data;
24 |
25 | public ActivityResult(int resultCode, Intent data) {
26 | this.resultCode = resultCode;
27 | this.data = data;
28 | }
29 |
30 | public int getResultCode() {
31 | return resultCode;
32 | }
33 |
34 | public Intent getData() {
35 | return data;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/IActivityObservable.java:
--------------------------------------------------------------------------------
1 | package rxactivityresult;
2 |
3 | import android.content.Intent;
4 |
5 | import rx.Observable;
6 |
7 | /**
8 | * Created by zhangqijun on 2017/6/9.
9 | */
10 |
11 | interface IActivityObservable {
12 |
13 | Observable getAttachedObservable();
14 |
15 | Observable getResultObservable();
16 |
17 | void startIntent(Intent intent);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/RxActivityResult.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 rxactivityresult;
18 |
19 | import android.app.Activity;
20 | import android.app.Fragment;
21 | import android.app.FragmentManager;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.support.v4.app.FragmentActivity;
25 |
26 | import java.lang.ref.WeakReference;
27 |
28 | import rx.Observable;
29 | import rx.functions.Func1;
30 |
31 |
32 | public final class RxActivityResult {
33 |
34 |
35 | private RxActivityResult() {
36 | }
37 |
38 |
39 | public static RxActivityResult.Builder on(T context) {
40 | return new RxActivityResult.Builder<>(context);
41 | }
42 |
43 | public static RxActivityResult.Builder on(T fragment) {
44 | return new RxActivityResult.Builder<>(fragment);
45 | }
46 |
47 | public static RxActivityResult.Builder on(T fragment) {
48 | return new RxActivityResult.Builder<>(fragment);
49 | }
50 |
51 |
52 | public static class Builder {
53 |
54 | WeakReference targetWeak;
55 |
56 | private Builder(T t) {
57 | targetWeak = new WeakReference(t);
58 | }
59 |
60 |
61 | public Observable startIntent(final Intent intent) {
62 | IActivityObservable activityObservable = buildActivityObservable();
63 | Observable intentObservable = startActivity(activityObservable, intent);
64 | Observable.Transformer transformer = getActivityResultTransformer();
65 | return intentObservable.compose(transformer);
66 | }
67 |
68 |
69 |
70 | private Observable startActivity(final IActivityObservable activityObservable, final Intent intent) {
71 | return activityObservable
72 | .getAttachedObservable()
73 | .filter(new Func1() {
74 | @Override
75 | public Boolean call(Boolean attach) {
76 | return attach;
77 | }
78 | })
79 | .take(1)
80 | .map(new Func1() {
81 | @Override
82 | public IActivityObservable call(Boolean aBoolean) {
83 | activityObservable.startIntent(intent);
84 | return activityObservable;
85 | }
86 | });
87 | }
88 |
89 | private IActivityObservable buildActivityObservable() {
90 |
91 | T target = targetWeak.get();
92 |
93 | if (target instanceof FragmentActivity) {
94 | FragmentActivity activity = (FragmentActivity) target;
95 | android.support.v4.app.FragmentManager fragmentManager = activity.getSupportFragmentManager();
96 | IActivityObservable activityObservable = RxResultHoldFragmentV4.getHoldFragment(fragmentManager);
97 | return activityObservable;
98 | }
99 |
100 | if (target instanceof Activity) {
101 | Activity activity = (Activity) target;
102 | FragmentManager fragmentManager = activity.getFragmentManager();
103 | IActivityObservable activityObservable = RxResultHoldFragment.getHoldFragment(fragmentManager);
104 | return activityObservable;
105 | }
106 | if (target instanceof Context) {
107 | final Context context = (Context) target;
108 | IActivityObservable activityObservable = new RxResultHoldContext(context);
109 | return activityObservable;
110 | }
111 |
112 | if (target instanceof Fragment) {
113 | Fragment fragment = (Fragment) target;
114 | FragmentManager fragmentManager = fragment.getFragmentManager();
115 | if (fragmentManager != null) {
116 | IActivityObservable activityObservable = RxResultHoldFragment.getHoldFragment(fragmentManager);
117 | return activityObservable;
118 | }
119 | }
120 | if (target instanceof android.support.v4.app.Fragment) {
121 | android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) target;
122 | android.support.v4.app.FragmentManager fragmentManager = fragment.getFragmentManager();
123 | if (fragmentManager != null) {
124 | IActivityObservable activityObservable = RxResultHoldFragmentV4.getHoldFragment(fragmentManager);
125 | return activityObservable;
126 | }
127 | }
128 | return new RxResultHoldEmpty();
129 | }
130 |
131 |
132 | public Observable.Transformer getActivityResultTransformer() {
133 | return new Observable.Transformer() {
134 | @Override
135 | public Observable call(Observable intentObservable) {
136 | return intentObservable
137 | .flatMap(new Func1>() {
138 | @Override
139 | public Observable call(IActivityObservable activityObservable) {
140 | return activityObservable.getResultObservable();
141 | }
142 | })
143 | .filter(new Func1() {
144 | @Override
145 | public Boolean call(ActivityResult result) {
146 | T target = targetWeak.get();
147 | return target != null;
148 | }
149 | });
150 | }
151 | };
152 | }
153 |
154 |
155 | }
156 |
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/RxResultHoldContext.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 rxactivityresult;
18 |
19 | import android.app.Activity;
20 | import android.content.Context;
21 | import android.content.Intent;
22 |
23 | import rx.Observable;
24 | import rx.subjects.BehaviorSubject;
25 | import rx.subjects.PublishSubject;
26 |
27 |
28 | /**
29 | * @author nekocode (nekocode.cn@gmail.com)
30 | */
31 | class RxResultHoldContext implements IActivityObservable {
32 |
33 | private Context context;
34 |
35 | public final PublishSubject resultPublisher = PublishSubject.create();
36 | public final BehaviorSubject attachedPublisher = BehaviorSubject.create(true);
37 |
38 |
39 | public RxResultHoldContext(Context context) {
40 | this.context = context;
41 | attachedPublisher.onNext(true);
42 | }
43 |
44 | public Observable getResultObservable() {
45 | return resultPublisher.asObservable();
46 | }
47 |
48 | public Observable getAttachedObservable() {
49 | return attachedPublisher.asObservable();
50 | }
51 |
52 |
53 | public void startIntent(Intent intent) {
54 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
55 | context.startActivity(intent);
56 |
57 | resultPublisher.onNext(new ActivityResult(Activity.RESULT_OK, null));
58 | resultPublisher.onCompleted();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/RxResultHoldEmpty.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 rxactivityresult;
18 |
19 | import android.content.Intent;
20 |
21 | import rx.Observable;
22 |
23 |
24 | /**
25 | * @author nekocode (nekocode.cn@gmail.com)
26 | */
27 | class RxResultHoldEmpty implements IActivityObservable {
28 |
29 |
30 | public Observable getResultObservable() {
31 | return Observable.empty();
32 | }
33 |
34 | public Observable getAttachedObservable() {
35 | return Observable.empty();
36 | }
37 |
38 |
39 | public void startIntent(Intent intent) {
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/RxResultHoldFragment.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 rxactivityresult;
18 |
19 | import android.app.Activity;
20 | import android.app.Fragment;
21 | import android.app.FragmentManager;
22 | import android.app.FragmentTransaction;
23 | import android.content.Context;
24 | import android.content.Intent;
25 | import android.os.Build;
26 | import android.os.Bundle;
27 | import android.support.annotation.Nullable;
28 |
29 | import rx.Observable;
30 | import rx.subjects.PublishSubject;
31 |
32 |
33 | /**
34 | * @author nekocode (nekocode.cn@gmail.com)
35 | */
36 | public class RxResultHoldFragment extends Fragment implements IActivityObservable {
37 |
38 | public static final String TAG = RxResultHoldFragment.class.getName();
39 | private ActivityResult activityResult;
40 | public final PublishSubject resultPublisher = PublishSubject.create();
41 | public final PublishSubject attachedPublisher = PublishSubject.create();
42 |
43 | public RxResultHoldFragment() {
44 |
45 | }
46 |
47 | @Override
48 | public void onCreate(@Nullable Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | setRetainInstance(true);
51 | }
52 |
53 | public Observable getResultObservable() {
54 | return resultPublisher.asObservable();
55 | }
56 |
57 | public Observable getAttachedObservable() {
58 | return attachedPublisher.asObservable();
59 | }
60 |
61 | @Override
62 | public void onAttach(Context context) {
63 | super.onAttach(context);
64 | onAttachToContext(context);
65 | }
66 |
67 | @SuppressWarnings("deprecation")
68 | @Override
69 | public void onAttach(Activity activity) {
70 | super.onAttach(activity);
71 | if (Build.VERSION.SDK_INT < 23) {
72 | onAttachToContext(activity);
73 | }
74 | }
75 |
76 |
77 | private void onAttachToContext(Context context) {
78 | attachedPublisher.onNext(true);
79 | }
80 |
81 |
82 | public void startIntent(Intent intent) {
83 | startActivityForResult(intent, 100);
84 | }
85 |
86 |
87 | @Override
88 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
89 | super.onActivityResult(requestCode, resultCode, data);
90 | activityResult = new ActivityResult(resultCode, data);
91 |
92 |
93 | }
94 |
95 | @Override
96 | public void onResume() {
97 | super.onResume();
98 | if (activityResult != null) {
99 | resultPublisher.onNext(activityResult);
100 | activityResult = null;
101 | resultPublisher.onCompleted();
102 | FragmentTransaction transaction = getFragmentManager().beginTransaction();
103 | transaction.remove(this);
104 | transaction.commit();
105 | }
106 | }
107 |
108 | public static RxResultHoldFragment getHoldFragment(FragmentManager fragmentManager) {
109 | RxResultHoldFragment holdFragment = new RxResultHoldFragment();
110 | FragmentTransaction transaction = fragmentManager.beginTransaction();
111 | transaction.add(holdFragment, RxResultHoldFragment.TAG);
112 | transaction.commit();
113 | return holdFragment;
114 | }
115 |
116 |
117 | @Override
118 | public void onSaveInstanceState(Bundle outState) {
119 | super.onSaveInstanceState(outState);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/java/rxactivityresult/RxResultHoldFragmentV4.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 rxactivityresult;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.support.annotation.Nullable;
23 | import android.support.v4.app.Fragment;
24 | import android.support.v4.app.FragmentManager;
25 | import android.support.v4.app.FragmentTransaction;
26 |
27 | import rx.Observable;
28 | import rx.subjects.PublishSubject;
29 |
30 |
31 | /**
32 | * @author nekocode (nekocode.cn@gmail.com)
33 | */
34 | public class RxResultHoldFragmentV4 extends Fragment implements IActivityObservable {
35 |
36 | public static final String TAG = RxResultHoldFragmentV4.class.getName();
37 | public final PublishSubject resultPublisher = PublishSubject.create();
38 | public final PublishSubject attachedPublisher = PublishSubject.create();
39 | private ActivityResult activityResult;
40 |
41 |
42 | public RxResultHoldFragmentV4() {
43 | }
44 |
45 | @Override
46 | public void onCreate(@Nullable Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setRetainInstance(true);
49 | }
50 |
51 | @Override
52 | public void onSaveInstanceState(Bundle outState) {
53 | super.onSaveInstanceState(outState);
54 | }
55 |
56 | public Observable getResultObservable() {
57 | return resultPublisher.asObservable();
58 | }
59 |
60 | public Observable getAttachedObservable() {
61 | return attachedPublisher.asObservable();
62 | }
63 |
64 | @Override
65 | public void onAttach(Context context) {
66 | super.onAttach(context);
67 | onAttachToContext(context);
68 |
69 | }
70 |
71 |
72 | private void onAttachToContext(Context context) {
73 | attachedPublisher.onNext(true);
74 | }
75 |
76 |
77 | public void startIntent(Intent intent) {
78 | startActivityForResult(intent, 100);
79 |
80 | }
81 |
82 |
83 | @Override
84 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
85 | super.onActivityResult(requestCode, resultCode, data);
86 | activityResult = new ActivityResult(resultCode, data);
87 |
88 |
89 | }
90 |
91 | @Override
92 | public void onResume() {
93 | super.onResume();
94 | if (activityResult != null) {
95 | resultPublisher.onNext(activityResult);
96 | activityResult = null;
97 | resultPublisher.onCompleted();
98 | FragmentTransaction transaction = getFragmentManager().beginTransaction();
99 | transaction.remove(this);
100 | transaction.commit();
101 | }
102 | }
103 |
104 |
105 | public static RxResultHoldFragmentV4 getHoldFragment(FragmentManager fragmentManager) {
106 | RxResultHoldFragmentV4 holdFragment = new RxResultHoldFragmentV4();
107 | FragmentTransaction transaction = fragmentManager.beginTransaction();
108 | transaction.add(holdFragment, RxResultHoldFragmentV4.TAG);
109 | transaction.commit();
110 | return holdFragment;
111 | }
112 |
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/rxactivityresult/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'android-aspectjx'
3 |
4 |
5 | android {
6 | compileSdkVersion 25
7 | buildToolsVersion "25.0.2"
8 |
9 | defaultConfig {
10 | applicationId "okdeeplink.sample"
11 | minSdkVersion 14
12 | targetSdkVersion 25
13 | versionCode 1
14 | versionName "1.0"
15 |
16 |
17 | }
18 | packagingOptions {
19 | exclude 'META-INF/services/javax.annotation.processing.Processor'
20 | }
21 | lintOptions {
22 | disable 'InvalidPackage'
23 | }
24 |
25 |
26 |
27 | // android.applicationVariants.all { variant ->
28 | // if (variant.install) {
29 | // variant.install.doLast {
30 | // description "Installs and Runs the APK for ${variant.description}."
31 | // def getMainActivity = { file ->
32 | // new XmlSlurper().parse(file).application.activity.find {
33 | // it.'intent-filter'.find { filter ->
34 | // return filter.action.find {
35 | // it.'@android:name'.text() == 'android.intent.action.MAIN'
36 | // } \
37 | // && filter.category.find {
38 | // it.'@android:name'.text() == 'android.intent.category.LAUNCHER'
39 | // }
40 | // }
41 | // }.'@android:name'
42 | // }
43 | // exec {
44 | // def activityClass =
45 | // getMainActivity(variant.outputs.processManifest.manifestOutputFile)
46 | // commandLine android.adbExe, 'shell', 'am', 'start', '-n',
47 | // "${variant.applicationId}/${activityClass}"
48 | //
49 | // }
50 | // }
51 | // }
52 | // }
53 | }
54 |
55 | configurations.all {
56 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
57 | }
58 |
59 | dependencies {
60 | compile project(":second")
61 | compile project(':okdeeplink-api')
62 | annotationProcessor project(':okdeeplink-processor')
63 | compile 'com.android.support:appcompat-v7:25.0.0'
64 | compile 'com.android.support:support-v4:25.0.0'
65 | }
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/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/christian/Environment/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 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/sample/src/main/java/okdeeplink/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package okdeeplink.sample;
3 |
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 |
11 | import okdeeplink.Query;
12 | import okdeeplink.Response;
13 | import okdeeplink.Service;
14 | import rx.functions.Action1;
15 |
16 |
17 | public class MainActivity extends AppCompatActivity {
18 |
19 | @Service
20 | SampleService sampleService;
21 | @Query("key")
22 | String key;
23 |
24 | @Override
25 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
26 | super.onActivityResult(requestCode, resultCode, data);
27 |
28 |
29 | }
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 |
36 | findViewById(R.id.Second).setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | sampleService.startSecondActivity("value1",2);
40 | }
41 | });
42 |
43 | findViewById(R.id.Capture_Image).setOnClickListener(new View.OnClickListener() {
44 | @Override
45 | public void onClick(View v) {
46 | sampleService
47 | .startImageCapture()
48 | .subscribe(new Action1() {
49 | @Override
50 | public void call(Response response) {
51 | Intent data = response.getData();
52 | int resultCode = response.getResultCode();
53 | if (resultCode == RESULT_OK) {
54 | Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
55 | ImageView imageView = (ImageView) findViewById(R.id.ImageView_Capture_Image);
56 | imageView.setImageBitmap(imageBitmap);
57 | }
58 | }
59 | });
60 | }
61 | });
62 |
63 | findViewById(R.id.Tel_Phone).setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | sampleService.startTel("10000");
67 | }
68 | });
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/sample/src/main/java/okdeeplink/sample/SampleService.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.sample;
2 |
3 | import android.content.Intent;
4 | import android.provider.MediaStore;
5 |
6 | import okdeeplink.Action;
7 | import okdeeplink.Activity;
8 | import okdeeplink.Path;
9 | import okdeeplink.Query;
10 | import okdeeplink.Response;
11 | import okdeeplink.Uri;
12 | import okdeeplink.UriReplace;
13 | import rx.Observable;
14 |
15 | /**
16 | * Created by zhangqijun on 2017/4/24.
17 | */
18 | public interface SampleService {
19 |
20 |
21 | @Path("/main")
22 | @Activity(MainActivity.class)
23 | void startMainActivity(@Query("key") String key);
24 |
25 | @Path("/second")
26 | void startSecondActivity(@Query("key1") String value1, @Query("key2") int value2);
27 |
28 |
29 | @Action(MediaStore.ACTION_IMAGE_CAPTURE)
30 | Observable startImageCapture();
31 |
32 |
33 | @Action(Intent.ACTION_DIAL)
34 | @Uri("tel:{phone}")
35 | void startTel(@UriReplace("phone") String phone);
36 | }
37 |
--------------------------------------------------------------------------------
/sample/src/main/java/okdeeplink/sample/SecondInterceptor.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.sample;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.support.v7.app.AlertDialog;
7 |
8 | import okdeeplink.Intercept;
9 | import okdeeplink.Interceptor;
10 | import okdeeplink.Request;
11 |
12 | /**
13 | * Created by zhangqijun on 2017/5/6.
14 | */
15 |
16 | @Intercept(path = "/second")
17 | public class SecondInterceptor extends Interceptor {
18 | @Override
19 | public void intercept(final Call call) {
20 |
21 | Request request = call.getRequest();
22 | final Intent intent = request.getIntent();
23 | Context context = request.getContext();
24 |
25 | StringBuffer stringBuffer = new StringBuffer();
26 | stringBuffer.append("Intercept\n");
27 | stringBuffer.append("URL: " + request.getUrl() + "\n");
28 |
29 | AlertDialog.Builder builder = new AlertDialog.Builder(context,R.style.Theme_AppCompat_Dialog_Alert);
30 | builder.setTitle("Notice");
31 | builder.setMessage(stringBuffer);
32 | builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
33 | @Override
34 | public void onClick(DialogInterface dialog, int which) {
35 | call.cancel();
36 | }
37 | });
38 | builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
39 | @Override
40 | public void onClick(DialogInterface dialog, int which) {
41 | intent.putExtra("key1", "value3");
42 | call.proceed();
43 | }
44 | });
45 | builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
46 | @Override
47 | public void onDismiss(DialogInterface dialog) {
48 | call.cancel();
49 | }
50 | });
51 | builder.show();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
23 |
24 |
29 |
30 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OkDeepLink Sample
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/second/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/second/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 |
4 | android {
5 | compileSdkVersion 25
6 | buildToolsVersion "25.0.2"
7 |
8 | defaultConfig {
9 | minSdkVersion 14
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile project(':okdeeplink-api')
31 | annotationProcessor project(':okdeeplink-processor')
32 | compile 'com.android.support:appcompat-v7:25.0.0'
33 | testCompile 'junit:junit:4.12'
34 | }
35 |
--------------------------------------------------------------------------------
/second/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/sunshine/Documents/AndroidStudio/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 |
--------------------------------------------------------------------------------
/second/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/second/src/main/java/okdeeplink/second/SecondActivity.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.second;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import okdeeplink.Query;
10 |
11 | /**
12 | * Created by zhangqijun on 2017/4/25.
13 | */
14 |
15 | public class SecondActivity extends AppCompatActivity {
16 |
17 | @Query("key1")
18 | String key1;
19 |
20 | @Query("key2")
21 | Integer key2;
22 |
23 |
24 | @Override
25 | protected void onCreate(@Nullable Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_second);
28 |
29 | Toast.makeText(this, "key1:" + key1 + "\nkey2:" + key2 + "\n", Toast.LENGTH_LONG).show();
30 | findViewById(R.id.Button).setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | finish();
34 | }
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/second/src/main/java/okdeeplink/second/SecondService.java:
--------------------------------------------------------------------------------
1 | package okdeeplink.second;
2 |
3 | import okdeeplink.Activity;
4 | import okdeeplink.Path;
5 |
6 | /**
7 | * Created by zhangqijun on 2017/4/24.
8 | */
9 |
10 | public interface SecondService {
11 |
12 | @Path("/second")
13 | @Activity(SecondActivity.class)
14 | void startSecondActivity();
15 | }
16 |
--------------------------------------------------------------------------------
/second/src/main/res/layout/activity_second.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/second/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/second/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':okdeeplink-annotation', ':okdeeplink-processor', ':okdeeplink-api', ':second', ':rxactivityresult', ':okdeeplink-gradle'
2 |
--------------------------------------------------------------------------------
/snapshot/intercept_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jjerry/OkDeepLink/9fa28eb3c04380970b76e0af9b0434170d82184a/snapshot/intercept_preview.png
--------------------------------------------------------------------------------