在线支付
使用Ping++实现在线支付
Ping++是为移动应用量身打造的下一代支付系统,开发者不需要编写冗长的代码,应付复杂的入网申请流程,简单几步就可以是你的移动应用福ode支付功能,从而更专注于开发应用本身。
支付渠道:
- 微信支付、微信扫码支付、微信红包、微信企业付款
- 支付宝支付、支付宝扫码支付
- 银联手机支付
- 京东支付
- 百度钱包
- 易宝支付
- Apple Pay
导入 Ping++ SDK,支持在线导入和下载 SDK 导入两种方式
客户端配置在线导入方式
- 在项目中的 build.gradle 中添加 bintray 仓库地址
allprojects {
repositories {
// ...其他仓库地址...
jcenter()
// 添加下面的 bintray 仓库地址
maven {
url "https://dl.bintray.com/pingxx/maven"
}
}
}
- 在 module 中 的 build.gradle 中设置
dependencies {
implementation 'com.pingxx:pingpp-android:2.2.2' // (Ping++ 标准版 SDK) 必须添加
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+' // 使用微信支付时添加,具体版本参考微信官方文档
implementation 'com.pingxx:pingpp-android-alipay:2.2.0' // 使用支付宝时添加
implementation 'com.pingxx:pingpp-android-upacp:2.2.0' // 使用银联支付时添加
implementation 'com.pingxx:pingpp-qpay:2.1.19' // 使用QQ钱包时添加
implementation 'com.pingxx:pingpp-cmbwallet:2.1.19' // 使用招行一网通时添加
implementation 'com.pingxx:pingpp-ccbpay:2.1.19' // 使用建行支付时添加
implementation 'com.pingxx:pingpp-android-cmpay:2.2.2' // 使用和包支付时添加
}
权限声明
<!-- 注:有些权限是需要动态注册的,如 READ_PHONE_STATE 权限 -->
<!-- 通用权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 银联需要的权限 -->
<uses-permission android:name="android.permission.NFC"/>
开始接入
注册 activity
<!-- Ping++ SDK -->
<activity
android:name="com.pingplusplus.android.PaymentActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
<!-- 不使用QQ钱包,可删除此部分代码 -->
<!-- scheme 填写规则建议:qwallet + QQ 钱包中的 app_id -->
<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="qwalletXXXXXXXX"/>
</intent-filter>
</activity>
<!-- 微信支付 -->
<!-- 1.需要将以下"替换成自己 APK 的包名"换成在微信平台上注册填写的包名 -->
<!-- 2.WxPayEntryActivity 这个类在 SDK 内部实现,开发者不需要额外实现该类 -->
<activity-alias
android:name="替换成自己APK的包名.wxapi.WXPayEntryActivity"
android:exported="true"
android:targetActivity="com.pingplusplus.android.PaymentActivity" />
<!-- 招行一网通(非混淆加密方式) -->
<service android:name="cmb.pb.cmbsafe.CmbService" android:exported="false"/>
<activity
android:name="cmb.pb.ui.PBKeyboardActivity"
android:theme="@style/CmbDialogStyleBottom" />
<!-- 招行一网通 App 即招商银行(格式:`<SCHEME>://pingppcmbwallet`,其中 `<SCHEME>` 是你自定义的 `URL Schemes`) -->
<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="自定义 URL Scheme"/>
<data android:host="pingppcmbwallet"/>
</intent-filter>
<!-- 将以上代码添加到 Ping++ SDK 注册的 Activity,如: -->
<activity
android:name="com.pingplusplus.android.PaymentActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
<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="自定义 URL Scheme"/>
<data android:host="pingppcmbwallet"/>
</intent-filter>
</activity>
<!-- 建行支付需注册 (自定义 action-name 保持与服务端的 third_app_info 一致) -->
<activity android:name="com.ccb.ccbnetpay.activity.appresult.ResultActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="自定义 action-name"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.ccb.ccbnetpay.activity.CcbUnionPayActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"/>
<activity android:name="com.ccb.ccbnetpay.activity.CcbH5PayActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"/>
客户端实现代码
package com.example.ping;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.gson.Gson;
import com.pingplusplus.android.PaymentActivity;
import com.pingplusplus.android.Pingpp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button button_pay;
private static final int REQUEST_CODE_PAYMENT = 1;
/**
* 银联支付渠道
*/
private static final String CHANNEL_UPACP = "upacp";
/**
* 微信支付渠道
*/
private static final String CHANNEL_WECHAT = "wx";
/**
* QQ钱包支付渠道
*/
private static final String CHANNEL_QPAY = "qpay";
/**
* 支付宝支付渠道
*/
private static final String CHANNEL_ALIPAY = "alipay";
/**
* 百度支付渠道
*/
private static final String CHANNEL_BFB = "bfb_wap";
/**
* 京东支付渠道
*/
private static final String CHANNEL_JDPAY_WAP = "jdpay_wap";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button_pay=findViewById(R.id.button_pay);
button_pay.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_pay:
new PaymentTask().execute(new PaymentRequest(CHANNEL_UPACP, 100));//数字按分来算,100=一块
break;
}
}
private static final String URL="http://192.168.1.82:8080/Pingxx/PayServlet";
//异步支付任务
class PaymentTask extends AsyncTask<PaymentRequest,Void,String> {
@Override
protected void onPreExecute() {
//按键点击之后的禁用,防止重复点击
//防止重复提交
button_pay.setOnClickListener(null);
}
@Override
protected String doInBackground(PaymentRequest... paymentRequests) {
PaymentRequest paymentRequest = paymentRequests[0];
String data = null;
String json=new Gson().toJson(paymentRequest);
try {
//向Your Ping++ Server SDK请求数据
//URL服务器地址
data = postJson(URL, json);
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 获得服务端的charge,调用ping++ sdk。
*/
@Override
protected void onPostExecute(String data) {
if(null == data){
showMsg("请求出错", "请检查URL", "URL无法获取charge");
return;
}
Log.d("charge", data);
//除QQ钱包外,其他渠道调起支付方式:
//参数一:Activity 当前调起支付的Activity
//参数二:data 获取到的charge或order的JSON字符串
// Pingpp.createPayment(ClientSDKActivity.this, data);
Intent intent=new Intent();
String packageName=getPackageName();
ComponentName componentName=new ComponentName(packageName,packageName+".wxapi.WXPayEntryActivity");
intent.setComponent(componentName);
intent.putExtra(PaymentActivity.EXTRA_CHARGE,data);
startActivityForResult(intent,REQUEST_CODE_PAYMENT);
//QQ钱包调用方式
//参数一:Activity 当前调起支付的Activity
//参数二:data 获取到的charge或order的JSON字符串
//参数三:“qwallet1234567890”需与AndroidManifest.xml中的scheme值一致
//Pingpp.createPayment(ClientSDKActivity.this, data, "qwallet1234567890");
}
}
//请求服务器
private static String postJson(String urlStr, String json) throws IOException {
java.net.URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/json");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.getOutputStream().write(json.getBytes());
if(conn.getResponseCode() == 200) {
BufferedReader
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
return null;
}
/**
* onActivityResult 获得支付结果,如果支付成功,服务器会收到ping++ 服务器发送的异步通知。
* 最终支付成功根据异步通知为准
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
button_pay.setOnClickListener(this);
//支付页面返回处理
if (requestCode == Pingpp.REQUEST_CODE_PAYMENT) {
if (resultCode == Activity.RESULT_OK) {
String result = data.getExtras().getString("pay_result");
/* 处理返回值
* "success" - payment succeed
* "fail" - payment failed
* "cancel" - user canceld
* "invalid" - payment plugin not installed
*/
String errorMsg = data.getExtras().getString("error_msg"); // 错误信息
String extraMsg = data.getExtras().getString("extra_msg"); // 错误信息
showMsg(result, errorMsg, extraMsg);
}
}
}
public void showMsg(String title, String msg1, String msg2) {
String str = title;
if (null !=msg1 && msg1.length() != 0) {
str += "\n" + msg1;
}
if (null !=msg2 && msg2.length() != 0) {
str += "\n" + msg2;
}
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(str);
builder.setTitle("提示");
builder.setPositiveButton("OK", null);
builder.create().show();
}
class PaymentRequest {
String channel;//支付渠道
int amount;//价格
public PaymentRequest(String channel, int amount) {
this.channel = channel;
this.amount = amount;
}
}
}
服务器端
PayServlet.java
package com.example.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.PingppException;
import com.pingplusplus.model.Charge;
/**
* Servlet implementation class PayServlet
*/
@WebServlet("/PayServlet")
public class PayServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public PayServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request,response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
PrintWriter out=response.getWriter();
Pingpp.apiKey="Your-Key";
//获取客户端参数:amount,channel
ServletInputStream in= request.getInputStream();
byte[] bytes=new byte[512];
int len=-1;
StringBuffer buf=new StringBuffer();
while((len=in.read(bytes))!=-1){
buf.append(new String(bytes,0,len));
}
Gson gson=new Gson();
PaymentRequest pay= gson.fromJson(buf.toString(), PaymentRequest.class);
Map<String, Object> chargeMap = new HashMap<String, Object>();
// 某些渠道需要添加extra参数,具体参数详见接口文档
chargeMap.put("amount", pay.amount);
chargeMap.put("currency", "cny");
chargeMap.put("subject", "购买了一款时髦的短发");
chargeMap.put("body", "黑色,短款,齐刘海");
chargeMap.put("order_no", "123456789");
chargeMap.put("channel", pay.channel);
chargeMap.put("client_ip", request.getRemoteAddr());
Map<String, String> app = new HashMap<String, String>();
app.put("id", "YOUR_APP_ID");
chargeMap.put("app", app);
try {
//发起交易请求
Charge charge = Charge.create(chargeMap);
System.out.println(charge.toString());
out.write(charge.toString());
} catch (PingppException e) {
e.printStackTrace();
}
}
}
PaymentRequest.java
package com.example.servlet;
public class PaymentRequest {
String channel;//支付渠道
int amount;//价格
public PaymentRequest(String channel, int amount) {
this.channel = channel;
this.amount = amount;
}
}