Skip to content

1711680493/SPay

Repository files navigation



个人也可实现在线支付



前言

本APP是为了解决个人无法接入在线支付的问题,接入第三方支付需要经营许可证,如微信、支付宝。除此之外还有一些中间商代理的方式(手续费高)

这些方法对于个人小打小闹来说行不通,于是改变思路,直接通过收款码方式收款,通过监听APP通知的方式知晓知否支付,这样也可以实现类似效果,仅供学习交流


优点

  • 不需要任何资质
  • 无手续费
  • 相比接入更简单

缺点

  • APP需要一直打开,并一直在线(手机基本上都是一直打开,问题不大)
  • 不能指定固定金额,需要用户手动输入(不怕麻烦可以生成固定金额的二维码,可能有其他更好的方法)
  • 因使用监听通知的方式,必须要有通知,当手机打开微信/支付宝时,可能不会发送通知,可能存在漏单情况,比如通知内容有更改等,需要有反馈入口以及手动完成此笔交易功能。
  • 不能同一时间有两笔相同金额的订单,因为无法知晓支付对应的是哪笔订单,需要有排队机制,或随机增加0.01或减少0.01等方式解决。
  • 可能在支付时收到其他款项,金额与订单金额一致,导致用户没有付款但通知服务器的情况。
  • 支付只能通过扫二维码(后续再看有没有其他办法)


体验

可通过以下链接进行体验,其中支付的金额就当赞赏咯~

https://pay.sdpro.top/spay.html



流程与设计

用户下单,服务端创建订单,用户付款后,APP监听到通知,将金额发送至服务端,服务端进行验证处理。

在设计上,为了确保安全性,应有验证机制。

验证:生成一串密钥,手动配置到服务端与APP,APP在监听到通知携带此密钥与当前时间戳发送至服务端,服务端验证密钥与时间戳,以确认请求是当前APP,应隔一段时间更新此密钥。



服务端接口

目前需要两个接口,一个是获取APP基本信息的接口,一个是服务端用于接收支付通知,url都在APP上动态设置。

可通过APP的测试模块来测试对应接口


基础信息接口

为了方便使用,配置信息放置在服务端上,所以首先需要拿到基础信息。

因是监听通知的方式,通知字符串内容可能会有改变,所以将其作为配置来增加可用性


接口请求类型 GET,无需参数与验证,只需请求url即可获取基础信息(使用SSL来说,相对安全,而且基础信息并不需要保密)

微信将金额信息放到通知内容中,支付宝将金额信息放到通知标题中,所以如下设计

接口响应类型为JSON,数据如下

{
    // 状态码,10000为成功
    "code" : "10000",
    // 数据,获取成功则为下方数据,失败则为错误提示.
    "msg" : {
        // 确认字符串为支付字符串的配置
        "paystr" : {
            // 格式为 类型:内容,下方是微信的示例
            "微信" : {
                // v1.0.1新增,是否上交服务器,默认true
                "isUp" : true,
                // app包名,数组中的都将匹配
                "packName" : ["com.tencent.mm"],
                // 匹配通知与截取金额的信息列表
                "list" : [
                    // 为兼容通知标题与内容都可能携带金额的情况,将按顺需依次处理下方JSON对象
                    {
                        // 金额是在通知标题还是在内容,true代表在标题 false代表在内容
                        "isTitle" : false,
                        // 通知内容的字符串匹配,将截取start与end之间的内容,如果有.
                        // (截取的金额将被转double,转换失败则代表非支付)
                        // 例如微信支付是:(微信支付收款xxx元),那么可以如下.
                        // (如果是以金额开头,那么start为"",如果是以金额结尾,那么end为"")
                        "start" : "微信支付收款",
                        "end" : "",
                        // v1.0.2新增,校验标题和校验内容,可选
                        // 存在的话会判断标题/内容是否包含指定内容,不包含则匹配失败,空字符串等价于不存在
                        "checkTitle" : "微信支付",
                        "checkContent" : ""
                    },
                    {
                        "isTitle" : false,
                        "start" : "收款",
                        "end" : ""
                    }
                ]
            }
        },
        "purl" : "支付回调接口的地址"
    }
}

注意事项

不知从什么时候开始(目前发现问题是2024-06-09),微信的通知进行了更改,带上了一个¥符号,需要注意,配置中符号的编码(UTF-8),这个符号是两个横线的,如果是ASCII等其他编码,将无法正确匹配。

后面不知道是否还有更改,但这里需要注意的就是编码,以及匹配的start和end字符是需要与通知中的字符是完全一致的


支付回调接口

接口请求类型 POST

需要接收以下参数

参数名 描述
amount 金额,单位分(这样不易出现精度丢失问题)
type 基础信息中匹配的类型,例如 微信
priKey 配置在服务端与APP上的密钥,这是自行生成的
time 提交此请求的时间戳

拿到参数后首先要验证priKeytime,密钥正确,时间差合理(比如在订单失效期前支付,失效期两分钟,那么设置为两分半即可)则代表此次请求是APP所发送。

而后通过amounttype来确认对应的订单,完成支付。(如果没有订单那可能代表此请求不是APP所发送,需要记录日志并提醒开发者,让其更新密钥)


接口响应如下,用于APP记录此次请求。

{
    "code" : "10000",
    "msg" : "当code非10000时,此为错误信息,将在APP上可见"
}


时区

在 1.0.1 版本,默认时区为 GMT+08:00



使用

打开APP会自动跳转开启通知权限,将其开启,可在测试中进行发送通知测试。


开启监听通知权限

高版本的Android需要手动开启,这个没办法,否则无法监听通知。

可通过APP - 测试 - 开启测试通知,然后发送通知来测试是否可以监听到通知,如果不能监听,那么就需要开启监听通知权限,具体操作如下。

打开手机上的设置,在最上方的搜索框输入通知,点击通知使用权,找到当前APP,开启(我的是OPPO手机,不同手机可能开启方式不一样),应用管理 -> 特殊应用权限 -> 通知使用权

经测试,当已安装APP且打开使用权后,更新版本,需要关闭通知使用权然后重新打开。


加入白名单

为了让APP不被系统优化,需要将当前APP加入白名单,不同手机操作方法不同,但大致类似。

设置中

电池 -> 应用耗电管理 -> SPay -> 允许完全后台行为,允许应用自启动,允许应用关联启动

应用管理 -> 自启动管理 -> SPay打开

应用管理 -> 关联启动管理 -> SPay打开


打开最近任务(底部有三按键点击正方形那个,如果是左右滑动上一级的在底部往上滑),给打开的SPay加个锁定


配置

打开 SPay APP,点击设置,输入基础信息接口地址后点击设置与更新,输入密钥信息后点击设置

对于基础信息接口地址,我制作了一份JSON放置我的服务器上,可供测试: https://sdpro.top/json/spay_test_base.json

JSON内容如下

{
    "code" : "10000",
    "msg" : {
        "paystr" : {
            "SPay" : {
                "packName" : ["shendi.pay"],
                "list" : [
                    {
                        "isTitle" : false,
                        "start" : "测试支付收款",
                        "end" : ""
                    }
                ]
            },
            "微信" : {
                "packName" : ["com.tencent.mm"],
                "list" : [
                    {
                        "isTitle" : false,
                        "start" : "微信支付收款",
                        "end" : ""
                    }
                ]
            }
        },
        "purl" : "支付回调接口的地址"
    }
}

在APP的测试页面中,通知部分,通知标题输入测试支付,通知内容输入测试支付收款1.11元,而后即可在记录与通知页面中看到效果。



手动支付

如果手机是正在打开微信,在这个时候,用户使用微信扫码支付,那么微信将不会发送系统通知,于是APP就无法自动处理,导致用户在线支付失败。

为了解决这种情况,在 APP 的测试页面中,支付回调接口部分,提供了一个 使用配置测试 的按钮,即我们知晓用户付款了多少金额,知晓支付类型,输入后点击按钮同样将请求服务端的回调接口,这是一种补救办法。

但对于服务端来说,拥有操作超时时间,对于服务端设计,实际超时时间应该大于用户超时时间20秒。以及手动操作需要在失效期前。


除此之外,还可以发展到其他场景,例如线上虚拟商品,但线下收款,通过手动支付进行核销...