├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── README_CN.md ├── README_EN.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── github │ │ └── mayubao │ │ └── android_pay │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── mayubao │ │ │ └── android_pay │ │ │ ├── MainActivity.java │ │ │ ├── PayAliPayActivity.java │ │ │ ├── PayWechatActivity.java │ │ │ └── TestOnlineActivity.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_pay_ali_pay.xml │ │ ├── activity_pay_wechat.xml │ │ ├── activity_test_online.xml │ │ ├── content_main.xml │ │ ├── content_pay_ali_pay.xml │ │ ├── content_pay_wechat.xml │ │ └── content_test_online.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── io │ └── github │ └── mayubao │ └── android_pay │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pay-library ├── .gitignore ├── build.gradle ├── libs │ ├── alipaySDK-20150818.jar │ └── libammsdk.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── github │ │ └── mayubao │ │ └── pay_library │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── mayubao │ │ │ └── pay_library │ │ │ ├── AliPayAPI.java │ │ │ ├── AliPayReq.java │ │ │ ├── AliPayReq2.java │ │ │ ├── MainActivity.java │ │ │ ├── PayAPI.java │ │ │ ├── WechatPayAPI.java │ │ │ ├── WechatPayReq.java │ │ │ └── alipay │ │ │ ├── Base64.java │ │ │ ├── ExternalFragment.java │ │ │ ├── PayResult.java │ │ │ └── SignUtils.java │ └── res │ │ ├── layout │ │ ├── pay_external.xml │ │ └── pay_main.xml │ │ ├── mipmap-hdpi │ │ ├── msp_demo_title.png │ │ ├── msp_demo_title_bg.png │ │ └── msp_icon.png │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── io │ └── github │ └── mayubao │ └── pay_library │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Android-Pay -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-Pay 2 | [中文](https://github.com/mayubao/Android-Pay/blob/master/README_CN.md) 3 | 4 | A pay library for Android, and which support Wechat pay and Ali pay. 5 | And developer can easily use Wechat pay in two lines of code. 6 | And developer can easily use Ali pay in three lines of code. 7 | 8 | ## Setup 9 | 10 | ### gradle 11 | add these code in the file **build.gradle** as follow: 12 | 13 | ```xml 14 | dependencies { 15 | //add pay library 16 | compile 'io.github.mayubao:pay_library:1.0.1' 17 | } 18 | ``` 19 | 20 | ### maven 21 | 22 | ```xml 23 | 24 | io.github.mayubao 25 | pay_library 26 | 1.0.1 27 | pom 28 | 29 | ``` 30 | 31 | ## Usage 32 | 33 | ### Wechat Pay 34 | 35 | ```java 36 | //1.create request for wechat pay 37 | WechatPayReq wechatPayReq = new WechatPayReq.Builder() 38 | .with(this) //activity instance 39 | .setAppId(appid) //wechat pay AppID 40 | .setPartnerId(partnerid)//wechat pay partner id 41 | .setPrepayId(prepayid)//pre pay id 42 | // .setPackageValue(wechatPayReq.get)//"Sign=WXPay" 43 | .setNonceStr(noncestr) 44 | .setTimeStamp(timestamp)//time stamp 45 | .setSign(sign)//sign 46 | .create(); 47 | //2. send the request with wechat pay 48 | PayAPI.getInstance().sendPayRequest(wechatPayReq); 49 | 50 | 51 | //set the callback for wechat pay 52 | //wechatPayReq.setOnWechatPayListener(new OnWechatPayListener); 53 | 54 | 55 | ``` 56 | 57 | >Notes:WechatPayReq have no method to set the money, because the money info is include in the parameter 'prepayid'. 58 | 59 | ### Ali Pay 60 | 61 | 62 | #### First way(**Not Recommend**, and its partner rsa private key export in the client , it is very dangerous!) 63 | ```java 64 | 65 | //step 1 create config for ali pay 66 | AliPayAPI.Config config = new AliPayAPI.Config.Builder() 67 | .setRsaPrivate(rsa_private) // rsa private key from partner (pkcs8 format) 68 | .setRsaPublic(rsa_public)//ali rsa public key 69 | .setPartner(partner) //set partner 70 | .setSeller(seller) //set partner seller accout 71 | .create(); 72 | 73 | //step 2 create reqeust for ali 74 | AliPayReq aliPayReq = new AliPayReq.Builder() 75 | .with(activity)//Activity instance 76 | .apply(config)// the above custome config 77 | .setOutTradeNo(outTradeNo)//set unique trade no 78 | .setPrice(price)//set price 79 | .setSubject(orderSubject)//set order subject 80 | .setBody(orderBody)//set order detail 81 | .setCallbackUrl(callbackUrl)//set callback for pay reqest 82 | .create()// 83 | .setOnAliPayListener(null);// 84 | 85 | //step 3 send the request for ali pay 86 | PayAPI.getInstance().sendPayRequest(aliPayReq); 87 | 88 | // set the ali pay callback 89 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 90 | 91 | ``` 92 | 93 | #### Second way(**Highly Recommend**) 94 | 95 | ```java 96 | //step 1 create raw ali pay order info 97 | String rawAliOrderInfo = new AliPayReq2.AliOrderInfo() 98 | .setPartner(partner) //set partner 99 | .setSeller(seller) //set partner seller accout 100 | .setOutTradeNo(outTradeNo) //set unique trade no 101 | .setSubject(orderSubject) //set order subject 102 | .setBody(orderBody) //set order detail 103 | .setPrice(price) //set price 104 | .setCallbackUrl(callbackUrl) //set callback for pay reqest 105 | .createOrderInfo(); //create ali pay order info 106 | 107 | 108 | //step 2 get the signed ali pay order info 109 | String signAliOrderInfo = getSignAliOrderInfoFromServer(rawAliOrderInfo); 110 | 111 | //step 3 step 3 send the request for ali pay 112 | AliPayReq2 aliPayReq = new AliPayReq2.Builder() 113 | .with(activity)//Activity instance 114 | .setSignedAliPayOrderInfo(signAliOrderInfo) 115 | .setRawAliPayOrderInfo(rawAliOrderInfo)//set the ali pay order info 116 | .setSignedAliPayOrderInfo(signAliOrderInfo) //set the signed ali pay order info 117 | .create()// 118 | .setOnAliPayListener(null);// 119 | PayAPI.getInstance().sendPayRequest(aliPayReq); 120 | 121 | 122 | //set the ali pay callback 123 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 124 | 125 | ``` 126 | 127 | 128 | ## ISSUE 129 | 130 | ### About Wechat Pay Callback 131 | 132 | 133 | How to do : 134 | 135 | 136 | 1.new folder named 'wxapi' under your project root package 137 | 138 |    2.and create class WXPayEntryActivity under the wxapi 139 | 140 |    3.implements IWXAPIEventHandler interface 141 | 142 | The sample as follow: 143 | 144 | 145 | ```java 146 | 147 | import android.app.Activity; 148 | import android.app.AlertDialog; 149 | import android.content.Intent; 150 | import android.os.Bundle; 151 | import android.util.Log; 152 | import android.widget.Toast; 153 | 154 | import com.tencent.mm.sdk.constants.ConstantsAPI; 155 | import com.tencent.mm.sdk.modelbase.BaseReq; 156 | import com.tencent.mm.sdk.modelbase.BaseResp; 157 | import com.tencent.mm.sdk.openapi.IWXAPI; 158 | import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; 159 | import com.tencent.mm.sdk.openapi.WXAPIFactory; 160 | 161 | public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{ 162 | 163 | private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity"; 164 | 165 | private IWXAPI api; 166 | 167 | //TODO need to replace your APP_ID 168 | private String APP_ID = "wx0xxxxxxxxx"; //need to replace your APP_ID 169 | 170 | @Override 171 | public void onCreate(Bundle savedInstanceState) { 172 | super.onCreate(savedInstanceState); 173 | // setContentView(R.layout.pay_result); 174 | 175 | api = WXAPIFactory.createWXAPI(this, APP_ID); 176 | api.handleIntent(getIntent(), this); 177 | } 178 | 179 | @Override 180 | protected void onNewIntent(Intent intent) { 181 | super.onNewIntent(intent); 182 | setIntent(intent); 183 | api.handleIntent(intent, this); 184 | } 185 | 186 | @Override 187 | public void onReq(BaseReq req) { 188 | } 189 | 190 | @Override 191 | public void onResp(BaseResp resp) { 192 | Log.d(TAG, "onPayFinish, errCode = " + resp.errCode); 193 | 194 | if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { 195 | // AlertDialog.Builder builder = new AlertDialog.Builder(this); 196 | // builder.setTitle(R.string.app_tip); 197 | // builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode))); 198 | // builder.show(); 199 | 200 | //send the wechat pay broadcast receiver,and you should the define wechat pay broadcast receive 201 | 202 | Intent intent = new Intent(); 203 | intent.setAction(WeChatPayReceiver.ACTION_PAY_RESULT); 204 | intent.putExtra("result", resp.errCode); 205 | sendBroadcast(intent); 206 | 207 | finish(); 208 | } 209 | } 210 | } 211 | 212 | ``` 213 | 214 | ## Proguard 215 | 216 | ```xml 217 | 218 | #pay_library 219 | -dontwarn io.github.mayubao.pay_library.** 220 | -keep class io.github.mayubao.pay_library.** {*;} 221 | 222 | #wechat pay 223 | -dontwarn com.tencent.** 224 | -keep class com.tencent.** {*;} 225 | 226 | 227 | #alipay 228 | -dontwarn com.alipay.** 229 | -keep class com.alipay.** {*;} 230 | 231 | -dontwarn com.ta.utdid2.** 232 | -keep class com.ta.utdid2.** {*;} 233 | 234 | -dontwarn com.ut.device.** 235 | -keep class com.ut.device.** {*;} 236 | 237 | -dontwarn org.json.alipay.** 238 | -keep class corg.json.alipay.** {*;} 239 | ``` 240 | 241 | 242 | ## Document 243 | 244 | ### wehcat pay official document 245 | https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 246 | 247 | ### ali pay official document 248 | https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.sdGXaH&treeId=204&articleId=105296&docType=1 249 | 250 | 251 | ## Help 252 | If it is helpful to you, could you buy me a cup of coffee? 253 | 254 | ### Wechat 255 | ![](http://img.blog.csdn.net/20170302140650271) 256 | ### Ali 257 | ![支付宝支付](http://img.blog.csdn.net/20170302140734345) 258 | 259 | 260 | ## Lisence 261 | 262 | Copyright 2017 mayubao 263 | 264 | Licensed under the Apache License, Version 2.0 (the "License"); 265 | you may not use this file except in compliance with the License. 266 | You may obtain a copy of the License at 267 | 268 | http://www.apache.org/licenses/LICENSE-2.0 269 | 270 | Unless required by applicable law or agreed to in writing, software 271 | distributed under the License is distributed on an "AS IS" BASIS, 272 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 273 | See the License for the specific language governing permissions and 274 | limitations under the License. 275 | 276 | 277 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Android-Pay 2 | 支持微信和支付宝两种主流支付的集成库, 两行代码实现微信支付, 三行代码实现支付宝支付 3 | 4 | ## 引入 5 | 6 | ### gradle 7 | 对应的项目中的build.gradle文件添加依赖: 8 | 9 | ```xml 10 | dependencies { 11 | //添加支付库 12 | compile 'io.github.mayubao:pay_library:1.0.1' 13 | } 14 | ``` 15 | 16 | ### maven 17 | 18 | ```xml 19 | 20 | io.github.mayubao 21 | pay_library 22 | 1.0.1 23 | pom 24 | 25 | ``` 26 | 27 | ## 使用 28 | 29 | ### 微信支付使用 30 | 31 | ```java 32 | //1.创建微信支付请求 33 | WechatPayReq wechatPayReq = new WechatPayReq.Builder() 34 | .with(this) //activity实例 35 | .setAppId(appid) //微信支付AppID 36 | .setPartnerId(partnerid)//微信支付商户号 37 | .setPrepayId(prepayid)//预支付码 38 | // .setPackageValue(wechatPayReq.get)//"Sign=WXPay" 39 | .setNonceStr(noncestr) 40 | .setTimeStamp(timestamp)//时间戳 41 | .setSign(sign)//签名 42 | .create(); 43 | //2.发送微信支付请求 44 | PayAPI.getInstance().sendPayRequest(wechatPayReq); 45 | 46 | 47 | //关于微信支付的回调 48 | //wechatPayReq.setOnWechatPayListener(new OnWechatPayListener); 49 | 50 | 51 | ``` 52 | 53 | 54 | 55 | >注意:这里没有金额设置,金额的信息已经包含在预支付码prepayid了。 56 | 57 | ### 支付宝支付使用 58 | 59 | #### 支付宝支付第一种方式(不建议用这种方式,商户私钥暴露在客户端,极其危险,推荐用第二种支付方式) 60 | ```java 61 | 62 | //1.创建支付宝支付配置 63 | AliPayAPI.Config config = new AliPayAPI.Config.Builder() 64 | .setRsaPrivate(rsa_private) //设置私钥 (商户私钥,pkcs8格式) 65 | .setRsaPublic(rsa_public)//设置公钥(// 支付宝公钥) 66 | .setPartner(partner) //设置商户 67 | .setSeller(seller) //设置商户收款账号 68 | .create(); 69 | 70 | //2.创建支付宝支付请求 71 | AliPayReq aliPayReq = new AliPayReq.Builder() 72 | .with(activity)//Activity实例 73 | .apply(config)//支付宝支付通用配置 74 | .setOutTradeNo(outTradeNo)//设置唯一订单号 75 | .setPrice(price)//设置订单价格 76 | .setSubject(orderSubject)//设置订单标题 77 | .setBody(orderBody)//设置订单内容 订单详情 78 | .setCallbackUrl(callbackUrl)//设置回调地址 79 | .create()// 80 | .setOnAliPayListener(null);// 81 | 82 | //3.发送支付宝支付请求 83 | PayAPI.getInstance().sendPayRequest(aliPayReq); 84 | 85 | //关于支付宝支付的回调 86 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 87 | 88 | ``` 89 | 90 | #### 支付宝支付第二种方式(**强烈推荐**) 91 | 92 | ```java 93 | //1.创建支付宝支付订单的信息 94 | String rawAliOrderInfo = new AliPayReq2.AliOrderInfo() 95 | .setPartner(partner) //商户PID || 签约合作者身份ID 96 | .setSeller(seller) // 商户收款账号 || 签约卖家支付宝账号 97 | .setOutTradeNo(outTradeNo) //设置唯一订单号 98 | .setSubject(orderSubject) //设置订单标题 99 | .setBody(orderBody) //设置订单内容 100 | .setPrice(price) //设置订单价格 101 | .setCallbackUrl(callbackUrl) //设置回调链接 102 | .createOrderInfo(); //创建支付宝支付订单信息 103 | 104 | 105 | //2.签名 支付宝支付订单的信息 ===>>> 商户私钥签名之后的订单信息 106 | //TODO 这里需要从服务器获取用商户私钥签名之后的订单信息 107 | String signAliOrderInfo = getSignAliOrderInfoFromServer(rawAliOrderInfo); 108 | 109 | //3.发送支付宝支付请求 110 | AliPayReq2 aliPayReq = new AliPayReq2.Builder() 111 | .with(activity)//Activity实例 112 | .setRawAliPayOrderInfo(rawAliOrderInfo)//支付宝支付订单信息 113 | .setSignedAliPayOrderInfo(signAliOrderInfo) //设置 商户私钥RSA加密后的支付宝支付订单信息 114 | .create()// 115 | .setOnAliPayListener(null);// 116 | PayAPI.getInstance().sendPayRequest(aliPayReq); 117 | 118 | //关于支付宝支付的回调 119 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 120 | ``` 121 | 122 | ## 存在的问题 123 | 124 | ### 微信支付回调的问题 125 | 126 | 之前微信支付是可以支付的,但是存在一个问题,就是微信支付回调的问题,我一直在寻找不同于官方的那样的回调方法,但是还是没有找到,只能想微信支付妥协~如果你想要微信支付的回调,还是可以实现的,只是做法跟微信支付官方文档一样。 127 | 128 | 129 | 解决方案: 130 | 131 | 1.在你的项目的包名下面新建wxapi包, 132 | 2.新建一个WXPayEntryActivity类, 133 | 3.实现IWXAPIEventHandler接口 134 | 4.在你对应的地方注册接收微信支付的广播即可 135 | 136 | 注意: 137 | 138 | 1.下面的是示例代码中的APP_ID需要替换为自己的 139 | 2.下面的是示例代码中的WeChatPayReceiver需要自己定义 140 | 141 | 下面是示例代码: 142 | 143 | 144 | ```java 145 | 146 | import android.app.Activity; 147 | import android.app.AlertDialog; 148 | import android.content.Intent; 149 | import android.os.Bundle; 150 | import android.util.Log; 151 | import android.widget.Toast; 152 | 153 | import com.tencent.mm.sdk.constants.ConstantsAPI; 154 | import com.tencent.mm.sdk.modelbase.BaseReq; 155 | import com.tencent.mm.sdk.modelbase.BaseResp; 156 | import com.tencent.mm.sdk.openapi.IWXAPI; 157 | import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; 158 | import com.tencent.mm.sdk.openapi.WXAPIFactory; 159 | 160 | public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{ 161 | 162 | private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity"; 163 | 164 | private IWXAPI api; 165 | 166 | //TODO 这里需要替换你的APP_ID 167 | private String APP_ID = "wx0xxxxxxxxx"; //这里需要替换你的APP_ID 168 | 169 | @Override 170 | public void onCreate(Bundle savedInstanceState) { 171 | super.onCreate(savedInstanceState); 172 | // setContentView(R.layout.pay_result); 173 | 174 | api = WXAPIFactory.createWXAPI(this, APP_ID); 175 | api.handleIntent(getIntent(), this); 176 | } 177 | 178 | @Override 179 | protected void onNewIntent(Intent intent) { 180 | super.onNewIntent(intent); 181 | setIntent(intent); 182 | api.handleIntent(intent, this); 183 | } 184 | 185 | @Override 186 | public void onReq(BaseReq req) { 187 | } 188 | 189 | @Override 190 | public void onResp(BaseResp resp) { 191 | Log.d(TAG, "onPayFinish, errCode = " + resp.errCode); 192 | 193 | if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { 194 | // AlertDialog.Builder builder = new AlertDialog.Builder(this); 195 | // builder.setTitle(R.string.app_tip); 196 | // builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode))); 197 | // builder.show(); 198 | 199 | //以下是自定义微信支付广播的发送,微信支付广播请自己定义 200 | 201 | Intent intent = new Intent(); 202 | intent.setAction(WeChatPayReceiver.ACTION_PAY_RESULT); 203 | intent.putExtra("result", resp.errCode); 204 | sendBroadcast(intent); 205 | 206 | finish(); 207 | } 208 | } 209 | } 210 | 211 | ``` 212 | 213 | ## 混淆 214 | 215 | ```xml 216 | 217 | #pay_library 218 | -dontwarn io.github.mayubao.pay_library.** 219 | -keep class io.github.mayubao.pay_library.** {*;} 220 | 221 | #wechat pay 222 | -dontwarn com.tencent.** 223 | -keep class com.tencent.** {*;} 224 | 225 | 226 | #alipay 227 | -dontwarn com.alipay.** 228 | -keep class com.alipay.** {*;} 229 | 230 | -dontwarn com.ta.utdid2.** 231 | -keep class com.ta.utdid2.** {*;} 232 | 233 | -dontwarn com.ut.device.** 234 | -keep class com.ut.device.** {*;} 235 | 236 | -dontwarn org.json.alipay.** 237 | -keep class corg.json.alipay.** {*;} 238 | ``` 239 | 240 | 241 | ## 文档 242 | 243 | ### 微信支付官方文档 支付流程 244 | https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 245 | 246 | ### 支付宝支付官方文档 支付流程 247 | https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.sdGXaH&treeId=204&articleId=105296&docType=1 248 | 249 | 250 | 251 | ## 注意 252 | 253 | ### 微信支付 254 | 255 | - 微信支付必须要在**正式签名**和**正确包名**的应用中才能成功调起。(**重点) 256 | 257 | 即商户在微信开放平台申请开发应用后对应包名和对应签名的应用才能成功调起。 258 | 详情请参考微信支付的开发流程文档。 259 | 260 | https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 261 | 262 | - 微信支付API没有在客户端显示的设置回调,回调是在Server端设置的。(与支付宝支付的区别,支付宝的回调是在客户端设置的) 263 | 264 | ### 支付宝支付 265 | 266 | - 支付宝支付为了保证交易双方的身份和数据安全, 需要配置双方密钥。 267 | 268 | 详情请参考支付宝支付的密钥处理体系文档。 269 | 270 | https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.1wPnBT&treeId=204&articleId=106079&docType=1 271 | 272 | ## 打赏 273 | 如果你觉得此项目对你有用,能否赏我一杯咖啡呢? 274 | 275 | ### 微信支付 276 | ![](http://img.blog.csdn.net/20170302140650271) 277 | ### 支付宝支付 278 | ![支付宝支付](http://img.blog.csdn.net/20170302140734345) 279 | 280 | 281 | ## Lisence 282 | 283 | Copyright 2017 mayubao 284 | 285 | Licensed under the Apache License, Version 2.0 (the "License"); 286 | you may not use this file except in compliance with the License. 287 | You may obtain a copy of the License at 288 | 289 | http://www.apache.org/licenses/LICENSE-2.0 290 | 291 | Unless required by applicable law or agreed to in writing, software 292 | distributed under the License is distributed on an "AS IS" BASIS, 293 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 294 | See the License for the specific language governing permissions and 295 | limitations under the License. 296 | 297 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # Android-Pay 2 | [中文](https://github.com/mayubao/Android-Pay/blob/master/README_CN.md) 3 | 4 | A pay libary for Android, and which support Wechat pay and Ali pay. 5 | And developer can easily use Wechat pay in two line code. 6 | And developer can easily use Ali pay in three line code. 7 | 8 | ## Include 9 | 10 | ### gradle 11 | add these code in your app **build.gradle** as follow: 12 | 13 | ```xml 14 | dependencies { 15 | //add pay libaray 16 | compile 'io.github.mayubao:pay_library:1.0.1' 17 | } 18 | ``` 19 | 20 | ### maven 21 | 22 | ```xml 23 | 24 | io.github.mayubao 25 | pay_library 26 | 1.0.1 27 | pom 28 | 29 | ``` 30 | 31 | ## Usage 32 | 33 | ### Wechat Pay Usage 34 | 35 | ```java 36 | //1.create request for wechat pay 37 | WechatPayReq wechatPayReq = new WechatPayReq.Builder() 38 | .with(this) //activity instance 39 | .setAppId(appid) //wechat pay AppID 40 | .setPartnerId(partnerid)//wechat pay partner id 41 | .setPrepayId(prepayid)//pre pay id 42 | // .setPackageValue(wechatPayReq.get)//"Sign=WXPay" 43 | .setNonceStr(noncestr) 44 | .setTimeStamp(timestamp)//time stamp 45 | .setSign(sign)//sign 46 | .create(); 47 | //2. send the request with wechat pay 48 | PayAPI.getInstance().sendPayRequest(wechatPayReq); 49 | 50 | 51 | //set the callback for wechat pay 52 | //wechatPayReq.setOnWechatPayListener(new OnWechatPayListener); 53 | 54 | 55 | ``` 56 | 57 | >Notes:WechatPayReq have no method to set the money, because the money info is include in the parameter 'prepayid'. 58 | 59 | ### Ali Pay Usage 60 | 61 | 62 | #### Ali Pay first way(**Not Recommend**, and its partner rsa private key export in the client , it is very dangerous!) 63 | ```java 64 | 65 | //step 1 create config for ali pay 66 | AliPayAPI.Config config = new AliPayAPI.Config.Builder() 67 | .setRsaPrivate(rsa_private) // rsa private key from partner (pkcs8 format) 68 | .setRsaPublic(rsa_public)//ali rsa public key 69 | .setPartner(partner) //set partner 70 | .setSeller(seller) //set partner seller accout 71 | .create(); 72 | 73 | //step 2 create reqeust for ali 74 | AliPayReq aliPayReq = new AliPayReq.Builder() 75 | .with(activity)//Activity instance 76 | .apply(config)// the above custome config 77 | .setOutTradeNo(outTradeNo)//set unique trade no 78 | .setPrice(price)//set price 79 | .setSubject(orderSubject)//set order subject 80 | .setBody(orderBody)//set order detail 81 | .setCallbackUrl(callbackUrl)//set callback for pay reqest 82 | .create()// 83 | .setOnAliPayListener(null);// 84 | 85 | //step 3 send the request for ali pay 86 | PayAPI.getInstance().sendPayRequest(aliPayReq); 87 | 88 | // set the ali pay callback 89 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 90 | 91 | ``` 92 | 93 | #### Ali Pay second way(**Highly Recommend**) 94 | 95 | ```java 96 | //step 1 create raw ali pay order info 97 | String rawAliOrderInfo = new AliPayReq2.AliOrderInfo() 98 | .setPartner(partner) //set partner 99 | .setSeller(seller) //set partner seller accout 100 | .setOutTradeNo(outTradeNo) //set unique trade no 101 | .setSubject(orderSubject) //set order subject 102 | .setBody(orderBody) //set order detail 103 | .setPrice(price) //set price 104 | .setCallbackUrl(callbackUrl) //set callback for pay reqest 105 | .createOrderInfo(); //create ali pay order info 106 | 107 | 108 | //step 2 get the signed ali pay order info 109 | String signAliOrderInfo = getSignAliOrderInfoFromServer(rawAliOrderInfo); 110 | 111 | //step 3 step 3 send the request for ali pay 112 | AliPayReq2 aliPayReq = new AliPayReq2.Builder() 113 | .with(activity)//Activity instance 114 | .setSignedAliPayOrderInfo(signAliOrderInfo) 115 | .setRawAliPayOrderInfo(rawAliOrderInfo)//set the ali pay order info 116 | .setSignedAliPayOrderInfo(signAliOrderInfo) //set the signed ali pay order info 117 | .create()// 118 | .setOnAliPayListener(null);// 119 | PayAPI.getInstance().sendPayRequest(aliPayReq); 120 | 121 | 122 | //set the ali pay callback 123 | //aliPayReq.setOnAliPayListener(new OnAliPayListener); 124 | 125 | ``` 126 | 127 | 128 | ## Proguard 129 | 130 | ```xml 131 | 132 | #pay_library 133 | -dontwarn io.github.mayubao.pay_library.** 134 | -keep class io.github.mayubao.pay_library.** {*;} 135 | 136 | #wechat pay 137 | -dontwarn com.tencent.** 138 | -keep class com.tencent.** {*;} 139 | 140 | 141 | #alipay 142 | -dontwarn com.alipay.** 143 | -keep class com.alipay.** {*;} 144 | 145 | -dontwarn com.ta.utdid2.** 146 | -keep class com.ta.utdid2.** {*;} 147 | 148 | -dontwarn com.ut.device.** 149 | -keep class com.ut.device.** {*;} 150 | 151 | -dontwarn org.json.alipay.** 152 | -keep class corg.json.alipay.** {*;} 153 | ``` 154 | 155 | 156 | ## Document 157 | 158 | ### wehcat pay official document 159 | https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 160 | 161 | ### ali pay official document 162 | https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.sdGXaH&treeId=204&articleId=105296&docType=1 163 | 164 | 165 | ## Help 166 | If it is helpful to you, could you buy me a cup of coffee? 167 | 168 | ### Wechat 169 | ![](http://img.blog.csdn.net/20170302140650271) 170 | ### Ali 171 | ![支付宝支付](http://img.blog.csdn.net/20170302140734345) 172 | 173 | 174 | ## Lisence 175 | 176 | Copyright 2017 mayubao 177 | 178 | Licensed under the Apache License, Version 2.0 (the "License"); 179 | you may not use this file except in compliance with the License. 180 | You may obtain a copy of the License at 181 | 182 | http://www.apache.org/licenses/LICENSE-2.0 183 | 184 | Unless required by applicable law or agreed to in writing, software 185 | distributed under the License is distributed on an "AS IS" BASIS, 186 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 187 | See the License for the specific language governing permissions and 188 | limitations under the License. 189 | 190 | 191 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "24.0.1" 6 | 7 | defaultConfig { 8 | applicationId "io.github.mayubao.android_pay" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.4.0' 26 | compile 'com.android.support:design:23.4.0' 27 | compile project(':pay-library') 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\android\adt-bundle-windows-x86_64-20140702\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/io/github/mayubao/android_pay/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.github.mayubao.android_pay; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 29 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/mayubao/android_pay/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.mayubao.android_pay; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.Snackbar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.View; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | 13 | public class MainActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_main); 19 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 20 | setSupportActionBar(toolbar); 21 | 22 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 23 | fab.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View view) { 26 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 27 | .setAction("Action", null).show(); 28 | } 29 | }); 30 | } 31 | 32 | @Override 33 | public boolean onCreateOptionsMenu(Menu menu) { 34 | // Inflate the menu; this adds items to the action bar if it is present. 35 | getMenuInflater().inflate(R.menu.menu_main, menu); 36 | return true; 37 | } 38 | 39 | @Override 40 | public boolean onOptionsItemSelected(MenuItem item) { 41 | // Handle action bar item clicks here. The action bar will 42 | // automatically handle clicks on the Home/Up button, so long 43 | // as you specify a parent activity in AndroidManifest.xml. 44 | int id = item.getItemId(); 45 | 46 | //noinspection SimplifiableIfStatement 47 | if (id == R.id.action_settings) { 48 | gotoUI(TestOnlineActivity.class); //作为库的module的AndroidManifest.xml是会被合并的 49 | return true; 50 | }else if (id == R.id.action_test_wechat_pay) { 51 | gotoUI(PayWechatActivity.class); 52 | return true; 53 | }else if (id == R.id.action_test_ali_pay) { 54 | gotoUI(PayAliPayActivity.class); 55 | return true; 56 | } 57 | 58 | return super.onOptionsItemSelected(item); 59 | } 60 | 61 | 62 | /** 63 | * 跳转到支付测试页面 64 | * @param clazz 65 | */ 66 | private void gotoUI(Class clazz){ 67 | Intent intent = new Intent(this, clazz); 68 | startActivity(intent); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/mayubao/android_pay/PayAliPayActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.mayubao.android_pay; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | 10 | public class PayAliPayActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_pay_ali_pay); 16 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 17 | setSupportActionBar(toolbar); 18 | 19 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 20 | fab.setOnClickListener(new View.OnClickListener() { 21 | @Override 22 | public void onClick(View view) { 23 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 24 | .setAction("Action", null).show(); 25 | } 26 | }); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/mayubao/android_pay/PayWechatActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.mayubao.android_pay; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | 10 | public class PayWechatActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_pay_wechat); 16 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 17 | setSupportActionBar(toolbar); 18 | 19 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 20 | fab.setOnClickListener(new View.OnClickListener() { 21 | @Override 22 | public void onClick(View view) { 23 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 24 | .setAction("Action", null).show(); 25 | } 26 | }); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/mayubao/android_pay/TestOnlineActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.mayubao.android_pay; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.View; 9 | import android.webkit.WebChromeClient; 10 | import android.webkit.WebView; 11 | import android.webkit.WebViewClient; 12 | 13 | public class TestOnlineActivity extends AppCompatActivity { 14 | 15 | public static final String DEFAULT_TEST_URL = "http://www.baidu.com"; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_test_online); 21 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 22 | setSupportActionBar(toolbar); 23 | 24 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 25 | fab.setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View view) { 28 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 29 | .setAction("Action", null).show(); 30 | } 31 | }); 32 | 33 | 34 | final WebView webView = (WebView) this.findViewById(R.id.webView); 35 | 36 | webView.getSettings().setJavaScriptEnabled(true); 37 | webView.setWebViewClient(new WebViewClient() { 38 | @Override 39 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 40 | webView.loadUrl(url); 41 | return super.shouldOverrideUrlLoading(view, url); 42 | } 43 | }); 44 | 45 | webView.setWebChromeClient(new WebChromeClient() { 46 | 47 | }); 48 | 49 | webView.loadUrl(DEFAULT_TEST_URL); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_pay_ali_pay.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_pay_wechat.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_test_online.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_pay_ali_pay.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_pay_wechat.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_test_online.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayubao/Android-Pay/603233da5d5d78b3f25273b87554e2a06d6d3e61/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayubao/Android-Pay/603233da5d5d78b3f25273b87554e2a06d6d3e61/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayubao/Android-Pay/603233da5d5d78b3f25273b87554e2a06d6d3e61/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayubao/Android-Pay/603233da5d5d78b3f25273b87554e2a06d6d3e61/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayubao/Android-Pay/603233da5d5d78b3f25273b87554e2a06d6d3e61/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | > 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Android-Pay 3 | Settings 4 | 微信支付测试 5 | 支付宝支付测试 6 | PayWechatActivity 7 | PayAliPayActivity 8 | TestOnlineActivity 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |