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

iOS集成Adyen HPP支付一直提示merchant signature not valid错误如何解决

问题描述

我正尝试通过HPP方式在iOS中集成Adyen支付,持续出现Merchant signature was not valid报错,我怀疑是编码环节存在问题。

iOS端原代码片段

var urlComponents = URLComponents()
urlComponents.queryItems = []
let contentKeys1: [String] = Array(content.keys)
for contentKey in contentKeys1 {
    if let contentValue = content[contentKey] {
        urlComponents.queryItems?.append(URLQueryItem(name: contentKey, value: contentValue))
    }
}
self.httpBody = urlComponents.query?.data(using: .utf8)

Android端同款逻辑运行正常,我将Android生成的请求字符串拿到iOS侧测试,支付页面可以正常打开无报错。

Android端参考代码片段

val query = StringBuilder()
if (providerDataset != null) {
  for (providerData: ProviderData in providerDataset) {
      val key = providerData.key
      var value: String? = ""
      try {
           if (providerData.value != null)
               value = URLEncoder.encode(providerData.value, StandardCharsets.UTF_8.toString())
      } catch (e: UnsupportedEncodingException) {
           e.printStackTrace()
      }
      val str = "$key=$value"
      query.append(str).append("&")
  }
}
return query.deleteCharAt(query.length - 1).toString()

请问iOS侧有没有可以实现和上述Android代码相同效果的编码方法?

Adyen报错截图

解决方案

问题根因是iOS系统的URLComponents默认的query编码规则不符合application/x-www-form-urlencoded标准要求,和Android端使用的URLEncoder.encode编码结果不一致,导致Adyen签名校验失败。具体差异点在于URLComponents不会把空格编码为+,也不会对~、/等特殊字符做编码,而Adyen的签名生成逻辑是严格按照表单编码规则处理的。

可以通过自定义编码规则对齐Android端实现,替换原有生成请求体的逻辑即可:

// 先给String加自定义编码扩展
extension String {
    func adyenFormEncoded() -> String {
        let allowedCharacters = CharacterSet(charactersIn: "*-._0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
        return self.addingPercentEncoding(withAllowedCharacters: allowedCharacters)?
            .replacingOccurrences(of: " ", with: "+") ?? ""
    }
}

// 替换原有的请求体生成逻辑
var queryItems: [String] = []
let contentKeys = Array(content.keys)
for contentKey in contentKeys {
    if let contentValue = content[contentKey] {
        let encodedKey = contentKey.adyenFormEncoded()
        let encodedValue = contentValue.adyenFormEncoded()
        queryItems.append("\(encodedKey)=\(encodedValue)")
    }
}
let queryString = queryItems.joined(separator: "&")
self.httpBody = queryString.data(using: .utf8)

上述实现和Android端URLEncoder.encode逻辑完全一致,生成的请求参数和Android端无差异,即可解决签名校验失败的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:00:02