Android Java集成Daraja API支付失败:无法唤起沙箱弹出错误Toast
Daraja API支付失败问题排查与修复
以下是针对你代码中可能导致支付失败的问题分析及修复方案:
1. 补充响应日志与错误详情获取
当前代码在支付请求的onResponse中仅处理了失败情况,且未输出任何错误详情,无法定位具体问题。修改initiatePayment中的回调逻辑:
@Override public void onResponse(Call call, Response response) throws IOException { String responseBody = response.body().string(); Log.d("MpesaDebug", "API Response: " + responseBody); // 打印完整响应日志 if (!response.isSuccessful()) { try { JSONObject errorJson = new JSONObject(responseBody); String errorMessage = errorJson.optString("errorMessage", "Unknown error"); callback.onAccessTokenError(new IOException("Failed to initiate payment: " + errorMessage)); } catch (JSONException e) { callback.onAccessTokenError(new IOException("Failed to initiate payment: " + response.message())); } } else { Log.d("MpesaDebug", "Payment initiated successfully"); } }
同时在PaymentActivity的错误回调中打印完整错误栈:
@Override public void onAccessTokenError(Throwable error) { runOnUiThread(new Runnable() { @Override public void run() { Log.e("PaymentError", error.getMessage(), error); // 打印错误详情 Toast.makeText(PaymentActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_LONG).show(); } }); }
2. 修正金额格式
Daraja API要求金额为整数(单位:肯先令),需确保传递的是整数值:
// 在initiatePayment中修改Amount字段 requestJson.put("Amount", (int)Math.round(amount));
3. 使用JSONObject构建请求体避免语法错误
手动拼接JSON容易出现语法错误,改用JSONObject构建:
private void initiatePayment(double amount, String formattedPhone, String accessToken, AccessTokenCallback callback) { SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.ENGLISH); String timestamp = format.format(new Date()); String password = generatePassword(timestamp); JSONObject requestJson = new JSONObject(); try { requestJson.put("BusinessShortCode", Constants.BUSINESS_CODE); requestJson.put("Password", password); requestJson.put("Timestamp", timestamp); requestJson.put("TransactionType", "CustomerPayBillOnline"); requestJson.put("Amount", (int)Math.round(amount)); requestJson.put("PartyA", formattedPhone); requestJson.put("PartyB", Constants.BUSINESS_CODE); requestJson.put("PhoneNumber", formattedPhone); requestJson.put("CallBackURL", Constants.CALLBACK_URL); requestJson.put("AccountReference", Constants.BUSINESS_CODE); requestJson.put("TransactionDesc", "Test"); } catch (JSONException e) { callback.onAccessTokenError(e); return; } RequestBody body = RequestBody.create(requestJson.toString(), JSON); // 后续请求代码不变 }
4. 优化手机号处理逻辑
确保手机号格式正确,兼容多种输入格式:
public void processPayment(double amount, String phone, AccessTokenCallback callback) { String formattedPhone = phone.trim(); // 处理带+号的情况 if (formattedPhone.startsWith("+")) { formattedPhone = formattedPhone.substring(1); } // 转换为254开头的格式 if (formattedPhone.startsWith("0")) { formattedPhone = "254" + formattedPhone.substring(1); } else if (!formattedPhone.startsWith("254")) { callback.onAccessTokenError(new RuntimeException("Invalid phone number format")); return; } // 验证长度是否正确 if (formattedPhone.length() != 12) { callback.onAccessTokenError(new RuntimeException("Phone number must be 10 digits (0xxxxxxxxx) or 12 digits (254xxxxxxxxx)")); return; } // 后续获取token逻辑不变 }
同时更新手机号验证方法:
private boolean isValidPhoneNumber(String phoneNumber) { return phoneNumber.matches("(\\+254|254|0)\\d{9,10}"); }
5. 检查Constants配置
确保Constants类中的以下参数与Daraja沙箱配置一致:
CONSUMER_KEY和CONSUMER_SECRET:开发者门户沙箱凭据BUSINESS_CODE:沙箱PayBill号码(默认174379)PASS_KEY:沙箱提供的Pass KeyTOKEN_URL:https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentialsSTK_PUSH_URL:https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequestCALLBACK_URL:可公网访问的回调地址(可使用ngrok临时生成)
完成以上修改后,查看Logcat中的日志即可获取具体错误信息,进一步定位问题。
内容的提问来源于stack exchange,提问作者Irene
相关产品推荐
相关产品推荐

