You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 Key
  • TOKEN_URL:https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials
  • STK_PUSH_URL:https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest
  • CALLBACK_URL:可公网访问的回调地址(可使用ngrok临时生成)

完成以上修改后,查看Logcat中的日志即可获取具体错误信息,进一步定位问题。

内容的提问来源于stack exchange,提问作者Irene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:26:04