一、微信支付
第一步登录微信开放平台:https://open.weixin.qq.com/,进入账号中心进行开发者资质认证,需要填写公司资料,包括但不限于,公司注册号,公司营业执照,公司对外办公电话,公司 对公银行卡信息(卡号,发卡行)。审核时间为
一周左右,进行开发者资质认证需要支付 300 元人民币/年,只有具备开发者资质认证的开发者才能够使用 app 支付,授权登录等接口。
申请 APP_ID/APP_KEY
每个应用/游戏要调用微信的接口都需要有一个微信标志,这个唯一标志通常成为 APP_ID 或者 APP_KEY,各开放平台差异不大进入管理中心,创建移动应用,每个开发者具有 10 个应用的创建机会,好在创建的应用可以随时删除。 已上线的应用就不建议手贱删除!!申请 appid 需要填写应用信息:应用名称,包名,签名(keystore 的 md5 值去分号小写),icon(2828 & 108108),app 下载地址等信息,即可分配到一个 appid。
开通微信商户平台,登录微信商户平台https://pay.weixin.qq.com,这里也是需要300元人民币/年开通微信支付功能,绑定企业银行,开通企业微信商户,在产品中心中,开通“APP支付”功能
开通成功之后绑定微信开放平台的APPID
在产品中心中,左边列表选择“APPID授权管理”进行绑定,
此时,微信支付申请就搞定了,可以进行开发了
Android studio 新建工程
在build.gradle 中的dependencies 中
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
依赖微信支付,登录的依赖包
在工程的目录包名下新建目录wxapi,新建WXPayEntryActivity.java类,此类名称不可以变,必须放在wxapi下,如包名为com.xx.xxx.xxx,WXPayEntryActivity类就放在com.xx.xxx.xxx.wxapi下,
在AndroidManifest.xml中配置
<activity
android:name="工程包名.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"/>
及网络权限
<uses-permission android:name="android.permission.INTERNET" />
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(WeiXinPay.getInstance(this)!=null){
WeiXinPay.getInstance(this).getWXApi().handleIntent(getIntent(), this);
}else {
finish();
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
if (!WeiXinPay.getInstance(this).getWXApi().handleIntent(intent, this)) {
finish();
}
}
@Override
public void onReq(BaseReq baseReq) {
}
@Override
public void onResp(BaseResp baseResp) {
//4、支付结果回调 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
Log.e("WXPayEntryActivity", "baseResp=" + baseResp.toString());
if(baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
if(WeiXinPay.getInstance(this) != null) {
if(baseResp.errStr != null) {
Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
}
WeiXinPay.getInstance(this).onResp(baseResp);
finish();
}
}
}
}
回调中 errCode 值列表:
0 支付成功
-1 发生错误 可能的原因:签名错误、未注册 APPID、项目设
置 APPID 不正确、注册的 APPID 与设置的不匹配、其他异常
等。
-2 用户取消 发生场景:用户不支付了,点击取消,返回 APP。
微信支付的回调再该类的onResp方法中回调
微信支付类,通过服务器返回的数据,拿到appid,注册到微信 mIWXAPI.registerApp(appId);
其中服务端返回的数据中partnerid 就是商户id
根据服务端返回的数据拉起支付
PayReq req = new PayReq();
req.appId = payBean.getAppid();
req.partnerId = payBean.getMch_id();
req.prepayId = payBean.getPrepay_id();
req.nonceStr = payBean.getNonce_str();
req.timeStamp = payBean.getTimestamp();
req.packageValue = "Sign=WXPay";
req.sign = payBean.getSignB();//服务端的签名 正式使用
//req.sign = genAppSign(payBean).toUpperCase();//客户端的签名 测试
mIWXAPI.sendReq(req);
需要注意的是,在微信开放平台创建的应用,填写的包名和签名,必须和工程保持一致,否则拉起支付有可能返回-1,
package 是不变的,sign 是服务签名的,客户端测试的话,可以放在客户端签名
测试代码
orderWechat = "{\n" +
" "appid": "wxca3042x2xxxxx4e344cf01",\n" +
" "partnerid": "1526501",\n" +
" "prepayid": "wx161841xxxxxxx542151",\n" +
" "timestamp": "1558xxx003316",\n" +
" "noncestr": "c8J2CxxnDxx7qDx15dus",\n" +
" "package": "Sign=WXPay",\n" +
" "sign": "34CBBAxxxxxxx0F59775F"\n" +
"}";
if(TextUtils.isEmpty(orderWechat)){
Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
return;
}
//微信支付
// * 注意
// * 微信的APPID 和签名信息及报名和微信开放平台填写的要一致
pay.payDoraVip(MainActivity.this,"PHP",JPay.PayMode.WXPAY,orderWechat);
客户端签名样例,key值按升序拼接在用MD5加密
private String genAppSign(WechatPayBean payBean) {
List<NameValuePair> signParams = new LinkedList<>();
signParams.add(new NameValuePair("appid", payBean.getAppid()));
signParams.add(new NameValuePair("noncestr", payBean.getNonce_str()));
signParams.add(new NameValuePair("package", "Sign=WXPay"));
signParams.add(new NameValuePair("partnerid",payBean.getMch_id()));
signParams.add(new NameValuePair("prepayid", payBean.getPrepay_id()));
signParams.add(new NameValuePair("timestamp", payBean.getTimestamp()));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < signParams.size(); i++) {
sb.append(signParams.get(i).getName());
sb.append('=');
sb.append(signParams.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append("api密钥");
String appSign = MD5Utils.getMessageDigest(sb.toString().getBytes());
return appSign;
}
二、支付宝支付
登录支付宝网站https://auth.alipay.com
进行企业验证,验证完成进入我的开放平台
我的开放平台---开发中心--网页移动应用
立即创建应用,创建完成添加APP支付功能
在工程到导入alipaySdk-20180601.jar包,
/**
- Created by camming on 2019/11/21.
- 支付宝支付
*/
private static Alipay mAliPay;
private Activity mContext;
private JPay.JPayListener mJPayListener;
//支付失败
public static final int PAY_ERROR = 0x001;
//支付网络连接出错
public static final int PAY_NETWORK_ERROR = 0x002;
//支付结果解析错误
public static final int RESULT_ERROR = 0x003;
//正在处理中
public static final int PAY_DEALING = 0x004;
//其它支付错误
public static final int PAY_OTHER_ERROR = 0x006;
//支付参数异常
public static final int PAY_PARAMETERS_ERROE = 0x007;
private Alipay(Activity context) {
mContext = context;
}
public static Alipay getInstance(Activity context){
if (mAliPay == null) {
synchronized(WeiXinPay.class){
if (mAliPay == null) {
mAliPay = new Alipay(context);
}
}
}
return mAliPay;
}
public void startAliPay(final String orderInfo,JPay.JPayListener listener){
boolean bool = checkAliPayInstalled(mContext);
if(!bool){
Toast.makeText(mContext,"支付宝未安装!",Toast.LENGTH_SHORT).show();
return;
}
mJPayListener = listener;
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(mContext);
Map<String, String> result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
/**
* 检测是否安装支付宝
* @param context
* @return
*/
public static boolean checkAliPayInstalled(Context context) {
Uri uri = Uri.parse("alipays://platformapi/startApp");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
ComponentName componentName = intent.resolveActivity(context.getPackageManager());
return componentName != null;
}
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) {
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
Log.e("payResult= ",payResult.toString());
System.out.print("payResult= "+payResult.toString());
String resultStatus = payResult.getResultStatus();
if (mJPayListener ==null){
return;
}
// https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.xN1NnL&treeId=204&articleId=105302&docType=1
if(payResult == null) {
mJPayListener.onPayError(RESULT_ERROR,"结果解析错误");
return;
}
if(TextUtils.equals(resultStatus, "9000")) {
//支付成功
mJPayListener.onPaySuccess();
} else if(TextUtils.equals(resultStatus, "8000")) {
//正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
mJPayListener.onPayError(PAY_DEALING,"正在处理结果中");
} else if(TextUtils.equals(resultStatus, "6001")) {
//支付取消
mJPayListener.onPayCancel();
} else if(TextUtils.equals(resultStatus, "6002")) {
//网络连接出错
mJPayListener.onPayError(PAY_NETWORK_ERROR,"网络连接出错");
} else if(TextUtils.equals(resultStatus, "4000")) {
//支付错误
mJPayListener.onPayError(PAY_ERROR,"订单支付失败");
}else {
mJPayListener.onPayError(PAY_OTHER_ERROR,resultStatus);
}
}
};
}
/**
- create by camming 2019/02/14
- 情人节也要写代码
- 支付宝支付
- */
public AliPayTask(Activity context) {
this.mContext = context;
}
public AliPayTask(Activity context,String type,JPay.JPayListener listener) {
this.mContext = context;
this.mJPayListener =listener;
this.serverType = type;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(String result) {
Log.e("AideaAliPayTask", "result"+result);
// AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
try {
if (result!=null){
// AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
if(serverType.equals(API_TYPE_PHP)){
System.out.println("PHP后台返回的数据orderInfo="+result);
PayUtils.getIntance(mContext).startAliPay(result,mJPayListener);
}else{
JSONObject jsonObject=new JSONObject(result);
int code = jsonObject.getInt("code");
if(code==0){
String resultData = jsonObject.getString("data");
System.out.println("orderInfo="+resultData);
///Toast.makeText(mContext, "正在调起支付", Toast.LENGTH_SHORT).show();
PayUtils.getIntance(mContext).startAliPay(resultData,mJPayListener);
}else{
Toast.makeText(mContext, "错误"+jsonObject.getString("message"), Toast.LENGTH_SHORT).show();
}
}
}else {
System.out.println("get AliPay exception, is null");
}
} catch (Exception e) {
Log.e("PAY_GET", "异常:"+e.getMessage());
Toast.makeText(mContext, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
super.onPostExecute(result);
}
}
三、QQ支付
登录网站https://qpay.qq.com/
申请APP支付,创建应用
在工程项目目录下的wxapi目录下,新建一个QQ支付回调的类,我这里是QQCallbackActivity.java
/**
- Create by camming 2019/02/20
- qq支付通知
- */
String appId = "101538445";
IOpenApi openApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_callback);
openApi = OpenApiFactory.getInstance(this, appId);
openApi.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
openApi.handleIntent(intent, this);
}
@Override
public void onOpenResponse(BaseResponse response) {
String title = "Callback from mqq";
String message;
QQPay.getInstance(this).onQQResponse(response);
if (response == null) {
message = "response is null.";
return;
} else {
if (response instanceof PayResponse) {
PayResponse payResponse = (PayResponse) response;
message = " apiName:" + payResponse.apiName
+ " serialnumber:" + payResponse.serialNumber
+ " isSucess:" + payResponse.isSuccess()
+ " retCode:" + payResponse.retCode
+ " retMsg:" + payResponse.retMsg;
if (payResponse.isSuccess()) {
if (!payResponse.isPayByWeChat()) {
message += " transactionId:" + payResponse.transactionId
+ " payTime:" + payResponse.payTime
+ " callbackUrl:" + payResponse.callbackUrl
+ " totalFee:" + payResponse.totalFee
+ " spData:" + payResponse.spData;
}
}
} else {
message = "response is not PayResponse.";
}
}
}
}
在AndroidManifest.xml中配置
<activity
android:name="工程包名.wxapi.QQCallbackActivity"
android:launchMode="singleTop"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="qwallet+qq商户id"/>
</intent-filter>
</activity>
导入mqqopenpay.jar,
/**
- Created by camming on 2019\2\19 0019.
- code is data data is code
- qq支付
*/
private static final String TAG = "QQPay";
@SuppressLint("StaticFieldLeak")
private static QQPay mQQPay;
private Context mContext;
private String callbackScheme = "qwallet+qqid";
private IOpenApi openApi;
int paySerial = 1;
public static final String QQ_APP_ID = "qqid";
// 签名步骤建议不要在app上执行,要放在服务器上执行
public static final String APP_KEY = "商户key";
private JPay.JPayListener mJPayListener;
public static QQPay getInstance(Context context){
if (mQQPay == null) {
synchronized(QQPay.class){
if (mQQPay == null) {
mQQPay = new QQPay(context);
}
}
}
return mQQPay;
}
private QQPay(Context context) {
mContext = context;
if(openApi==null)
openApi = OpenApiFactory.getInstance(mContext, QQ_APP_ID);
}
/**手机QQ是否已经安装*/
public boolean isMqqInstalled() {
if(openApi==null)
return false;
else
return openApi.isMobileQQInstalled();
}
/**是否支持手机qq支付*/
public boolean isMqqSupportPay() {
if(openApi==null)
return false;
else
return openApi.isMobileQQSupportApi(OpenConstants.API_NAME_PAY);
}
// public void startQQPay(String payResult, JPay.JPayListener listener){
// startQQPay(resultBean,listener);
// }
/**
* 开始QQ支付
*
* */
public void startQQPay(String pay, JPay.JPayListener listener){
this.mJPayListener = listener;
QQPayBean payBean = JSONObject.parseObject(pay,new TypeReference<QQPayBean>(){});
Log.i("qqpay","payBean="+payBean);
// ToastUtils.show(mContext,payBean);
if(!isMqqInstalled()){
Toast.makeText(mContext,"QQ未安装!",Toast.LENGTH_SHORT).show();
return;
}
if(!isMqqSupportPay()){
Toast.makeText(mContext,"该QQ版本不支持QQ支付!",Toast.LENGTH_SHORT).show();
return;
}
PayApi api = new PayApi();
api.appId = payBean.getAppid();
api.serialNumber = "" + paySerial++;//支付序号
api.callbackScheme = callbackScheme;
api.tokenId = payBean.getPrepay_id();// QQ钱包支付生成的token_id
api.pubAcc = "";
api.pubAccHint = "";
api.nonce = payBean.getNonce_str();
api.timeStamp = System.currentTimeMillis() / 1000;
api.bargainorId = payBean.getMch_id();
//直接使用后台返回的签名数据 如果使用服务端的签名,把
//下面的signApi()方法注释掉
// api.sig = "";
// api.sigType = "HMAC-SHA1";
try {
//为了测试,这里直接签名,此步骤放在服务端
signApi(api);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(mContext,"签名异常!",Toast.LENGTH_SHORT).show();
return;
}
if (api.checkParams()) {
openApi.execApi(api);
}else{
Toast.makeText(mContext,"支付参数有误!",Toast.LENGTH_SHORT).show();
}
}
/**
* 签名步骤建议不要在app上执行,要放在服务器上执行.
*/
public void signApi(PayApi api) throws Exception {
// 按key排序 ASCII
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("appId=").append(api.appId);
stringBuilder.append("&bargainorId=").append(api.bargainorId);
stringBuilder.append("&nonce=").append(api.nonce);
stringBuilder.append("&pubAcc=").append("");
stringBuilder.append("&tokenId=").append(api.tokenId);
byte[] byteKey = (APP_KEY+"&").getBytes("UTF-8");
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKey secretKey = new SecretKeySpec(byteKey, "HmacSHA1");
// 生成一个指定 Mac 算法 的 Mac 对象
Mac mac = Mac.getInstance("HmacSHA1");
// 用给定密钥初始化 Mac 对象
mac.init(secretKey);
byte[] byteSrc = stringBuilder.toString().getBytes("UTF-8");
// 完成 Mac 操作
byte[] dst = mac.doFinal(byteSrc);
// Base64
api.sig = Base64.encodeToString(dst, Base64.NO_WRAP);
api.sigType = "HMAC-SHA1";
}
/**
*
* QQ支付结果状态
* */
public void onQQResponse(BaseResponse response){
Log.i("QQPay","response.retCode="+response.retCode+",response.retMsg="+response.retMsg);
if(response!=null){
switch (response.retCode){
case 0://支付成功
if(mJPayListener!=null)
mJPayListener.onPaySuccess();
break;
case -1://支付取消 用户主动取消
if(mJPayListener!=null)
mJPayListener.onPayCancel();
break;
case -2://登录超时
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"登录超时");
break;
case -3://重复提交订单
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"重复提交订单");
break;
case -4:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"快速注册用户手机号不一致");
break;
case -5:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"账号被冻结");
break;
case -6:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"支付密码输入超限");
break;
case -100:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"网络异常错误");
break;
case -101:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"支付参数错误");
break;
default:
if(mJPayListener!=null)
mJPayListener.onPayError(response.retCode,"未知错误");
}
}
}
}
测试代码
orderQQ = "{"appid":"10445","mch_id":"1562271","nonce_str":"58d79b407a55b4af","prepay_id":"6M6c1a02c3b0e6c4","result_code":"SUCCESS","retcode":"0","retmsg":"ok","return_code":"SUCCESS","return_msg":"SUCCESS","sign":"638E931C4B13F7F","trade_type":"APP"}";
if(TextUtils.isEmpty(orderQQ)){
Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
return;
}
pay.payDoraVip(MainActivity.this,"PHP", JPay.PayMode.QQPAY,orderQQ);
JPay工具类,统一管理支付,好了,就写到这里,谢谢
有问题可以加我qq:215330802
项目地址:https://github.com/cammingcai/DoraPay