在线支付

使用Ping++实现在线支付

Ping++是为移动应用量身打造的下一代支付系统,开发者不需要编写冗长的代码,应付复杂的入网申请流程,简单几步就可以是你的移动应用福ode支付功能,从而更专注于开发应用本身。

 

支付渠道:

  1. 微信支付、微信扫码支付、微信红包、微信企业付款
  2. 支付宝支付、支付宝扫码支付
  3. 银联手机支付
  4. 京东支付
  5. 百度钱包
  6. 易宝支付
  7. 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;
	}
}

Android 支付功能_java