├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── paylib ├── .gitignore ├── build.gradle ├── libs │ └── alipaySingle-20170510.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zys │ │ └── paylib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zys │ │ │ └── paylib │ │ │ ├── PayConfig.java │ │ │ ├── alipay │ │ │ ├── AlipayUtil.java │ │ │ ├── AuthResult.java │ │ │ ├── Base64.java │ │ │ ├── OrderInfoUtil.java │ │ │ ├── PayResult.java │ │ │ └── SignUtils.java │ │ │ ├── pay │ │ │ ├── AliPay.java │ │ │ ├── IPay.java │ │ │ ├── PayTools.java │ │ │ └── WxPay.java │ │ │ └── wxpay │ │ │ ├── ParameterConfig.java │ │ │ ├── WXPayInfo.java │ │ │ └── WXPayUtil.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── zys │ └── paylib │ └── ExampleUnitTest.java ├── sample ├── .gitignore ├── build.gradle ├── class_files.txt ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zys │ │ └── zyspay │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zys │ │ │ └── zyspay │ │ │ └── demo │ │ │ ├── App.java │ │ │ ├── MainActivity.java │ │ │ └── wxapi │ │ │ └── WXPayEntryActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── wx_pay_result.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zys │ └── zyspay │ └── demo │ └── ExampleUnitTest.java └── settings.gradle /.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/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | # Uncomment the following line if you do not want to check your keystore files in. 47 | #*.jks 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PayLib 2 | [![](https://jitpack.io/v/Equalzys/PayLib.svg)](https://jitpack.io/#Equalzys/PayLib) 3 | 4 | 支付宝支付,微信支付封装,使用简单方便 5 | 只用自己服务器返回 支付宝或微信的预支付订单号 即可完成支付 6 | 7 | 第一步:在项目根目录的 build.gradle 里添加jitpack库 8 | ```java 9 | allprojects { 10 | repositories { 11 | ... 12 | maven { url 'https://jitpack.io' } 13 | } 14 | } 15 | ``` 16 | 17 | 第二步:在app的 build.gradle 里添加依赖 18 | ```java 19 | dependencies { 20 | implementation 'com.github.Equalzys:PayLib:1.0.2' 21 | } 22 | ``` 23 | 24 | 第三步:初始化库(建议在application里初始化) 25 | ```java 26 | String RSA_PRIVATE="6e**********eo5ff9=="; 27 | //用到支付宝的时候配置 28 | PayConfig.alipay() 29 | .appId("2017******3659") 30 | .rsa(RSA_PRIVATE) 31 | .notifyUrl("http://www.xx**xx.com/api/trade/notify/alipay") 32 | .intro("支付宝订单-") 33 | .init(); 34 | 35 | //用到微信的时候配置 36 | PayConfig.wxpay() 37 | .appId("wx62*******87") 38 | .mchId("15******1") 39 | .apiKey("Rd88G******I0ci406") 40 | .notifyUrl("http://www.xx**xx.com/api/trade/notify/wxpay") 41 | .intro("微信订单-") 42 | .init(); 43 | ``` 44 | 45 | 第四步:在支付的地方调用pay,ps:微信支付需要在包名下添加 wxapi.WXPayEntryActivity 46 | ```java 47 | //支付宝支付 48 | String tradenumber = "这里是实际交易订单号-服务器返回"; 49 | double money=0.01;//需要支付的金额 50 | PayTools.aliPay(this) 51 | .tradeNumber(tradenumber) 52 | .money(money) 53 | .intro("订单-")//(非必填) 54 | .pay(new AlipayUtil.AlipayCallBack() { 55 | @Override 56 | public void success(String ordernumber, String resultInfo) { 57 | 58 | } 59 | 60 | @Override 61 | public void fail(String resultInfo) { 62 | 63 | } 64 | 65 | }); 66 | 67 | 68 | 69 | //微信支付 70 | String tradenumber = "这里是实际交易订单号-服务器返回"; 71 | double money=0.01;//需要支付的金额 72 | PayTools.wxPay(this) 73 | .tradeNumber(tradenumber) 74 | .intro("订单-")//(非必填) 75 | .money(money) 76 | .pay();//支付回调在WXPayEntryActivity 77 | 78 | 79 | ``` 80 | -------------------------------------------------------------------------------- /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 | google() 6 | jcenter() 7 | mavenCentral() 8 | maven { 9 | url "https://jitpack.io" 10 | } 11 | maven { 12 | url "https://maven.google.com" 13 | } 14 | } 15 | dependencies { 16 | classpath 'com.android.tools.build:gradle:3.3.0' 17 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | allprojects { 24 | repositories { 25 | google() 26 | jcenter() 27 | mavenCentral() 28 | maven { 29 | url "https://jitpack.io" 30 | } 31 | maven { 32 | url "https://maven.google.com" 33 | } 34 | } 35 | } 36 | 37 | task clean(type: Delete) { 38 | delete rootProject.buildDir 39 | } 40 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equalzys/PayLib/613b325496b6f03843be57ba8f817f3a9feab226/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Feb 18 09:24:05 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 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 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /paylib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /paylib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | group='com.github.Equalzys' 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | defaultConfig { 9 | minSdkVersion 16 10 | targetSdkVersion 28 11 | versionCode 100 12 | versionName "1.0.0" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | 18 | useLibrary 'org.apache.http.legacy' 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | dexOptions { 27 | preDexLibraries = false 28 | } 29 | repositories { 30 | flatDir{ dirs 'libs' } 31 | } 32 | 33 | } 34 | 35 | dependencies { 36 | implementation fileTree(include: ['*.jar'], dir: 'libs') 37 | implementation 'com.android.support:appcompat-v7:28.0.0' 38 | testImplementation 'junit:junit:4.12' 39 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 40 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 41 | api files('libs/alipaySingle-20170510.jar') 42 | api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.1.6' 43 | } 44 | -------------------------------------------------------------------------------- /paylib/libs/alipaySingle-20170510.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equalzys/PayLib/613b325496b6f03843be57ba8f817f3a9feab226/paylib/libs/alipaySingle-20170510.jar -------------------------------------------------------------------------------- /paylib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /paylib/src/androidTest/java/com/zys/paylib/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zys.paylib.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /paylib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/PayConfig.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.text.TextUtils; 6 | 7 | import com.zys.paylib.alipay.AlipayUtil; 8 | import com.zys.paylib.wxpay.ParameterConfig; 9 | 10 | public class PayConfig { 11 | 12 | private static final String TAG = "PayConfig"; 13 | 14 | 15 | public static AliConfig alipay() { 16 | return new AliConfig(); 17 | } 18 | 19 | public static class AliConfig { 20 | /** 21 | * appid 22 | */ 23 | public AliInfo appId(String appid) { 24 | return new AliInfo(appid); 25 | } 26 | 27 | public class AliInfo { 28 | private String app_id; 29 | private String rsa_private; 30 | private String notify_url; 31 | private String intro; 32 | 33 | 34 | public AliInfo(String appid) { 35 | this.app_id = appid; 36 | } 37 | /** 38 | * 商户私钥,pkcs8格式,rsa2 39 | */ 40 | public AliInfo rsa(String rsa_private) { 41 | this.rsa_private = rsa_private; 42 | return this; 43 | } 44 | 45 | /** 46 | * 自己服务器支付回调地址 47 | */ 48 | public AliInfo notifyUrl(String notify_url) { 49 | this.notify_url = notify_url; 50 | return this; 51 | } 52 | 53 | /** 54 | * 支付宝窗口显示的订单信息:默认为 "订单-实际订单号",'-实际订单号'为固定值 55 | * 这里可以修改 "订单"这两个字,修改为 "测试订单-实际订单号" 56 | */ 57 | public AliInfo intro(String i) { 58 | this.intro = i; 59 | return this; 60 | } 61 | 62 | public void init() { 63 | AlipayUtil.setAPPID(app_id); 64 | AlipayUtil.setNotifyUrl(notify_url); 65 | AlipayUtil.setRsaPrivate(rsa_private); 66 | if (!TextUtils.isEmpty(intro)) { 67 | AlipayUtil.setIntro(intro); 68 | } 69 | } 70 | } 71 | 72 | } 73 | 74 | public static WXPConfig wxpay() { 75 | return new WXPConfig(); 76 | } 77 | 78 | public static class WXPConfig { 79 | /** 80 | * appid 81 | */ 82 | public WXInfo appId(String appid) { 83 | return new WXInfo(appid); 84 | } 85 | 86 | public class WXInfo { 87 | private String app_id; 88 | 89 | private String mch_id; 90 | private String api_key; 91 | private String notify_url; 92 | private String intro; 93 | 94 | public WXInfo(String appid) { 95 | this.app_id = appid; 96 | } 97 | 98 | /** 99 | * 商户号 100 | */ 101 | public WXInfo mchId(String mch_id) { 102 | this.mch_id = mch_id; 103 | return this; 104 | } 105 | 106 | /** 107 | * API密钥,在商户平台设置 108 | */ 109 | public WXInfo apiKey(String api_key) { 110 | this.api_key = api_key; 111 | return this; 112 | } 113 | 114 | /** 115 | * 自己服务器支付回调地址 116 | */ 117 | public WXInfo notifyUrl(String notify_url) { 118 | this.notify_url = notify_url; 119 | return this; 120 | } 121 | 122 | /** 123 | * 支付宝窗口显示的订单信息:默认为 "订单-实际订单号",'-实际订单号'为固定值 124 | * 这里可以修改 "订单"这两个字,修改为 "测试订单-实际订单号" 125 | */ 126 | public WXInfo intro(String i) { 127 | this.intro = i; 128 | return this; 129 | } 130 | 131 | public void init() { 132 | ParameterConfig.setWxAppId(app_id); 133 | ParameterConfig.setWxMchId(mch_id); 134 | ParameterConfig.setWX_notifyUrl(notify_url); 135 | ParameterConfig.setWxApiKey(api_key); 136 | if (!TextUtils.isEmpty(intro)) { 137 | ParameterConfig.setIntro(intro); 138 | } 139 | 140 | } 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/AlipayUtil.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | import android.os.Handler; 7 | import android.os.Message; 8 | import android.text.TextUtils; 9 | import android.util.Log; 10 | 11 | import com.alipay.sdk.app.PayTask; 12 | import com.zys.paylib.wxpay.ParameterConfig; 13 | 14 | import java.text.SimpleDateFormat; 15 | import java.util.Date; 16 | import java.util.Locale; 17 | import java.util.Map; 18 | import java.util.Random; 19 | 20 | 21 | public class AlipayUtil { 22 | String TAG = "AlipayUtil"; 23 | private static AlipayUtil mUtil; 24 | 25 | private static String APPID = ""; 26 | //商户私钥,pkcs8格式 27 | private static String RSA_PRIVATE = ""; 28 | //测试回调地址 29 | private static String NOTIFY_URL = ""; 30 | private static String intro = "订单-"; 31 | boolean rsa2 = true; 32 | private static final int SDK_PAY_FLAG = 1; 33 | private String OutTradeNo; //商户唯一支付订单号 34 | private static final int SDK_AUTH_FLAG = 2; 35 | 36 | 37 | public static AlipayUtil getInstance() { 38 | if (mUtil == null) { 39 | mUtil = new AlipayUtil(); 40 | } 41 | return mUtil; 42 | } 43 | 44 | private Handler mHandler = new Handler() { 45 | public void handleMessage(Message msg) { 46 | switch (msg.what) { 47 | case SDK_PAY_FLAG: { 48 | @SuppressWarnings("unchecked") 49 | PayResult payResult = new PayResult((Map) msg.obj); 50 | /** 51 | 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。 52 | */ 53 | // 同步返回需要验证的信息 54 | String resultInfo = payResult.getResult(); 55 | String resultStatus = payResult.getResultStatus(); 56 | Log.d(TAG, "resultInfo=" + resultInfo + "---resultStatus=" + resultStatus); 57 | // 判断resultStatus 为9000则代表支付成功 58 | if (TextUtils.equals(resultStatus, "9000")) { 59 | //支付成功 60 | if (callback != null) { 61 | callback.success(OutTradeNo, resultInfo); 62 | } 63 | } else { 64 | //支付失败 65 | if (callback != null) { 66 | callback.fail(resultInfo); 67 | } 68 | } 69 | break; 70 | } 71 | case SDK_AUTH_FLAG: { 72 | @SuppressWarnings("unchecked") 73 | AuthResult authResult = new AuthResult((Map) msg.obj, true); 74 | String resultStatus = authResult.getResultStatus(); 75 | 76 | // 判断resultStatus 为“9000”且result_code 77 | // 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档 78 | if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) { 79 | Log.d(TAG, "授权成功"); 80 | } else { 81 | Log.d(TAG, "授权失败"); 82 | if (callback != null) { 83 | callback.fail("9000-授权失败"); 84 | } 85 | } 86 | break; 87 | } 88 | default: 89 | break; 90 | } 91 | } 92 | 93 | ; 94 | }; 95 | 96 | 97 | public void pay(final Activity activity, String body, String price, AlipayCallBack callback) { 98 | 99 | pay(activity, "", body, price, callback); 100 | } 101 | 102 | public void pay(final Activity activity, String subject_start, String body, String price, 103 | AlipayCallBack callback) { 104 | 105 | if (TextUtils.isEmpty(APPID) || TextUtils.isEmpty(RSA_PRIVATE) || TextUtils.isEmpty(NOTIFY_URL)) { 106 | new AlertDialog.Builder(activity).setTitle("警告").setMessage("需要配置APPID | RSA_PRIVATE|" + 107 | " NOTIFY_URL\n请调用PayConfig进行初始化配置") 108 | .setPositiveButton("确定", new DialogInterface.OnClickListener() { 109 | @Override 110 | public void onClick(DialogInterface dialoginterface, int i) { 111 | } 112 | }).show(); 113 | return; 114 | } 115 | this.OutTradeNo = body; 116 | this.callback = callback; 117 | if (TextUtils.isEmpty(subject_start)) { 118 | subject_start = intro; 119 | } 120 | Map params = OrderInfoUtil.buildOrderParamMap(APPID, body, price, 121 | subject_start + body, NOTIFY_URL, rsa2); 122 | String orderParam = OrderInfoUtil.buildOrderParam(params); 123 | 124 | String privateKey = RSA_PRIVATE; 125 | String sign = OrderInfoUtil.getSign(params, privateKey, rsa2); 126 | Log.d(TAG, "签名:" + sign); 127 | final String orderInfo = orderParam + "&" + sign; 128 | 129 | Runnable payRunnable = new Runnable() { 130 | 131 | @Override 132 | public void run() { 133 | PayTask alipay = new PayTask(activity); 134 | Map result = alipay.payV2(orderInfo, true); 135 | // Log.i("msp", result.toString()); 136 | 137 | Message msg = new Message(); 138 | msg.what = SDK_PAY_FLAG; 139 | msg.obj = result; 140 | mHandler.sendMessage(msg); 141 | } 142 | }; 143 | 144 | Thread payThread = new Thread(payRunnable); 145 | payThread.start(); 146 | 147 | } 148 | 149 | 150 | /** 151 | * get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范) 152 | */ 153 | public String getOutTradeNo() { 154 | SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault()); 155 | Date date = new Date(); 156 | String key = format.format(date); 157 | Random r = new Random(); 158 | key = key + r.nextInt(); 159 | key = key.substring(0, 15); 160 | return key; 161 | } 162 | 163 | /** 164 | * sign the order info. 对订单信息进行签名 165 | * 166 | * @param content 待签名订单信息 167 | */ 168 | public String sign(String content) { 169 | return SignUtils.sign(content, RSA_PRIVATE, false); 170 | } 171 | 172 | /** 173 | * get the sign type we use. 获取签名方式 174 | */ 175 | public String getSignType() { 176 | return "sign_type=\"RSA\""; 177 | } 178 | 179 | private AlipayCallBack callback; 180 | 181 | public interface AlipayCallBack { 182 | /** 183 | * 支付成功 184 | */ 185 | void success(String ordernumber, String resultInfo); 186 | 187 | /** 188 | * 支付失败 189 | */ 190 | void fail(String resultInfo); 191 | 192 | } 193 | 194 | public static String getAPPID() { 195 | return APPID; 196 | } 197 | 198 | public static void setAPPID(String APPID) { 199 | AlipayUtil.APPID = APPID; 200 | } 201 | 202 | public static String getRsaPrivate() { 203 | return RSA_PRIVATE; 204 | } 205 | 206 | public static void setRsaPrivate(String rsaPrivate) { 207 | RSA_PRIVATE = rsaPrivate; 208 | } 209 | 210 | public static String getNotifyUrl() { 211 | return NOTIFY_URL; 212 | } 213 | 214 | public static void setNotifyUrl(String notifyUrl) { 215 | NOTIFY_URL = notifyUrl; 216 | } 217 | 218 | public static String getIntro() { 219 | return intro; 220 | } 221 | 222 | public static void setIntro(String i) { 223 | intro = i; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/AuthResult.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; import android.text.TextUtils; import java.util.Map; public class AuthResult { private String resultStatus; private String result; private String memo; private String resultCode; private String authCode; private String alipayOpenId; public AuthResult(Map rawResult, boolean removeBrackets) { if (rawResult == null) { return; } for (String key : rawResult.keySet()) { if (TextUtils.equals(key, "resultStatus")) { resultStatus = rawResult.get(key); } else if (TextUtils.equals(key, "result")) { result = rawResult.get(key); } else if (TextUtils.equals(key, "memo")) { memo = rawResult.get(key); } } String[] resultValue = result.split("&"); for (String value : resultValue) { if (value.startsWith("alipay_open_id")) { alipayOpenId = removeBrackets(getValue("alipay_open_id=", value), removeBrackets); continue; } if (value.startsWith("auth_code")) { authCode = removeBrackets(getValue("auth_code=", value), removeBrackets); continue; } if (value.startsWith("result_code")) { resultCode = removeBrackets(getValue("result_code=", value), removeBrackets); continue; } } } private String removeBrackets(String str, boolean remove) { if (remove) { if (!TextUtils.isEmpty(str)) { if (str.startsWith("\"")) { str = str.replaceFirst("\"", ""); } if (str.endsWith("\"")) { str = str.substring(0, str.length() - 1); } } } return str; } @Override public String toString() { return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}"; } private String getValue(String header, String data) { return data.substring(header.length(), data.length()); } /** * @return the resultStatus */ public String getResultStatus() { return resultStatus; } /** * @return the memo */ public String getMemo() { return memo; } /** * @return the result */ public String getResult() { return result; } /** * @return the resultCode */ public String getResultCode() { return resultCode; } /** * @return the authCode */ public String getAuthCode() { return authCode; } /** * @return the alipayOpenId */ public String getAlipayOpenId() { return alipayOpenId; } } -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/Base64.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; 2 | 3 | public final class Base64 { 4 | 5 | private static final int BASELENGTH = 128; 6 | private static final int LOOKUPLENGTH = 64; 7 | private static final int TWENTYFOURBITGROUP = 24; 8 | private static final int EIGHTBIT = 8; 9 | private static final int SIXTEENBIT = 16; 10 | private static final int FOURBYTE = 4; 11 | private static final int SIGN = -128; 12 | private static char PAD = '='; 13 | private static byte[] base64Alphabet = new byte[BASELENGTH]; 14 | private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; 15 | 16 | static { 17 | for (int i = 0; i < BASELENGTH; ++i) { 18 | base64Alphabet[i] = -1; 19 | } 20 | for (int i = 'Z'; i >= 'A'; i--) { 21 | base64Alphabet[i] = (byte) (i - 'A'); 22 | } 23 | for (int i = 'z'; i >= 'a'; i--) { 24 | base64Alphabet[i] = (byte) (i - 'a' + 26); 25 | } 26 | 27 | for (int i = '9'; i >= '0'; i--) { 28 | base64Alphabet[i] = (byte) (i - '0' + 52); 29 | } 30 | 31 | base64Alphabet['+'] = 62; 32 | base64Alphabet['/'] = 63; 33 | 34 | for (int i = 0; i <= 25; i++) { 35 | lookUpBase64Alphabet[i] = (char) ('A' + i); 36 | } 37 | 38 | for (int i = 26, j = 0; i <= 51; i++, j++) { 39 | lookUpBase64Alphabet[i] = (char) ('a' + j); 40 | } 41 | 42 | for (int i = 52, j = 0; i <= 61; i++, j++) { 43 | lookUpBase64Alphabet[i] = (char) ('0' + j); 44 | } 45 | lookUpBase64Alphabet[62] = (char) '+'; 46 | lookUpBase64Alphabet[63] = (char) '/'; 47 | 48 | } 49 | 50 | private static boolean isWhiteSpace(char octect) { 51 | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); 52 | } 53 | 54 | private static boolean isPad(char octect) { 55 | return (octect == PAD); 56 | } 57 | 58 | private static boolean isData(char octect) { 59 | return (octect < BASELENGTH && base64Alphabet[octect] != -1); 60 | } 61 | 62 | /** 63 | * Encodes hex octects into Base64 64 | * 65 | * @param binaryData 66 | * Array containing binaryData 67 | * @return Encoded Base64 array 68 | */ 69 | public static String encode(byte[] binaryData) { 70 | 71 | if (binaryData == null) { 72 | return null; 73 | } 74 | 75 | int lengthDataBits = binaryData.length * EIGHTBIT; 76 | if (lengthDataBits == 0) { 77 | return ""; 78 | } 79 | 80 | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 81 | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 82 | int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 83 | : numberTriplets; 84 | char encodedData[] = null; 85 | 86 | encodedData = new char[numberQuartet * 4]; 87 | 88 | byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 89 | 90 | int encodedIndex = 0; 91 | int dataIndex = 0; 92 | 93 | for (int i = 0; i < numberTriplets; i++) { 94 | b1 = binaryData[dataIndex++]; 95 | b2 = binaryData[dataIndex++]; 96 | b3 = binaryData[dataIndex++]; 97 | 98 | l = (byte) (b2 & 0x0f); 99 | k = (byte) (b1 & 0x03); 100 | 101 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) 102 | : (byte) ((b1) >> 2 ^ 0xc0); 103 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) 104 | : (byte) ((b2) >> 4 ^ 0xf0); 105 | byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) 106 | : (byte) ((b3) >> 6 ^ 0xfc); 107 | 108 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 109 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 110 | encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; 111 | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; 112 | } 113 | 114 | // form integral number of 6-bit groups 115 | if (fewerThan24bits == EIGHTBIT) { 116 | b1 = binaryData[dataIndex]; 117 | k = (byte) (b1 & 0x03); 118 | 119 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) 120 | : (byte) ((b1) >> 2 ^ 0xc0); 121 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 122 | encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; 123 | encodedData[encodedIndex++] = PAD; 124 | encodedData[encodedIndex++] = PAD; 125 | } else if (fewerThan24bits == SIXTEENBIT) { 126 | b1 = binaryData[dataIndex]; 127 | b2 = binaryData[dataIndex + 1]; 128 | l = (byte) (b2 & 0x0f); 129 | k = (byte) (b1 & 0x03); 130 | 131 | byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) 132 | : (byte) ((b1) >> 2 ^ 0xc0); 133 | byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) 134 | : (byte) ((b2) >> 4 ^ 0xf0); 135 | 136 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 137 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 138 | encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; 139 | encodedData[encodedIndex++] = PAD; 140 | } 141 | 142 | return new String(encodedData); 143 | } 144 | 145 | /** 146 | * Decodes Base64 data into octects 147 | * 148 | * @param encoded 149 | * string containing Base64 data 150 | * @return Array containind decoded data. 151 | */ 152 | public static byte[] decode(String encoded) { 153 | 154 | if (encoded == null) { 155 | return null; 156 | } 157 | 158 | char[] base64Data = encoded.toCharArray(); 159 | // remove white spaces 160 | int len = removeWhiteSpace(base64Data); 161 | 162 | if (len % FOURBYTE != 0) { 163 | return null;// should be divisible by four 164 | } 165 | 166 | int numberQuadruple = (len / FOURBYTE); 167 | 168 | if (numberQuadruple == 0) { 169 | return new byte[0]; 170 | } 171 | 172 | byte decodedData[] = null; 173 | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; 174 | char d1 = 0, d2 = 0, d3 = 0, d4 = 0; 175 | 176 | int i = 0; 177 | int encodedIndex = 0; 178 | int dataIndex = 0; 179 | decodedData = new byte[(numberQuadruple) * 3]; 180 | 181 | for (; i < numberQuadruple - 1; i++) { 182 | 183 | if (!isData((d1 = base64Data[dataIndex++])) 184 | || !isData((d2 = base64Data[dataIndex++])) 185 | || !isData((d3 = base64Data[dataIndex++])) 186 | || !isData((d4 = base64Data[dataIndex++]))) { 187 | return null; 188 | }// if found "no data" just return null 189 | 190 | b1 = base64Alphabet[d1]; 191 | b2 = base64Alphabet[d2]; 192 | b3 = base64Alphabet[d3]; 193 | b4 = base64Alphabet[d4]; 194 | 195 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 196 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 197 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 198 | } 199 | 200 | if (!isData((d1 = base64Data[dataIndex++])) 201 | || !isData((d2 = base64Data[dataIndex++]))) { 202 | return null;// if found "no data" just return null 203 | } 204 | 205 | b1 = base64Alphabet[d1]; 206 | b2 = base64Alphabet[d2]; 207 | 208 | d3 = base64Data[dataIndex++]; 209 | d4 = base64Data[dataIndex++]; 210 | if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters 211 | if (isPad(d3) && isPad(d4)) { 212 | if ((b2 & 0xf) != 0)// last 4 bits should be zero 213 | { 214 | return null; 215 | } 216 | byte[] tmp = new byte[i * 3 + 1]; 217 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 218 | tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 219 | return tmp; 220 | } else if (!isPad(d3) && isPad(d4)) { 221 | b3 = base64Alphabet[d3]; 222 | if ((b3 & 0x3) != 0)// last 2 bits should be zero 223 | { 224 | return null; 225 | } 226 | byte[] tmp = new byte[i * 3 + 2]; 227 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 228 | tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 229 | tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 230 | return tmp; 231 | } else { 232 | return null; 233 | } 234 | } else { // No PAD e.g 3cQl 235 | b3 = base64Alphabet[d3]; 236 | b4 = base64Alphabet[d4]; 237 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 238 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 239 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 240 | 241 | } 242 | 243 | return decodedData; 244 | } 245 | 246 | /** 247 | * remove WhiteSpace from MIME containing encoded Base64 data. 248 | * 249 | * @param data 250 | * the byte array of base64 data (with WS) 251 | * @return the new length 252 | */ 253 | private static int removeWhiteSpace(char[] data) { 254 | if (data == null) { 255 | return 0; 256 | } 257 | 258 | // count characters that's not whitespace 259 | int newSize = 0; 260 | int len = data.length; 261 | for (int i = 0; i < len; i++) { 262 | if (!isWhiteSpace(data[i])) { 263 | data[newSize++] = data[i]; 264 | } 265 | } 266 | return newSize; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/OrderInfoUtil.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; 2 | 3 | 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.net.URLEncoder; 7 | import java.text.SimpleDateFormat; 8 | import java.util.ArrayList; 9 | import java.util.Calendar; 10 | import java.util.Collections; 11 | import java.util.Date; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Locale; 15 | import java.util.Map; 16 | import java.util.Random; 17 | 18 | 19 | public class OrderInfoUtil { 20 | 21 | /** 22 | * 构造授权参数列表 23 | * 24 | * @param pid 25 | * @param app_id 26 | * @param target_id 27 | * @return 28 | */ 29 | public static Map buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) { 30 | Map keyValues = new HashMap(); 31 | 32 | // 商户签约拿到的app_id,如:2013081700024223 33 | keyValues.put("app_id", app_id); 34 | 35 | // 商户签约拿到的pid,如:2088102123816631 36 | keyValues.put("pid", pid); 37 | 38 | // 服务接口名称, 固定值 39 | keyValues.put("apiname", "com.alipay.account.auth"); 40 | 41 | // 商户类型标识, 固定值 42 | keyValues.put("app_name", "mc"); 43 | 44 | // 业务类型, 固定值 45 | keyValues.put("biz_type", "openservice"); 46 | 47 | // 产品码, 固定值 48 | keyValues.put("product_id", "APP_FAST_LOGIN"); 49 | 50 | // 授权范围, 固定值 51 | keyValues.put("scope", "kuaijie"); 52 | 53 | // 商户唯一标识,如:kkkkk091125 54 | keyValues.put("target_id", target_id); 55 | 56 | // 授权类型, 固定值 57 | keyValues.put("auth_type", "AUTHACCOUNT"); 58 | 59 | // 签名类型 60 | keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA"); 61 | 62 | return keyValues; 63 | } 64 | 65 | /** 66 | * 构造支付订单参数列表 67 | * @param app_id 68 | * @return 69 | */ 70 | public static Map buildOrderParamMap(String app_id,String ordernumber, String price,String subject,String notify_url,boolean rsa2) { 71 | Map keyValues = new HashMap(); 72 | 73 | keyValues.put("app_id", app_id); 74 | 75 | keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"out_trade_no\":\"" + ordernumber + "\"}"); 76 | 77 | keyValues.put("charset", "utf-8"); 78 | keyValues.put("total_amount", price); 79 | keyValues.put("body", ordernumber); 80 | keyValues.put("subject", subject); 81 | 82 | keyValues.put("method", "alipay.trade.app.pay"); 83 | 84 | keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA"); 85 | 86 | keyValues.put("timestamp", getTimeYMDHMS()); 87 | // keyValues.put("timestamp", DatetimeUtil.formatDateTime(new Date())); 88 | keyValues.put("notify_url", notify_url);//回调地址 89 | 90 | keyValues.put("version", "1.0"); 91 | 92 | return keyValues; 93 | } 94 | 95 | /** 96 | * 构造支付订单参数信息 97 | * 98 | * @param map 99 | * 支付订单参数 100 | * @return 101 | */ 102 | public static String buildOrderParam(Map map) { 103 | List keys = new ArrayList(map.keySet()); 104 | 105 | StringBuilder sb = new StringBuilder(); 106 | for (int i = 0; i < keys.size() - 1; i++) { 107 | String key = keys.get(i); 108 | String value = map.get(key); 109 | sb.append(buildKeyValue(key, value, true)); 110 | sb.append("&"); 111 | } 112 | 113 | String tailKey = keys.get(keys.size() - 1); 114 | String tailValue = map.get(tailKey); 115 | sb.append(buildKeyValue(tailKey, tailValue, true)); 116 | 117 | return sb.toString(); 118 | } 119 | 120 | /** 121 | * 拼接键值对 122 | * 123 | * @param key 124 | * @param value 125 | * @param isEncode 126 | * @return 127 | */ 128 | private static String buildKeyValue(String key, String value, boolean isEncode) { 129 | StringBuilder sb = new StringBuilder(); 130 | sb.append(key); 131 | sb.append("="); 132 | if (isEncode) { 133 | try { 134 | sb.append(URLEncoder.encode(value, "UTF-8")); 135 | } catch (UnsupportedEncodingException e) { 136 | sb.append(value); 137 | } 138 | } else { 139 | sb.append(value); 140 | } 141 | return sb.toString(); 142 | } 143 | 144 | /** 145 | * 对支付参数信息进行签名 146 | * 147 | * @param map 148 | * 待签名授权信息 149 | * 150 | * @return 151 | */ 152 | public static String getSign(Map map, String rsaKey, boolean rsa2) { 153 | List keys = new ArrayList(map.keySet()); 154 | // key排序 155 | Collections.sort(keys); 156 | 157 | StringBuilder authInfo = new StringBuilder(); 158 | for (int i = 0; i < keys.size() - 1; i++) { 159 | String key = keys.get(i); 160 | String value = map.get(key); 161 | authInfo.append(buildKeyValue(key, value, false)); 162 | authInfo.append("&"); 163 | } 164 | 165 | String tailKey = keys.get(keys.size() - 1); 166 | String tailValue = map.get(tailKey); 167 | authInfo.append(buildKeyValue(tailKey, tailValue, false)); 168 | 169 | String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2); 170 | String encodedSign = ""; 171 | 172 | try { 173 | encodedSign = URLEncoder.encode(oriSign, "UTF-8"); 174 | } catch (UnsupportedEncodingException e) { 175 | e.printStackTrace(); 176 | } 177 | return "sign=" + encodedSign; 178 | } 179 | 180 | /** 181 | * 要求外部订单号必须唯一。 182 | * @return 183 | */ 184 | private static String getOutTradeNo() { 185 | SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault()); 186 | Date date = new Date(); 187 | String key = format.format(date); 188 | 189 | Random r = new Random(); 190 | key = key + r.nextInt(); 191 | key = key.substring(0, 15); 192 | return key; 193 | } 194 | 195 | 196 | private static String getTimeYMDHMS() { 197 | Calendar c = Calendar.getInstance();// 可以对每个时间域单独修改 198 | 199 | int year = c.get(Calendar.YEAR); 200 | int month = c.get(Calendar.MONTH) + 1; 201 | int date = c.get(Calendar.DATE); 202 | int hour = c.get(Calendar.HOUR_OF_DAY); 203 | int minute = c.get(Calendar.MINUTE); 204 | int second = c.get(Calendar.SECOND); 205 | String monthstr = ""; 206 | String datestr = ""; 207 | String hourstr = ""; 208 | String minutestr = ""; 209 | String secondstr = ""; 210 | if (month < 10) { 211 | monthstr = "0" + month; 212 | } else { 213 | monthstr = month + ""; 214 | } 215 | if (date < 10) { 216 | datestr = "0" + date; 217 | } else { 218 | datestr = date + ""; 219 | } 220 | if (hour < 10) { 221 | hourstr = "0" + hour; 222 | } else { 223 | hourstr = hour + ""; 224 | } 225 | if (minute < 10) { 226 | minutestr = "0" + minute; 227 | } else { 228 | minutestr = minute + ""; 229 | } 230 | if (second < 10) { 231 | secondstr = "0" + second; 232 | } else { 233 | secondstr = second + ""; 234 | } 235 | String time = year + "-" + monthstr + "-" + datestr + " " + hourstr + ":" 236 | + minutestr + ":" + secondstr; 237 | return time; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/PayResult.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; import android.text.TextUtils; import java.util.Map; public class PayResult { private String resultStatus; private String result; private String memo; public PayResult(Map rawResult) { if (rawResult == null) { return; } for (String key : rawResult.keySet()) { if (TextUtils.equals(key, "resultStatus")) { resultStatus = rawResult.get(key); } else if (TextUtils.equals(key, "result")) { result = rawResult.get(key); } else if (TextUtils.equals(key, "memo")) { memo = rawResult.get(key); } } } @Override public String toString() { return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}"; } /** * @return the resultStatus */ public String getResultStatus() { return resultStatus; } /** * @return the memo */ public String getMemo() { return memo; } /** * @return the result */ public String getResult() { return result; } } -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/alipay/SignUtils.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.alipay; 2 | 3 | import android.os.Build; 4 | 5 | import java.security.KeyFactory; 6 | import java.security.PrivateKey; 7 | import java.security.spec.PKCS8EncodedKeySpec; 8 | 9 | public class SignUtils { 10 | 11 | private static final String ALGORITHM = "RSA"; 12 | 13 | private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; 14 | 15 | private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; 16 | 17 | private static final String DEFAULT_CHARSET = "UTF-8"; 18 | 19 | private static String getAlgorithms(boolean rsa2) { 20 | return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS; 21 | } 22 | 23 | public static String sign(String content, String privateKey, boolean rsa2) { 24 | try { 25 | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( 26 | Base64.decode(privateKey)); 27 | KeyFactory keyf; 28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 29 | keyf = KeyFactory.getInstance("RSA"); //适配Android P及以后版本,否则报错NoSuchAlgorithmException 30 | } else { 31 | keyf = KeyFactory.getInstance("RSA", "BC"); 32 | } 33 | PrivateKey priKey = keyf.generatePrivate(priPKCS8); 34 | 35 | java.security.Signature signature = java.security.Signature 36 | .getInstance(getAlgorithms(rsa2)); 37 | 38 | signature.initSign(priKey); 39 | signature.update(content.getBytes(DEFAULT_CHARSET)); 40 | 41 | byte[] signed = signature.sign(); 42 | 43 | return Base64.encode(signed); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } 47 | 48 | return null; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/pay/AliPay.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.pay; 2 | 3 | import android.app.Activity; 4 | 5 | import com.zys.paylib.alipay.AlipayUtil; 6 | 7 | 8 | public class AliPay implements IPay { 9 | @Override 10 | public void pay(Activity activity, String paynumbe, double price, 11 | AlipayUtil.AlipayCallBack callback) { 12 | AlipayUtil.getInstance().pay(activity, paynumbe, price + "", callback); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/pay/IPay.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.pay; 2 | 3 | import android.app.Activity; 4 | 5 | import com.zys.paylib.alipay.AlipayUtil; 6 | 7 | 8 | public interface IPay { 9 | void pay(Activity activity, String paynumbe, double price, AlipayUtil.AlipayCallBack callback); 10 | } 11 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/pay/PayTools.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.pay; 2 | 3 | import android.app.Activity; 4 | import android.support.annotation.NonNull; 5 | import android.text.TextUtils; 6 | 7 | import com.zys.paylib.PayConfig; 8 | import com.zys.paylib.alipay.AlipayUtil; 9 | import com.zys.paylib.wxpay.ParameterConfig; 10 | import com.zys.paylib.wxpay.WXPayInfo; 11 | import com.zys.paylib.wxpay.WXPayUtil; 12 | 13 | 14 | public class PayTools { 15 | // private IPay iPay; 16 | 17 | // public PayTools(IPay iPay) { 18 | // this.iPay = iPay; 19 | // } 20 | // 21 | // public void pay(Activity activity, String paynumbe, double price, 22 | // AlipayUtil.AlipayCallBack callback) { 23 | // this.iPay.pay(activity, paynumbe, price, callback); 24 | // } 25 | 26 | public static AlipayTool aliPay(Activity activity) { 27 | return new AlipayTool(activity); 28 | } 29 | 30 | public static class AlipayTool { 31 | private Activity activity; 32 | private String trade_number; 33 | private String intro; 34 | private double money; 35 | private AlipayUtil.AlipayCallBack callBack; 36 | 37 | 38 | /** 39 | * @param activity activity 40 | */ 41 | public AlipayTool(Activity activity) { 42 | this.activity = activity; 43 | } 44 | 45 | /** 46 | * @param trade_number 三方预支付订单号 47 | */ 48 | public AlipayTool tradeNumber(String trade_number) { 49 | this.trade_number = trade_number; 50 | return this; 51 | } 52 | 53 | /** 54 | * @param intro 支付宝窗口显示的订单信息:默认为 "订单-实际订单号",'-实际订单号'为固定值 55 | * 这里可以修改 "订单-"这两个字,修改为 "测试订单-实际订单号" 56 | * 非必填 57 | */ 58 | public AlipayTool intro(String intro) { 59 | this.intro = intro; 60 | return this; 61 | } 62 | 63 | /** 64 | * @param money 实付金额>=0 65 | **/ 66 | public AlipayTool money(double money) { 67 | this.money = money; 68 | return this; 69 | } 70 | 71 | /** 72 | * @param callBack 支付宝交易结果回调 73 | */ 74 | public void pay(AlipayUtil.AlipayCallBack callBack) { 75 | this.callBack = callBack; 76 | if (null==activity) { 77 | throw new NullPointerException("Activity为空"); 78 | } 79 | if (TextUtils.isEmpty(trade_number)) { 80 | throw new NullPointerException("预支付订单号trade_number为空"); 81 | } 82 | if (money <= 0) { 83 | throw new NullPointerException("支付金额不能小于0"); 84 | } 85 | if (null == callBack) { 86 | throw new NullPointerException("支付回调callBack为空"); 87 | } 88 | AlipayUtil.getInstance().pay(activity, trade_number, intro, money + "", callBack); 89 | } 90 | 91 | } 92 | 93 | public static WXPayTool wxPay(Activity activity) { 94 | return new WXPayTool(activity); 95 | } 96 | 97 | public static class WXPayTool { 98 | private Activity activity; 99 | private String trade_number; 100 | private String intro; 101 | private double money; 102 | 103 | /** 104 | * @param activity activity 105 | */ 106 | public WXPayTool(Activity activity) { 107 | this.activity = activity; 108 | } 109 | 110 | /** 111 | * @param trade_number 三方预支付订单号 112 | */ 113 | public WXPayTool tradeNumber(String trade_number) { 114 | this.trade_number = trade_number; 115 | return this; 116 | } 117 | 118 | /** 119 | * @param intro 支付宝窗口显示的订单信息:默认为 "订单-实际订单号",'-实际订单号'为固定值 120 | * 这里可以修改 "订单-"这两个字,修改为 "测试订单-实际订单号" 121 | * 非必填 122 | */ 123 | public WXPayTool intro(String intro) { 124 | this.intro = intro; 125 | return this; 126 | } 127 | 128 | /** 129 | * @param money 实付金额>=0 130 | */ 131 | public WXPayTool money(double money) { 132 | this.money = money; 133 | return this; 134 | } 135 | 136 | public void pay() { 137 | if (null == activity) { 138 | throw new NullPointerException("Activity为空"); 139 | } 140 | if (TextUtils.isEmpty(trade_number)) { 141 | throw new NullPointerException("预支付订单号trade_number为空"); 142 | } 143 | if (money <= 0) { 144 | throw new NullPointerException("支付金额不能小于0"); 145 | } 146 | if (TextUtils.isEmpty(intro)) { 147 | new WXPayUtil(activity, new WXPayInfo(ParameterConfig.getIntro(), money), 148 | trade_number); 149 | } else { 150 | new WXPayUtil(activity, new WXPayInfo(intro, money), trade_number); 151 | } 152 | } 153 | } 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/pay/WxPay.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.pay; 2 | 3 | import android.app.Activity; 4 | 5 | import com.zys.paylib.alipay.AlipayUtil; 6 | import com.zys.paylib.wxpay.ParameterConfig; 7 | import com.zys.paylib.wxpay.WXPayInfo; 8 | import com.zys.paylib.wxpay.WXPayUtil; 9 | 10 | 11 | public class WxPay implements IPay { 12 | 13 | @Override 14 | public void pay(Activity activity, String paynumbe, double price, AlipayUtil.AlipayCallBack callback) { 15 | new WXPayUtil(activity, new WXPayInfo(ParameterConfig.getIntro(), price), paynumbe); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/wxpay/ParameterConfig.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.wxpay; 2 | 3 | 4 | 5 | public class ParameterConfig { 6 | // appid 7 | private static String WX_APP_ID = ""; 8 | // 商户号 9 | private static String WX_MCH_ID = ""; 10 | // API密钥,在商户平台设置 11 | private static String WX_API_KEY = ""; 12 | //自己服务器回调地址 13 | private static String WX_notifyUrl = ""; 14 | private static String intro = "订单-"; 15 | 16 | public static String getWxAppId() { 17 | return WX_APP_ID; 18 | } 19 | 20 | public static void setWxAppId(String wxAppId) { 21 | WX_APP_ID = wxAppId; 22 | } 23 | 24 | public static String getWxMchId() { 25 | return WX_MCH_ID; 26 | } 27 | 28 | public static void setWxMchId(String wxMchId) { 29 | WX_MCH_ID = wxMchId; 30 | } 31 | 32 | public static String getWxApiKey() { 33 | return WX_API_KEY; 34 | } 35 | 36 | public static void setWxApiKey(String wxApiKey) { 37 | WX_API_KEY = wxApiKey; 38 | } 39 | 40 | public static String getWX_notifyUrl() { 41 | return WX_notifyUrl; 42 | } 43 | 44 | public static void setWX_notifyUrl(String WX_notifyUrl) { 45 | ParameterConfig.WX_notifyUrl = WX_notifyUrl; 46 | } 47 | 48 | public static String getIntro() { 49 | return intro; 50 | } 51 | 52 | public static void setIntro(String i) { 53 | intro = i; 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/wxpay/WXPayInfo.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.wxpay; 2 | 3 | import java.io.Serializable; 4 | 5 | 6 | public class WXPayInfo implements Serializable { 7 | private String productname; 8 | private double totalamount; 9 | 10 | public WXPayInfo(String productname, double totalamount) { 11 | this.productname = productname; 12 | this.totalamount = totalamount; 13 | } 14 | 15 | public String getProductname() { 16 | return productname; 17 | } 18 | 19 | public void setProductname(String productname) { 20 | this.productname = productname; 21 | } 22 | 23 | public double getTotalamount() { 24 | return totalamount; 25 | } 26 | 27 | public void setTotalamount(double totalamount) { 28 | this.totalamount = totalamount; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /paylib/src/main/java/com/zys/paylib/wxpay/WXPayUtil.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib.wxpay; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.app.ProgressDialog; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.os.AsyncTask; 9 | import android.text.TextUtils; 10 | import android.util.Log; 11 | import android.util.Xml; 12 | import android.widget.Toast; 13 | 14 | import com.tencent.mm.opensdk.modelpay.PayReq; 15 | import com.tencent.mm.opensdk.openapi.IWXAPI; 16 | import com.tencent.mm.opensdk.openapi.WXAPIFactory; 17 | 18 | import org.apache.http.HttpResponse; 19 | import org.apache.http.HttpStatus; 20 | import org.apache.http.HttpVersion; 21 | import org.apache.http.NameValuePair; 22 | import org.apache.http.client.HttpClient; 23 | import org.apache.http.client.methods.HttpPost; 24 | import org.apache.http.conn.ClientConnectionManager; 25 | import org.apache.http.conn.scheme.PlainSocketFactory; 26 | import org.apache.http.conn.scheme.Scheme; 27 | import org.apache.http.conn.scheme.SchemeRegistry; 28 | import org.apache.http.conn.ssl.SSLSocketFactory; 29 | import org.apache.http.conn.util.InetAddressUtils; 30 | import org.apache.http.entity.StringEntity; 31 | import org.apache.http.impl.client.DefaultHttpClient; 32 | import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 33 | import org.apache.http.message.BasicNameValuePair; 34 | import org.apache.http.params.BasicHttpParams; 35 | import org.apache.http.params.HttpParams; 36 | import org.apache.http.params.HttpProtocolParams; 37 | import org.apache.http.protocol.HTTP; 38 | import org.apache.http.util.EntityUtils; 39 | import org.xmlpull.v1.XmlPullParser; 40 | 41 | import java.io.IOException; 42 | import java.io.StringReader; 43 | import java.net.InetAddress; 44 | import java.net.NetworkInterface; 45 | import java.net.Socket; 46 | import java.net.SocketException; 47 | import java.net.UnknownHostException; 48 | import java.security.KeyManagementException; 49 | import java.security.KeyStore; 50 | import java.security.KeyStoreException; 51 | import java.security.MessageDigest; 52 | import java.security.NoSuchAlgorithmException; 53 | import java.security.UnrecoverableKeyException; 54 | import java.security.cert.X509Certificate; 55 | import java.util.Enumeration; 56 | import java.util.HashMap; 57 | import java.util.LinkedList; 58 | import java.util.List; 59 | import java.util.Map; 60 | import java.util.Random; 61 | 62 | import javax.net.ssl.SSLContext; 63 | import javax.net.ssl.TrustManager; 64 | import javax.net.ssl.X509TrustManager; 65 | 66 | 67 | 68 | public class WXPayUtil { 69 | private IWXAPI api; 70 | private WXPayInfo order; 71 | private PayReq req; 72 | private Map resultunifiedorder; 73 | private Context context; 74 | private String tradenumber; 75 | 76 | public WXPayUtil(Context mcontext, WXPayInfo order, String tradenumber){//初始化微信支付 77 | this.order=order; 78 | this.context=mcontext; 79 | this.tradenumber = tradenumber; 80 | if (TextUtils.isEmpty(ParameterConfig.getWxAppId()) || TextUtils.isEmpty(ParameterConfig.getWxMchId()) || TextUtils.isEmpty(ParameterConfig.getWxApiKey())|| TextUtils.isEmpty(ParameterConfig.getWX_notifyUrl())) { 81 | new AlertDialog.Builder(context).setTitle("警告").setMessage("需要配置WX_APP_ID | WX_MCH_ID| WX_API_KEY| WX_NOTIFY_URL\n请调用PayConfig进行初始化配置") 82 | .setPositiveButton("确定", new DialogInterface.OnClickListener() { 83 | @Override 84 | public void onClick(DialogInterface dialoginterface, int i) { 85 | } 86 | }).show(); 87 | return; 88 | } 89 | 90 | api = WXAPIFactory.createWXAPI(context, null); 91 | api.registerApp(ParameterConfig.getWxAppId()); 92 | boolean isWXAppInstalled=api.isWXAppInstalled(); 93 | if (!isWXAppInstalled){ 94 | Toast.makeText(mcontext,"未安装微信,请先安装微信!", Toast.LENGTH_SHORT).show(); 95 | return ; 96 | } 97 | req = new PayReq(); 98 | //生成prepay_id 99 | GetPrepayIdTask getPrepayId = new GetPrepayIdTask(); 100 | getPrepayId.execute(); 101 | } 102 | 103 | 104 | /** 105 | * 用于获取 106 | * @author 95 107 | * 108 | */ 109 | private class GetPrepayIdTask extends AsyncTask> { 110 | 111 | private ProgressDialog dialog; 112 | @Override 113 | protected void onPreExecute() { 114 | dialog = ProgressDialog.show(context, "提示", "正在获取预支付订单..."); 115 | } 116 | 117 | @Override 118 | protected void onPostExecute(Map result) { 119 | if (dialog != null) { 120 | dialog.dismiss(); 121 | } 122 | resultunifiedorder=result; 123 | Log.e("resultunifiedorder",resultunifiedorder.toString()); 124 | genPayReq(); 125 | //sendPayReq(); 126 | } 127 | 128 | @Override 129 | protected void onCancelled() { 130 | super.onCancelled(); 131 | } 132 | 133 | @Override 134 | protected Map doInBackground(Void... params) { 135 | 136 | String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder"); 137 | String entity = genProductArgs(); 138 | 139 | byte[] buf = httpPost(url,entity); 140 | String content = new String(buf); 141 | Map xml=decodeXml(content); 142 | return xml; 143 | } 144 | } 145 | 146 | private void genPayReq() { 147 | 148 | req.appId = ParameterConfig.getWxAppId(); 149 | req.partnerId = ParameterConfig.getWxMchId(); 150 | req.prepayId = resultunifiedorder.get("prepay_id"); 151 | //req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id"); 152 | req.packageValue = "Sign=WXPay"; 153 | req.nonceStr = genNonceStr(); 154 | req.timeStamp = String.valueOf(genTimeStamp()); 155 | 156 | 157 | List signParams = new LinkedList(); 158 | signParams.add(new BasicNameValuePair("appid", req.appId)); 159 | signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); 160 | signParams.add(new BasicNameValuePair("package", req.packageValue)); 161 | signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); 162 | signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); 163 | signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); 164 | 165 | req.sign = genAppSign(signParams); 166 | Log.e("orion", signParams.toString()); 167 | sendPayReq(); 168 | } 169 | private void sendPayReq() { 170 | // api.registerApp(ParameterConfig.getWxAppId()); 171 | api.sendReq(req); 172 | 173 | } 174 | 175 | private String genProductArgs() { 176 | StringBuffer xml = new StringBuffer(); 177 | 178 | try { 179 | String nonceStr = genNonceStr(); 180 | xml.append(""); 181 | List packageParams = new LinkedList(); 182 | packageParams.add(new BasicNameValuePair("appid", ParameterConfig.getWxAppId())); 183 | packageParams.add(new BasicNameValuePair("body", order.getProductname())); 184 | packageParams.add(new BasicNameValuePair("mch_id", ParameterConfig.getWxMchId())); 185 | packageParams.add(new BasicNameValuePair("nonce_str", nonceStr)); 186 | packageParams.add(new BasicNameValuePair("notify_url", ParameterConfig.getWX_notifyUrl())); 187 | packageParams.add(new BasicNameValuePair("out_trade_no",tradenumber));//订单号 188 | packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1")); 189 | packageParams.add(new BasicNameValuePair("total_fee", String.valueOf((int)(order.getTotalamount()*100)+""))); 190 | packageParams.add(new BasicNameValuePair("trade_type", "APP")); 191 | 192 | String sign = genPackageSign(packageParams); 193 | packageParams.add(new BasicNameValuePair("sign", sign)); 194 | String xmlstring =toXml(packageParams); 195 | return new String(xmlstring.toString().getBytes(), "ISO8859-1"); 196 | //return xmlstring; 197 | 198 | } catch (Exception e) { 199 | return null; 200 | } 201 | } 202 | //获取手机IP 203 | public String getLocalHostIp() { 204 | String ipaddress = ""; 205 | try { 206 | Enumeration en = NetworkInterface.getNetworkInterfaces(); 207 | // 遍历所用的网络接口 208 | while (en.hasMoreElements()) { 209 | NetworkInterface nif = en.nextElement();// 得到每一个网络接口绑定的所有ip 210 | Enumeration inet = nif.getInetAddresses(); 211 | // 遍历每一个接口绑定的所有ip 212 | while (inet.hasMoreElements()) { 213 | InetAddress ip = inet.nextElement(); 214 | if (!ip.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ip.getHostAddress())) { 215 | return ip.getHostAddress(); 216 | } 217 | } 218 | } 219 | } 220 | catch (SocketException e) { 221 | Log.e("feige", "获取本地ip地址失败"); 222 | e.printStackTrace(); 223 | } 224 | return ipaddress; 225 | } 226 | 227 | private String genAppSign(List params) { 228 | StringBuilder sb = new StringBuilder(); 229 | 230 | for (int i = 0; i < params.size(); i++) { 231 | sb.append(params.get(i).getName()); 232 | sb.append('='); 233 | sb.append(params.get(i).getValue()); 234 | sb.append('&'); 235 | } 236 | sb.append("key="); 237 | sb.append(ParameterConfig.getWxApiKey()); 238 | 239 | 240 | String appSign = getMessageDigest(sb.toString().getBytes()); 241 | Log.e("orion",appSign); 242 | return appSign; 243 | } 244 | 245 | 246 | private static class SSLSocketFactoryEx extends SSLSocketFactory { 247 | 248 | SSLContext sslContext = SSLContext.getInstance("TLS"); 249 | 250 | public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { 251 | super(truststore); 252 | 253 | TrustManager tm = new X509TrustManager() { 254 | 255 | @Override 256 | public X509Certificate[] getAcceptedIssuers() { 257 | return null; 258 | } 259 | 260 | @Override 261 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { 262 | } 263 | 264 | @Override 265 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { 266 | } 267 | }; 268 | 269 | sslContext.init(null, new TrustManager[] { tm }, null); 270 | } 271 | 272 | @Override 273 | public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { 274 | return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); 275 | } 276 | 277 | @Override 278 | public Socket createSocket() throws IOException { 279 | return sslContext.getSocketFactory().createSocket(); 280 | } 281 | } 282 | public static byte[] httpPost(String url, String entity) { 283 | if (url == null || url.length() == 0) { 284 | return null; 285 | } 286 | 287 | HttpClient httpClient = getNewHttpClient(); 288 | 289 | HttpPost httpPost = new HttpPost(url); 290 | 291 | try { 292 | httpPost.setEntity(new StringEntity(entity)); 293 | httpPost.setHeader("Accept", "application/json"); 294 | httpPost.setHeader("Content-type", "application/json"); 295 | 296 | HttpResponse resp = httpClient.execute(httpPost); 297 | if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 298 | return null; 299 | } 300 | 301 | return EntityUtils.toByteArray(resp.getEntity()); 302 | } catch (Exception e) { 303 | e.printStackTrace(); 304 | Log.e("orion--------","报错了"); 305 | return null; 306 | } 307 | } 308 | 309 | private static HttpClient getNewHttpClient() { 310 | try { 311 | KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 312 | trustStore.load(null, null); 313 | 314 | SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); 315 | sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 316 | 317 | HttpParams params = new BasicHttpParams(); 318 | HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 319 | HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); 320 | 321 | SchemeRegistry registry = new SchemeRegistry(); 322 | registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 323 | registry.register(new Scheme("https", sf, 443)); 324 | 325 | ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); 326 | 327 | return new DefaultHttpClient(ccm, params); 328 | } catch (Exception e) { 329 | return new DefaultHttpClient(); 330 | } 331 | } 332 | 333 | 334 | private String genOutTradNo() { 335 | Random random = new Random(); 336 | return getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); 337 | } 338 | 339 | public Map decodeXml(String content) { 340 | 341 | try { 342 | Map xml = new HashMap(); 343 | XmlPullParser parser = Xml.newPullParser(); 344 | parser.setInput(new StringReader(content)); 345 | int event = parser.getEventType(); 346 | while (event != XmlPullParser.END_DOCUMENT) { 347 | 348 | String nodeName=parser.getName(); 349 | switch (event) { 350 | case XmlPullParser.START_DOCUMENT: 351 | 352 | break; 353 | case XmlPullParser.START_TAG: 354 | 355 | if("xml".equals(nodeName)==false){ 356 | //实例化student对象 357 | xml.put(nodeName,parser.nextText()); 358 | } 359 | break; 360 | case XmlPullParser.END_TAG: 361 | break; 362 | } 363 | event = parser.next(); 364 | } 365 | 366 | return xml; 367 | } catch (Exception e) { 368 | Log.e("orion",e.toString()); 369 | } 370 | return null; 371 | 372 | } 373 | 374 | private String genNonceStr() { 375 | Random random = new Random(); 376 | return getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); 377 | } 378 | 379 | private long genTimeStamp() { 380 | return System.currentTimeMillis() / 1000; 381 | } 382 | 383 | public String getMessageDigest(byte[] buffer) { 384 | char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 385 | try { 386 | MessageDigest mdTemp = MessageDigest.getInstance("MD5"); 387 | mdTemp.update(buffer); 388 | byte[] md = mdTemp.digest(); 389 | int j = md.length; 390 | char str[] = new char[j * 2]; 391 | int k = 0; 392 | for (int i = 0; i < j; i++) { 393 | byte byte0 = md[i]; 394 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 395 | str[k++] = hexDigits[byte0 & 0xf]; 396 | } 397 | return new String(str); 398 | } catch (Exception e) { 399 | return null; 400 | } 401 | } 402 | 403 | /** 404 | 生成签名 405 | */ 406 | 407 | private String genPackageSign(List params) { 408 | StringBuilder sb = new StringBuilder(); 409 | 410 | for (int i = 0; i < params.size(); i++) { 411 | sb.append(params.get(i).getName()); 412 | sb.append('='); 413 | sb.append(params.get(i).getValue()); 414 | sb.append('&'); 415 | } 416 | sb.append("key="); 417 | sb.append(ParameterConfig.getWxApiKey()); 418 | 419 | 420 | String packageSign = getMessageDigest(sb.toString().getBytes()).toUpperCase(); 421 | Log.e("orion",packageSign); 422 | return packageSign; 423 | } 424 | 425 | private String toXml(List params) { 426 | StringBuilder sb = new StringBuilder(); 427 | sb.append(""); 428 | for (int i = 0; i < params.size(); i++) { 429 | sb.append("<"+params.get(i).getName()+">"); 430 | 431 | 432 | sb.append(params.get(i).getValue()); 433 | sb.append(""); 434 | } 435 | sb.append(""); 436 | 437 | Log.e("orion",sb.toString()); 438 | return sb.toString(); 439 | } 440 | } 441 | -------------------------------------------------------------------------------- /paylib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | paylib 3 | 4 | -------------------------------------------------------------------------------- /paylib/src/test/java/com/zys/paylib/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zys.paylib; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.zys.zyspay.demo" 7 | minSdkVersion 19 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:28.0.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 28 | implementation project(':paylib') 29 | } 30 | -------------------------------------------------------------------------------- /sample/class_files.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equalzys/PayLib/613b325496b6f03843be57ba8f817f3a9feab226/sample/class_files.txt -------------------------------------------------------------------------------- /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 D:\AndroidSDK/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 | -optimizationpasses 5 28 | 29 | #包明不混合大小写 30 | -dontusemixedcaseclassnames 31 | 32 | #不去忽略非公共的库类 33 | -dontskipnonpubliclibraryclasses 34 | 35 | #优化 不优化输入的类文件 36 | -dontoptimize 37 | 38 | #预校验 39 | -dontpreverify 40 | 41 | #混淆时是否记录日志 42 | -verbose 43 | 44 | # 混淆时所采用的算法 45 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 46 | 47 | #保护注解 48 | -keepattributes *Annotation* 49 | 50 | # 保持哪些类不被混淆 51 | -keep public class * extends android.app.Fragment 52 | -keep public class * extends android.app.Activity 53 | -keep public class * extends android.app.Application 54 | -keep public class * extends android.app.Service 55 | -keep public class * extends android.content.BroadcastReceiver 56 | -keep public class * extends android.content.ContentProvider 57 | -keep public class * extends android.app.backup.BackupAgentHelper 58 | -keep public class * extends android.preference.Preference 59 | -keep public class com.android.vending.licensing.ILicensingService 60 | #如果有引用v4包可以添加下面这行 61 | -keep public class * extends android.support.v4.app.Fragment 62 | 63 | ##忽略警告 64 | #-dontwarn 65 | -ignorewarnings 66 | ##记录生成的日志数据,gradle build时在本项目根目录输出## 67 | #apk 包内所有 class 的内部结构 68 | -dump proguard/class_files.txt 69 | #未混淆的类和成员 70 | -printseeds proguard/seeds.txt 71 | #列出从 apk 中删除的代码 72 | -printusage proguard/unused.txt 73 | #混淆前后的映射 74 | -printmapping proguard/mapping.txt 75 | ########记录生成的日志数据,gradle build时 在本项目根目录输出-end###### 76 | 77 | #如果引用了v4或者v7包 78 | -dontwarn android.support.** 79 | 80 | ####混淆保护自己项目的部分代码以及引用的第三方jar包library-end#### 81 | 82 | 83 | 84 | #保持 native 方法不被混淆 85 | -keepclasseswithmembernames class * { 86 | native ; 87 | } 88 | 89 | #保持自定义控件类不被混淆 90 | -keepclasseswithmembers class * { 91 | public (android.content.Context, android.util.AttributeSet); 92 | } 93 | 94 | #保持自定义控件类不被混淆 95 | -keepclassmembers class * extends android.app.Activity { 96 | public void *(android.view.View); 97 | } 98 | 99 | -keep public class * extends android.view.View { 100 | public (android.content.Context); 101 | public (android.content.Context, android.util.AttributeSet); 102 | public (android.content.Context, android.util.AttributeSet, int); 103 | public void set*(...); 104 | } 105 | 106 | #保持 Parcelable 不被混淆 107 | -keep class * implements android.os.Parcelable { 108 | public static final android.os.Parcelable$Creator *; 109 | } 110 | 111 | #保持 Serializable 不被混淆 112 | -keepnames class * implements java.io.Serializable 113 | 114 | #保持 Serializable 不被混淆并且enum 类也不被混淆 115 | -keepclassmembers class * implements java.io.Serializable { 116 | static final long serialVersionUID; 117 | private static final java.io.ObjectStreamField[] serialPersistentFields; 118 | !static !transient ; 119 | !private ; 120 | !private ; 121 | private void writeObject(java.io.ObjectOutputStream); 122 | private void readObject(java.io.ObjectInputStream); 123 | java.lang.Object writeReplace(); 124 | java.lang.Object readResolve(); 125 | } 126 | 127 | #保持枚举 enum 类不被混淆 128 | -keepclassmembers enum * { 129 | public static **[] values(); 130 | public static ** valueOf(java.lang.String); 131 | } 132 | 133 | -keepclassmembers class * { 134 | public void *ButtonClicked(android.view.View); 135 | } 136 | 137 | #不混淆资源类 138 | -keepclassmembers class **.R$* { 139 | public static ; 140 | } 141 | 142 | #避免混淆泛型 如果混淆报错建议关掉 143 | #-keepattributes Signature 144 | 145 | #移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用,另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制 146 | -assumenosideeffects class android.util.Log { 147 | public static *** v(...); 148 | public static *** i(...); 149 | public static *** d(...); 150 | public static *** w(...); 151 | public static *** e(...); 152 | } 153 | 154 | ############################################################################################# 155 | ######################## 以上通用 ################################## 156 | ############################################################################################# 157 | #gson 158 | #如果用用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错。 159 | -keepattributes Signature 160 | # Gson specific classes 161 | -keep class sun.misc.Unsafe { *; } 162 | # Application classes that will be serialized/deserialized over Gson 163 | -keep class com.google.gson.** { *; } 164 | -keep class com.google.gson.stream.** { *; } 165 | 166 | #极光 167 | -dontoptimize 168 | -dontpreverify 169 | 170 | -dontwarn cn.jpush.** 171 | -keep class cn.jpush.** { *; } 172 | 173 | -dontwarn cn.jiguang.** 174 | -keep class cn.jiguang.** { *; } 175 | 176 | #友盟 177 | -dontusemixedcaseclassnames 178 | -dontshrink 179 | -dontoptimize 180 | -dontwarn com.google.android.maps.** 181 | -dontwarn android.webkit.WebView 182 | -keep public class javax.** 183 | -keep public class android.webkit.** 184 | -dontwarn android.support.v4.** 185 | -keep enum com.facebook.** 186 | -keepattributes Exceptions,InnerClasses,Signature 187 | -keepattributes *Annotation* 188 | -keepattributes SourceFile,LineNumberTable 189 | 190 | -keep public interface com.facebook.** 191 | -keep public interface com.tencent.** 192 | -keep public interface com.umeng.socialize.** 193 | -keep public interface com.umeng.socialize.sensor.** 194 | -keep public interface com.umeng.scrshot.** 195 | -keep class com.android.dingtalk.share.ddsharemodule.** { *; } 196 | -keep public class com.umeng.socialize.* {*;} 197 | 198 | 199 | -keep class com.tencent.** {*;} 200 | -dontwarn com.tencent.** 201 | -keep public class com.umeng.com.umeng.soexample.R$*{ 202 | public static final int *; 203 | } 204 | -keep public class com.linkedin.android.mobilesdk.R$*{ 205 | public static final int *; 206 | } 207 | -keepclassmembers enum * { 208 | public static **[] values(); 209 | public static ** valueOf(java.lang.String); 210 | } 211 | 212 | -keep class com.tencent.open.TDialog$* 213 | -keep class com.tencent.open.TDialog$* {*;} 214 | -keep class com.tencent.open.PKDialog 215 | -keep class com.tencent.open.PKDialog {*;} 216 | -keep class com.tencent.open.PKDialog$* 217 | -keep class com.tencent.open.PKDialog$* {*;} 218 | 219 | -keep class com.sina.** {*;} 220 | -dontwarn com.sina.** 221 | -keep class com.alipay.share.sdk.** { 222 | *; 223 | } 224 | -keepnames class * implements android.os.Parcelable { 225 | public static final ** CREATOR; 226 | } 227 | 228 | -keep class com.linkedin.** { *; } 229 | -keepattributes Signature 230 | 231 | #支付宝 232 | #-libraryjars libs/alipaysingle-20170510.jar 233 | 234 | -keep class com.alipay.android.app.IAlixPay{*;} 235 | -keep class com.alipay.android.app.IAlixPay$Stub{*;} 236 | -keep class com.alipay.android.app.IRemoteServiceCallback{*;} 237 | -keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;} 238 | -keep class com.alipay.sdk.app.PayTask{ public *;} 239 | -keep class com.alipay.sdk.app.AuthTask{ public *;} 240 | 241 | -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep class com.tencent.android.tpush.** {* ;} 242 | -keep class com.tencent.mid.** {* ;} 243 | 244 | -keep class butterknife.** { *; } 245 | -dontwarn butterknife.internal.** 246 | -keep class **$$ViewBinder { *; } 247 | 248 | -keepclasseswithmembernames class * { 249 | @butterknife.* ; 250 | } 251 | 252 | -keepclasseswithmembernames class * { 253 | @butterknife.* ; 254 | } 255 | -keep class com.baidu.** {*;} 256 | -keep class vi.com.** {*;} 257 | -dontwarn com.baidu.** 258 | 259 | -dontwarn com.yanzhenjie.album.** 260 | -keep class com.yanzhenjie.album.**{*;} 261 | 262 | -keep class cn.finalteam.galleryfinal.widget.*{*;} 263 | -keep class cn.finalteam.galleryfinal.widget.crop.*{*;} 264 | -keep class cn.finalteam.galleryfinal.widget.zoonview.*{*;} 265 | 266 | -keep class cn.sharesdk.**{*;} 267 | -keep class com.sina.**{*;} 268 | -keep class **.R$* {*;} 269 | -keep class **.R{*;} 270 | -keep class com.mob.**{*;} 271 | -dontwarn com.mob.** 272 | -dontwarn cn.sharesdk.** 273 | -dontwarn **.R$* 274 | 275 | -keep class com.qiyukf.** {*;} 276 | -dontwarn com.qiyukf.** 277 | -keep public class com.alibaba.android.arouter.routes.**{*;} 278 | -keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;} 279 | 280 | -dontwarn com.google.** 281 | 282 | -dontwarn com.android.** 283 | 284 | 285 | #如果你使用全文检索插件,需要加入 286 | -dontwarn org.apache.lucene.** 287 | -keep class org.apache.lucene.** {*;} 288 | 289 | 290 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/zys/zyspay/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zys.zyspay.demo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zys.zyspay.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sample/src/main/java/com/zys/zyspay/demo/App.java: -------------------------------------------------------------------------------- 1 | package com.zys.zyspay.demo; 2 | 3 | import android.app.Application; 4 | 5 | import com.zys.paylib.PayConfig; 6 | 7 | public class App extends Application { 8 | 9 | private final String RSA_PRIVATE = "MIIEv****很长很长******stnwxntWIrgr/fvtXuyXSfI="; 10 | 11 | 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | 16 | //用到支付宝的时候配置 17 | PayConfig.alipay() 18 | .appId("2017******3659") 19 | .rsa(RSA_PRIVATE) 20 | .notifyUrl("http://www.xx**xx.com/api/trade/notify/alipay") 21 | .intro("支付宝订单-")//非必填 22 | .init(); 23 | 24 | //用到微信的时候配置 25 | PayConfig.wxpay() 26 | .appId("wx62*******87") 27 | .mchId("15******1") 28 | .apiKey("Rd88G******I0ci406") 29 | .notifyUrl("http://www.xx**xx.com/api/trade/notify/wxpay") 30 | .intro("微信订单-")//非必填 31 | .init(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sample/src/main/java/com/zys/zyspay/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zys.zyspay.demo; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import com.zys.paylib.alipay.AlipayUtil; 7 | import com.zys.paylib.pay.AliPay; 8 | import com.zys.paylib.pay.PayTools; 9 | import com.zys.paylib.pay.WxPay; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | 18 | } 19 | 20 | 21 | private void toAliPay() { 22 | String tradenumber = "这里是实际交易订单号-服务器返回"; 23 | double money=0.01;//需要支付的金额 24 | PayTools.aliPay(this) 25 | .tradeNumber(tradenumber) 26 | .money(money) 27 | .intro("订单-")//(非必填) 28 | .pay(new AlipayUtil.AlipayCallBack() { 29 | @Override 30 | public void success(String ordernumber, String resultInfo) { 31 | 32 | } 33 | 34 | @Override 35 | public void fail(String resultInfo) { 36 | 37 | } 38 | 39 | }); 40 | 41 | } 42 | 43 | private void toWXPay() { 44 | String tradenumber = "这里是实际交易订单号-服务器返回"; 45 | double money=0.01;//需要支付的金额 46 | PayTools.wxPay(this) 47 | .tradeNumber(tradenumber) 48 | .intro("订单-")//(非必填) 49 | .money(money) 50 | .pay();//支付回调在WXPayEntryActivity 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sample/src/main/java/com/zys/zyspay/demo/wxapi/WXPayEntryActivity.java: -------------------------------------------------------------------------------- 1 | package com.zys.zyspay.demo.wxapi; 2 | 3 | 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.widget.Toast; 9 | 10 | import com.tencent.mm.opensdk.constants.ConstantsAPI; 11 | import com.tencent.mm.opensdk.modelbase.BaseReq; 12 | import com.tencent.mm.opensdk.modelbase.BaseResp; 13 | import com.tencent.mm.opensdk.openapi.IWXAPI; 14 | import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; 15 | import com.tencent.mm.opensdk.openapi.WXAPIFactory; 16 | import com.zys.paylib.wxpay.ParameterConfig; 17 | import com.zys.zyspay.demo.R; 18 | 19 | 20 | public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { 21 | private IWXAPI api; 22 | 23 | // private TextView reulttv; 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | try { 27 | super.onCreate(savedInstanceState); 28 | } catch (Exception e) { 29 | e.printStackTrace(); 30 | } 31 | setContentView(R.layout.wx_pay_result); 32 | api = WXAPIFactory.createWXAPI(this, ParameterConfig.getWxAppId()); 33 | api.handleIntent(getIntent(), this); 34 | } 35 | 36 | @Override 37 | protected void onNewIntent(Intent intent) { 38 | super.onNewIntent(intent); 39 | setIntent(intent); 40 | api.handleIntent(intent, this); 41 | } 42 | 43 | @Override 44 | public void onReq(BaseReq req) { 45 | 46 | } 47 | 48 | @Override 49 | public void onResp(BaseResp resp) { 50 | if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { 51 | Log.e("WXPayEntryActivity",resp.toString()); 52 | int code = resp.errCode; 53 | switch (code) { 54 | case 0: 55 | Toast.makeText(this, "支付成功", Toast.LENGTH_SHORT).show(); 56 | //可以使用EventBus通知支付成功 57 | // EventBusUtil.post(EventConstant.WXPAYORDERSUCCESS); 58 | finish(); 59 | break; 60 | case -1: 61 | Toast.makeText(this, "支付失败", Toast.LENGTH_SHORT).show(); 62 | finish(); 63 | break; 64 | case -2: 65 | Toast.makeText(this, "支付取消", Toast.LENGTH_SHORT).show(); 66 | finish(); 67 | break; 68 | default: 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 |