蜜蜂市场支付集成帮助文档
编写人 :毕伟平 版本:1.3 正式版 时间:2017-08-29 一、 集成准备 1.1 注册账号,获取 KEY 信息 访问蜜蜂市场开发者平台(),注册开发者帐号后,进入管理中心。
进入管理中心后,选择左侧支付配置选项,点击右侧的【添加 SDK 应用】按钮,会弹出创建 SDK 应用的对话框,填写应用信息保存后,系统会生成对应的 APP_KEY 和 BEE_KEY。
通过点击支付配置页面【配置】按钮,可以查看 APP_KEY 和 BEE_KEY,和填写回调接口。
BEE_KEY 和 APP_KEY 的作用:用来确定集成了我们支付的应用和开发者(用户)信息,为资金对账提供依据。
1.2 下载支付 sdk 请登录开发者平台,或从管理中心选择左侧的【SDK 下载】按钮,选择下载最新版 SDK 集成到应用中。
1.3 配置 回调接口 配置方法:进入管理中心后,选择【支付配置】-----> 选择应用 ----->【配置】,在弹出框
中回调接口处填写回调接口。
回调接口:第三方提供的一个接口,我们蜜蜂支付服务器在支付完成后会将支付相关的信息发送到这个接口,以便告知第三方应用支付成功与否。
1.4
导入 SDK 将下载包中的 libs 文件夹合并到本地工程 libs 子目录下;在 Eclipse 中右键工程根目录,选择 Properties -> Java Build Path -> Libraries,然后点击 Add External JARs... 选择指向 jar 的路径,点击 OK,即导入成功(ADT17 及以上不需要手动导入)。
二、 基本功能集成 2.1 支付流程图
见单独流程图文件 集成了蜜蜂支付的第三方App蜜蜂支付SDK 蜜蜂服务器支付渠道服务器(微信,支付宝)
发起支付请求 发送支付必填信息 申请支付返回支付通道获取支付二维码展示给用户根据支付结果执行操作 通知支付结果 返回支付结果将支付结果推送给第三方app1 2 3456 789,与第7步同时执行
2.2 Manifest 配置
1 2.2.1 必要权限的添加
<uses-permission android:name="NET" /> <uses-permission android:name="S_NETWORK_STATE" /> <uses-permission android:name="_PHONE_STATE" />
<uses-permission android:name="S_WIFI_STATE" />
<uses-permission android:name="_EXTERNAL_STORAGE" />
<uses-permission android:name="_EXTERNAL_STORAGE" />
2.2.2 KEY 值 的填写
将 M anifest 中的【你的 Bee_KEY】替换为您的应用 BEE_KEY,APP_KEY 也进行同样操作;标签在 application 下,其他部分不需改动。配置文件如下所示。
BEE_KEY、APP_KEY 即添加支付配置时,系统给改应用生成的 BEE_KEY 和 APP_KEY。
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".yActivity"
android:screenOrientation="landscape"
android:theme="@android:style/.creen" >
</activity>
<meta-data
android:name="APP_KEY"
android:value=" 你的 APP_KEY" />
<meta-data
android:name="BEE_KEY"
android:value=" 你的 BEE_KEY" />
</application>
2.3 调用页面
拉起支付 Activity 注 :所有参数 均为 为 g String 类型
private String pid; private String pname; private String price; private String pdesc; private String pchannel; private String porder;
private String pextra;
Intent intent = new Intent(); ass(, );
tra(,pid);
//商品id,最大长度为40个字符,必填 tra(,pname); //商品名称,最大长度为60个字符,必填 tra(E,price); //商品价格,必填 tra(,pdesc); //商品描述,最大长度为60个字符,必填 tra(NEL,pchannel); //渠道号,必填 tra(R,porder);//order为订单号数字,可选 tra(A,pextra);//extra为备用字段,可选 startActivityForResult(intent, 0);
2.4 获取返回值
@Override protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
ivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK){
ext(this, "您的商品已经购买成功...", 1).show();
}
if(resultCode==_RESULT_UNKOWN){
ext(this, "未知的状态码...", 1).show();
}
if(resultCode==_RESULT_CLOSE){
ext(this, "订单已经关闭...", 1).show();
} if(resultCode==_RESULT_CANCEL){
ext(this, "订单已经创建,但是用户关闭了支付界面,你需要自己去服务器核对订单是否支付...", 1).show();
}
} resultCode 的值说明 RESULT_OK:成功购买,客户端受到服务器传来的轮询结果 _RESULT_UNKOWN :
未知的结果,需 app 自己取核对结果 _RESULT_CLOSE :
订单关闭了 _RESULT_CANCEL:订单处于轮询状态,但是用户关闭了支付界面,无法收到轮询消息,需自己去查询服务器核对支付结果
2.5 回调接口
要求接入方提供回调地址,SDK 服务端即时推送支付状态至接入方,接入方根据 SDK 服务端的支付状态以及 SDK 客户端的支付状态进行二次确认判断,可在该应用的配置页面填写回调接口 。
2.5.1 回调接口参数说明
mtime
支付时间
start
支付状态
Total_fee
支付金额
Out_trade_no
订单号
User_no
商户订单号
Pay_user
支付标识
Pay_type
支付方式
extra
备用字段
pid
商品 ID
2.5.2 支付状态查询接口 为了防止漏单情况(接入方回调接口调用失败),支付提供支付状态查询接口!
接口链接:
/openApi/n
请求参数列表:
名称 类型 备注 orderNo/porder string SDK 订单号或用户订单号,二选一 appKey string 应用秘钥 sign string 签名数据 orderNo 是 SDK 支付平台这边的订单号;porder 是商户订单号;两者二选一为参数传递给接口;sign 是上面三个参数参与计算的 md5 值,请参考以下 demo:
sign 计算方法及生成订单查询 url:
String appKey="07000fa65";//商户的 appKey String beeKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkcQG90QOXUKon/VmhM/o31SmyzGb4xm3z5Vf94itGZNRNJ6f6MDbnpBeA2GJYAaNtcCxnn5ltb2Mz23KCil+mSm0WbMhNeGvxSlhOonqA+WGbpKmI1AaXWgsMpZpAFV5VAZY86ledsazK7z80s6mqIlbw8M8DDQC8Za9/hnDlmwIDAQAB";//商户的 beeKey String orderNo="s";//商户需要查询 SDK 支付平台订单号 //String porder=”xxxx”;//商户订单号 Map<String,Object> dataMap=new HashMap<String, Object>(); ("appKey",appKey); //(“porder”,porder); ("orderNo",orderNo); String sign= ateSign(dataMap,beeKey); String url=""+eUrlQueryString(dataMap)+"&sign="+sign; ("查询订单 URL:"+url);
SdkSignUtil 签名工具类 package ;
import e.4j.LogManager; import e.4j.Logger;
import .UnsupportedEncodingException;
import .URLEncoder; import geDigest; import hAlgorithmException; import .ArrayList; import .Collections; import .List; import .Map;
public class SdkSignUtil {
private static final Logger log = gger();
/**
* 生成签名验证信息
* @param dataMap
* @param beeKey
* @return
*/
public static String generateSign(Map<String,Object> dataMap,String beeKey) throws UnsupportedEncodingException {
String queryString=createUrlQueryString(dataMap);
queryString+="&beeKey="+beeKey;
("SDK 签名前字符串:"+queryString);
return md5(queryString);
}
public static String createUrlQueryString(Map<String,Object> dataMap) throws UnsupportedEncodingException {
List<String> keys = new ArrayList<String>(t());
(keys);
StringBuilder queryString = new StringBuilder();
for (int i = 0; i < (); i++) {
String key = (i);
Object value = (key);
if (s("sign")) {
continue;
}
d(key + "=" + e(Of(value),"utf-8") + "&");
}
return ring(0, h() - 1);
}
public static String md5(String plainText) {
try {
MessageDigest md = stance("MD5");
md.update(tes());
byte[] b = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
d("0");
d(String(i));
}
return ing();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
} }
2.6 特殊情况说明 若以上步骤中,用户将蜜蜂支付 SDK 关闭后再进行支付,则蜜蜂 SDK 是无法返回支付结果到接入方的 APP,需要接入方自行和 APP 服务器进行支付确认,否则可能会造成无法获得支付结果。
三、 支付流程
注册蜜蜂开发者账号创建应用获得并配置beeKey和appKey填写回调接口和支付应用接入支付sdk打开支付页面Sdk验证appKey和beeKey失败SDK参数传递给服务器通过蜜蜂服务器验证appKey和beeKey返回支付方式通过失败用户扫码支付回调接口通知支付成功成功未支付订单失败
四、 服务器异步通知 用户通过手机扫描二维码进行支付,订单支付成功时会沿着商户预填写的回调通知地址主动推送给商户订单信息
4.1 在蜜蜂市场开发者平台配置应用回调接口
4.2 支付 SDK 平台回调参数:
参数
说明
orderNo
SDK 订单号
pid
商户产品 ID
name 商品名称 price 商品价格,单位为分,1 元==100 分 porder
商户订单号
pextra
商户拓展字段
payTime
支付时间,数据为 long 类型
createTime
订单创建时间,数据为 long 类型 status
订单状态,0:待支付,1:支付成功,2:订单已关闭
sign
签名字段
注:当字段为空时,SDK 平台不会传递该参数,而且也不参与 sign 签名计算
4.3 验证签名规则请参考下面代码:
package ;
import ba.bject;
import e.4j.LogManager; import e.4j.Logger;
import et.ServletException; import et.ervlet; import et.ervletRequest; import et.ervletResponse; import .IOException; import .PrintWriter; import .UnsupportedEncodingException; import .Enumeration; import .HashMap; import .Map;
public class DefaultServlet extends HttpServlet {
private static Logger log= gger();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
aracterEncoding("utf-8");
aracterEncoding("utf-8");
String appKey="ef0bdadf49f3bb88";//商户 appKey
String beeKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUi6FwUPsv4mP2lJC0bi//puIVkyDWHHKyikmmGFNgTipVxY6KdLsFI6R8D4EYhI2Yxh5JDbVpnH1mZmmWYSlZDpUhRo3IvKG0zv02IviTatsR6EJicdWdF5Y9okVDxjWvDz55Rf+LwUisFAzxHt2C97RVV3st0AJIqgPnnfWf7wIDAQAB";//商户 beeKey
ntentType("application/json");
PrintWriter out=iter();
("full url-->"+questURL());
("params--->"+ NString(rameterMap()));
if (!checkSign(request,appKey,beeKey)){
("签名验证不通过!");
ln("{\"code\":199}");
("回调处理失败:{\"code\":199}");
}else {
ln("{\"code\":200}");
("回调处理成功:{\"code\":200}");
}
}
/**
* 验证签名
* @param request
* @return
*/
private boolean checkSign(HttpServletRequest request,String appKey,String beeKey) {
Enumeration keys=rameterNames();
Map<String,Object> dataMap=new HashMap<String, Object>();
("appKey",appKey);
while (reElements()){
String key= (String) lement();
(key,rameter(key));
}
String sign=null;
try {
sign=ateSign(dataMap,beeKey);
} catch (UnsupportedEncodingException e) {
("生成签名字符无法进行 utf-8 编码",e);
return false;
}
if (sIgnoreCase((String) ("sign"))){
return true;
}
("签名不一致,"+sign+"--->"+("sign"));
return false;
} }