1、华为支付相对微信支付又复杂点,同样包名,签名,appId都必须正确,不能修改
2、配置内容也多点,不过基本按照文档说明认真配置也是没问题的
3、华为支付是没demo源码参考,只有文档的示例代码,其他第三方一般都会有demo的
官方开发文档
https://developer.huawei.com/consumer/cn/service/hms/catalog/huaweiiap_oversea.html?page=hmssdk_huaweiiap_devprepare_oversea
按照文档一步步来,千万不要跳步骤,要不出问题不好排查
可能出问题的地方
在清单的application节点下增加APPID
android:value="appid=xxx">
记住里面是appid=xxx而不是去掉xxx
初始化Agent
1.在Application类中的onCreate方法中初始化HMS Agent套件
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HMSAgent.init(this);
}}
2.请务必在应用启动后的首个activity的onCreate方法中调用connect接口,确保HMS SDK和HMS APK的连接
HMSAgent.connect(this, new ConnectHandler() {
@Override
public void onConnect(int rst) {
showLog("HMS connect end:" + rst);
}});
注意是启动的第一个activity,要不会上架审核不成功的
调起华为支付
关键方法HuaweiPay.HuaweiPayApi.pay();
只好建个中间的Activity来集成,因为支付返回结果都是在onActivityResult获取。如果只有一个界面有华为支付的,就没必要了。
中间华为支付activity
示例代码:
public abstract class HuaWeiActivity> extends BaseActivity implements ISetHw {
private static final String TAG = HuaWeiActivity.class.getName();
public HuaweiApiClient client;
private String outTradeNo;
//启动参数,区分startactivityforresult的处理结果
private final int REQ_CODE_PAY = 4001;
//作用同startactivityforresult方法中的requestcode
private static final int REQUEST_HMS_RESOLVE_ERROR = 1000;
private ShowPayDialog showPayDialog;
//初始化init华为支付
private void initClient() {
//-------------------华为支付----------------------
if(null == client){
client = new HuaweiApiClient.Builder(this)
.addApi(HuaweiPay.PAY_API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
}
client.connect(this);
}
@Override
public void onResume() {
super.onResume();
initClient();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != client) {
client.disconnect();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LogUtils.i("reCode", requestCode + " " + resultCode + "");
if (requestCode == REQUEST_HMS_RESOLVE_ERROR) {
if (resultCode == Activity.RESULT_OK) {
int result = data.getIntExtra(EXTRA_RESULT, 0);
if (result == ConnectionResult.SUCCESS) {
LogUtils.i(TAG, "错误成功解决");
if (!client.isConnecting() && !client.isConnected()) {
client.connect(this);
}
} else if (result == ConnectionResult.CANCELED) {
LogUtils.i(TAG, "解决错误过程被用户取消");
} else if (result == ConnectionResult.INTERNAL_ERROR) {
LogUtils.i(TAG, "发生内部错误,重试可以解决");
//CP可以在此处重试连接华为移动服务等操作,导致失败的原因可能是网络原因等
} else {
LogUtils.i(TAG, "未知返回码");
}
} else {
LogUtils.i(TAG, "调用解决方案发生错误");
}
} else if (requestCode == REQ_CODE_PAY) {
//当返回值是-1的时候表明用户支付调用成功
if (resultCode == Activity.RESULT_OK) {
//获取支付完成信息
PayResultInfo payResultInfo = HuaweiPay.HuaweiPayApi.getPayResultInfoFromIntent(data);
if (payResultInfo != null) {
Map paramsa = new HashMap();
if (PayStatusCodes.PAY_STATE_SUCCESS == payResultInfo.getReturnCode()) {
//mHuaWeiPayPresenter.getHwPayNotify(b_tag, payResultInfo.getRequestId(), payResultInfo.getReturnCode(), success);
payHwSuccessNotify(payResultInfo.getReturnCode());
//paySuccess();
closeDialog();
} else if (PayStatusCodes.PAY_STATE_CANCEL == payResultInfo.getReturnCode()) {
//支付失败,原因是用户取消了支付,可能是用户取消登录,或者取消支付
Log.i(TAG, "支付失败:用户取消" + payResultInfo.getErrMsg());
payHwFailNotify();
} else {
//支付失败,其他一些原因
Log.i(TAG, "支付失败:" + payResultInfo.getErrMsg() + payResultInfo.getReturnCode());
payHwFailNotify();
}
} else {
//支付失败
payHwFailNotify();
}
} else {
//当resultCode 为0的时候表明用户未登录,则CP可以处理用户不登录事件
Log.i(TAG, "resultCode为0, 用户未登录 CP可以处理用户不登录事件");
}
}
}
protected abstract void payHwSuccessNotify(int payCode);
protected abstract void payHwFailNotify();
@Override
public void onConnected() {
}
@Override
public void onConnectionSuspended(int i) {
//HuaweiApiClient异常断开连接, if 括号里的条件可以根据需要修改
if (!this.isDestroyed() && !this.isFinishing()) {
client.connect(this);
}
LogUtils.i(TAG, "HuaweiApiClient 连接异常断开成功");
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
LogUtils.i(TAG, "HuaweiApiClient连接失败,错误码:" + connectionResult.getErrorCode());
if (HuaweiApiAvailability.getInstance().isUserResolvableError(connectionResult.getErrorCode())) {
final int errorCode = connectionResult.getErrorCode();
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
// 此方法必须在主线程调用, xxxxxx.this 为当前界面的activity
HuaweiApiAvailability.getInstance().resolveError(HuaWeiActivity.this, errorCode, REQUEST_HMS_RESOLVE_ERROR);
}
});
} else {
//其他错误码请参见API文档
}
}
/**
* 发起支付流程,开发者可以直接参照该方法写法
*/
protected void hwPay(HashMap params, String sign) {
if (!client.isConnected()) {
LogUtils.i(TAG, "支付失败,原因:HuaweiApiClient未连接");
client.connect(this);
return;
}
PendingResult payResult = HuaweiPay.HuaweiPayApi.pay(client, HwPayUtils.createPayReq(params, sign));
payResult.setResultCallback(new PayResultCallback());
}
/**
* 弹框相关
*
* @param showPayDialog
*/
public void setShowDialog(ShowPayDialog showPayDialog) {
this.showPayDialog = showPayDialog;
}
/**
* 支付接口调用的回调处理
* 只有当处理结果中的返回码为 PayStatusCodes.PAY_STATE_SUCCESS的时候,CP需要继续调用支付
* 否则就需要处理支付失败结果
*/
private class PayResultCallback implements ResultCallback {
@Override
public void onResult(PayResult result) {
//支付鉴权结果,处理result.getStatus()
Status status = result.getStatus();
if (PayStatusCodes.PAY_STATE_SUCCESS == status.getStatusCode()) {
//当支付回调 返回码为0的时候,表明支付流程正确,CP需要调用startResolutionForResult接口来进行后续处理
//支付会先判断华为帐号是否登录,如果未登录,会先提示用户登录帐号。之后才会进行支付流程
try {
status.startResolutionForResult(HuaWeiActivity.this, REQ_CODE_PAY);
} catch (IntentSender.SendIntentException e) {
LogUtils.i(TAG, "启动支付失败" + e.getMessage());
}
} else {
LogUtils.i(TAG, "支付失败,原因 :" + status.getStatusCode());
}
}
}
public void closeDialog() {
if (null != showPayDialog) {
showPayDialog.dialogDismiss();
}
}}
仅仅是示例,把不用的删掉即可,
其中HuaweiPay.HuaweiPayApi.pay是调起华为支付,
PayResultCallback是是否能正常调起华为支付,
onActivityResult是调起后支付成功还是失败
HwPayUtils类
public class HwPayUtils {
private static final String TAG = "HwPayUtils";
/**
* 获取华为的appId
*
* @param context
* @return
*/
public static String getAppId(Context context) {
String value = "";
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(),
PackageManager.GET_META_DATA);
value = appInfo.metaData.getString("com.huawei.hms.client.appid");
String[] appidValue = value.split("=");
return appidValue[appidValue.length-1];
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return value;
}
/**
* 生成支付信息map 包含
* HwPayConstant.KEY_MERCHANTID 必选参数 商户id,开发者联盟网站生成的支付ID
* HwPayConstant.KEY_APPLICATIONID 必选参数 应用的appid,开发者联盟网站生成
* HwPayConstant.KEY_AMOUNT 必选参数 支付金额 string类型,精确到小数点后2位 比如 20.00
* HwPayConstant.KEY_PRODUCTNAME 必选参数 商品名称 此名称将会在支付时显示给用户确认 注意:该字段中不能包含特殊字符,包括# " & / ? $ ^ *:) ,
* HwPayConstant.KEY_PRODUCTDESC 必选参数 商品描述 注意:该字段中不能包含特殊字符,包括# " & / ? $ ^ *:) , |
* HwPayConstant.KEY_REQUESTID 必选参数 请求订单号。其值由商户定义生成,用于标识一次支付请求,每次请求需唯一,不可重复。
* 支付平台在服务器回调接口中会原样返回requestId的值。注意:该字段中不能包含特殊字符,包括# " & / ? $ ^ *:) , .以及中文字符
* HwPayConstant.KEY_SDKCHANNEL 必选参数 渠道信息。 取值如下:0 代表自有应用,无渠道 1 代表应用市场渠道 2 代表预装渠道 3 代表游戏中心渠道
* HwPayConstant.KEY_URLVER 可选参数 回调接口版本号。如果传值则必须传2, 额外回调信息,具体参考接口文档
* HwPayConstant.KEY_URL 可选参数 支付结果回调URL. 华为服务器收到后检查该应用有无在开发者联盟配置回调URL,如果配置了则使用应用配置的URL,否则使用此url
* 作为该次支付的回调URL,建议直接 以配置在 华为开发者联盟的回调URL为准
* HwPayConstant.KEY_COUNTRY 可选参数 国家码.建议无特殊需要,不传
* HwPayConstant.KEY_CURRENCY 可选参数 币种 选填.建议无特殊需要不传此参数。目前仅支持CNY,默认CNY
*/
public static HashMap getPayInfo(PayHwOrderResult result) {
HashMap params = new HashMap();
PayHwOrderResult.DataBean obj = result.getData();
params.put(HwPayConstant.KEY_MERCHANTID, obj.getMerchantId());
params.put(HwPayConstant.KEY_APPLICATIONID, obj.getAppId());
params.put(HwPayConstant.KEY_AMOUNT, obj.getAmount());
params.put(HwPayConstant.KEY_PRODUCTNAME, obj.getProductName());
params.put(HwPayConstant.KEY_PRODUCTDESC, obj.getProductDesc());
params.put(HwPayConstant.KEY_REQUESTID, obj.getOutTradeNo());
params.put(HwPayConstant.KEY_SDKCHANNEL, obj.getSdkChannel());
params.put(HwPayConstant.KEY_URLVER, obj.getUrlver());
params.put(HwPayConstant.KEY_URL, obj.getUrl());
//不需要签名参数
params.put(HwPayConstant.KEY_MERCHANTNAME, obj.getMerchantName());
params.put(HwPayConstant.KEY_SERVICECATALOG, obj.getServiceCatalog());
params.put(HwPayConstant.KEY_EXTRESERVED, obj.getExtReserved());
return params;
}
/**
* 封装json参数给后台
*
* @param params
* @return
*/
public static String paramJson(HashMap params) {
String value = "";
try {
JSONObject mJsonobjData = new JSONObject();
mJsonobjData.put(HwPayConstant.KEY_MERCHANTID, params.get(HwPayConstant.KEY_MERCHANTID));
mJsonobjData.put(HwPayConstant.KEY_APPLICATIONID, params.get(HwPayConstant.KEY_APPLICATIONID));
mJsonobjData.put(HwPayConstant.KEY_AMOUNT, params.get(HwPayConstant.KEY_AMOUNT));
mJsonobjData.put(HwPayConstant.KEY_PRODUCTNAME, params.get(HwPayConstant.KEY_PRODUCTNAME));
mJsonobjData.put(HwPayConstant.KEY_PRODUCTDESC, params.get(HwPayConstant.KEY_PRODUCTDESC));
mJsonobjData.put(HwPayConstant.KEY_REQUESTID, params.get(HwPayConstant.KEY_REQUESTID));
mJsonobjData.put(HwPayConstant.KEY_SDKCHANNEL, params.get(HwPayConstant.KEY_SDKCHANNEL));
mJsonobjData.put(HwPayConstant.KEY_URLVER, params.get(HwPayConstant.KEY_URLVER));
mJsonobjData.put(HwPayConstant.KEY_URL, params.get(HwPayConstant.KEY_URL));
value = mJsonobjData.toString();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return value;
}
/**
* 生成PayReq对象,用来在进行支付请求的时候携带支付相关信息
* payReq订单参数需要商户使用在华为开发者联盟申请的RSA私钥进行签名,强烈建议将签名操作在商户服务端处理,避免私钥泄露
*/
public static PayReq createPayReq(HashMap params, String sign) {
PayReq payReq = new PayReq();
//商品名称
payReq.productName = (String) params.get(HwPayConstant.KEY_PRODUCTNAME);
//商品描述
payReq.productDesc = (String) params.get(HwPayConstant.KEY_PRODUCTDESC);
// 商户ID:来源于开发者联盟的“支付ID”
payReq.merchantId = (String) params.get(HwPayConstant.KEY_MERCHANTID);
// 应用ID
payReq.applicationID = (String) params.get(HwPayConstant.KEY_APPLICATIONID);
// 支付金额
payReq.amount = (String) params.get(HwPayConstant.KEY_AMOUNT);
// 商户订单号:开发者在支付前生成,用来唯一标识一次支付请求
payReq.requestId = (String) params.get(HwPayConstant.KEY_REQUESTID);
// 渠道号
payReq.sdkChannel = (Integer) params.get(HwPayConstant.KEY_SDKCHANNEL);
// 回调接口版本号
payReq.urlVer = (String) params.get(HwPayConstant.KEY_URLVER);
payReq.url = (String) params.get(HwPayConstant.KEY_URL);
LogUtils.i("hwPayUrl",payReq.url);
LogUtils.i(TAG, payReq.productName + " " + payReq.productDesc + " " + payReq.merchantId + " " + payReq.applicationID + " "
+ payReq.amount + " " + payReq.requestId + " " + payReq.sdkChannel + " " + payReq.getUrlVer());
//以上信息按照一定规则进行签名,建议CP在服务器端储存签名私钥,并在服务器端进行签名操作。
payReq.sign = sign;
// 商户名称,必填,不参与签名。开发者注册的公司名
payReq.merchantName = (String) params.get(HwPayConstant.KEY_MERCHANTNAME);
//分类,必填,不参与签名。该字段会影响风控策略
// X4:主题,X5:应用商店, X6:游戏,X7:天际通,X8:云空间,X9:电子书,X10:华为学习,X11:音乐,X12 视频,
// X31 话费充值,X32 机票/酒店,X33 电影票,X34 团购,X35 手机预购,X36 公共缴费,X39 流量充值
payReq.serviceCatalog = (String) params.get(HwPayConstant.KEY_SERVICECATALOG);
//商户保留信息,选填不参与签名,支付成功后会华为支付平台会原样 回调CP服务端
payReq.extReserved = (String) params.get(HwPayConstant.KEY_EXTRESERVED);
return payReq;
}
/**
* 将商户id,应用id, 商品名称,商品说明,支付金额,订单号,渠道号,回调地址版本号等信息按照key值升序排列后
* 以key=value并以&的方式连接起来生成待签名的字符串
*
* @return
*/
public static String getNoSign(Map params) {
//对参数按照key做升序排序,对map的所有value进行处理,转化成string类型
//拼接成key=value&key=value&....格式的字符串
StringBuffer content = new StringBuffer();
// 按照key做排序
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
String value = null;
Object object = null;
for (int i = 0; i