字节跳动小程序(抖音) uniapp PHP 支付宝SDK 开发支付功能

目录

前提条件

正文

代码流程: 

详细代码

 一、获取字节跳动订单

二、获取支付宝alipay_url参数

 三、开始生成orderInfo 给前端吊起支付宝咯

总结哈 keke



前提条件

字节跳动:

  1. API 支付支持版本(不拉起收银台,直接拉起微信/支付宝):今日头条(iOS & Android)7.4.3+版本;抖音 iOS 9.1.0+版本 / Android 8.7.0+版本
  2. 字节跳动开放平台 -> 基础设置 -> 企业认证完成 -> 将所有信息填写好
  3. 开发管理->开发设置 -> 小程序Key&服务器域名配置好
  4. 字节跳动开放平台 -> 功能管理 -> 支付 -> 收银台支付 完成信息填写(图片真的找不到原图抱歉) 填写之后 这个样儿
  5. 提交一个测试版(用于支付宝APP签约)

支付宝:

  1. 注册支付宝开放平台账号并完成企业认证
  2. 开发者中心控制台->我的应用中创建网页&移动应用->支付接入; 填入名称与抖音小程序相同->选择网页应用->url无所谓
  3. 在能力列表中添加能力选择APP支付; 选择确认后需要签约, 此处签约的APP名称一定要填写测试版字节跳动小程序的名称(必须), 其他的看着填写(最好有截图放到word中上传)
  4. 签约完成后需要在应用信息中设置接口加签方式(选RSA2接口加密方式自己百度很简单) 保存下载好任何可以下载的文件; 授权回调地址用来接收支付宝验签用暂时不管他

正文

工作中用到抖音小程序与支付宝开发 记录一次摸(cai)索(keng)过程 ! 

首先要梳理下思路:  要区分为两个部分{ 支付宝 , 字节跳动 } 本文需要通过 字节跳动的 tt.pay 前端方法 吊起支付宝支付

一定要看好前提条件, 不然很容易乱

 

代码流程: 

大概过程: 前端请求服务端接口, 服务端返回orderInfo

服务端生成的orderInfo过程:

1、获取字节跳动签名(sign)

2、获取支付宝的alipay_url 

3、组合参数 orderInfo 给前端

 

 

 

详细代码

 一、获取字节跳动订单

  1. 抖音用户授权登录(需要Openid)
  2. 获取字节跳动订单 , 此处需要创建自定义订单信息 (随便写除了openid)  我的代码   -----------获取字节跳动订单-----------
    //------------------自定义订单信息--------------------------
    $data = [
       'out_order_no' => date('Ymd') . $time, //随便搞个订单号
       'openid' => $userinfo['openid'],       //抖音用户openid
       'fee' => '1',                          //金额 单位:分!分!分!
       'cid' => $cid,                         
       'time' => $time,
       'body' => '123',                        //支付的内容(支付宝)
       'subject' => '456',                     //支付的标题(支付宝)
        //body 和 subject 刚开始先用数字(中文会有其他问题)
    ];
    //------------------自定义订单信息--------------------------
    
    //TP5框架 fastadmin
    //------------------组合请求sign信息--------------------------
    //↓↓↓获取用户真实IP
    $risk_info = request()->ip();    
    //↓↓↓头条支付分配给业务方的ID(不是头条小程序的appid)
    $payload['app_id'] = $this->config['tt_pay_app_id'];
    //↓↓↓头条支付分配给业务方的支付秘钥
    $app_secret = $this->config['tt_pay_app_secret'];     
    //↓↓↓请求使用的编码格式
    $payload['charset'] = "utf-8";
    //↓↓↓接口名称               
    $payload['method'] = "tp.trade.create";     
    //↓↓↓发送请求的时间
    $payload['timestamp'] = $time;        
    // 请求参数的集合   json     
    $biz_content = [
        //商户订单号
        "out_order_no" => $data['out_order_no'],
        //唯一标识用户open_id        
        "uid" => $data['openid'],               
        //金额,分为单位,应传整型 
        "total_amount" => $data['fee'], 
        //商户订单名称           
        "subject" => $data['subject'],    
        //商户订单详情            
        "body" => $data['body'],      
        //头条支付分配给业务方的商户号          
        "merchant_id" => $this->config['merchant_id'], 
        //货币种类
        "currency" => "CNY",                        
        //下单时间戳
        "trade_time" => $time,               
        //订单有效时间(此处测试 时间留的长)     单位:秒
        "valid_time" => "3000",        
        //服务器异步通知地址尽量https 没试过http 
        "notify_url" => 'https://**********.com/api/pay/verificationSign',   
        //用户的真实ip 一定要json序列化
        "risk_info" => json_encode(['ip' => $risk_info]),           
    ]; 
    $payload['biz_content'] = json_encode($biz_content);
    //字节跳动采用的是MD5加密
    $payload['sign_type'] = "MD5";        
    $payload['format'] = "json";
    $payload['version'] = "1.0";
    //这里写了一个签名的方法, 千万别乱, 此处签名用来请求的, 与其他签名没有任何关联;(共3个签名)
    $stringToBeSigned = $this->getSignContent($payload, $payload['charset']);    
    $payload["sign"] = md5($stringToBeSigned . $app_secret);
    
    $url = "https://tp-pay.snssdk.com/gateway"; // 请求地址正式环境
    $result = $this->curl($url, $payload);
    /*返回示例:
    {"response":{"code":"10000","msg":"Success","trade_no":"SP2020081509594510822988870791"},"sign":"E7RRJSJCVAhA4DMyMPr/Q1IOc1RKpyQNikl9l8b3ObW6dAYzep7rK6wY5YVjSubhmINsI0iWb/cu+YCqp1D+amifkXh4nX2JG3D0xgi2eWJrTv3Ou27zuEPbEb5y10SBG1f4QCYoa7r2upmOL5xbjY6kG5iDPjiS4JIthsojR5Q="}*/
    $result = json_decode($result, true);
    
    //------------------组合请求sign信息--------------------------
    
    

    ------------------------------------------------------------------获取字节跳动签名------------------------------------------------------------------

  3. 返回值{"response":{"code":"10000","msg":"Success","trade_no":"SP2020081509594510822988870791"},"sign":"E7RRJSJCVAhA4DMyMPr/Q1IOc1RKpyQNikl9l8b3ObW6dAYzep7rK6wY5YVjSubhmINsI0iWb/cu+YCqp1D+amifkXh4nX2JG3D0xgi2eWJrTv3Ou27zuEPbEb5y10SBG1f4QCYoa7r2upmOL5xbjY6kG5iDPjiS4JIthsojR5Q="}    trade_no(订单号)留着用哈

二、获取支付宝alipay_url参数

  1. 我用的是支付宝sdk中证书方法生成 alipay_url 
  2. 下载支付宝sdk 点我下载  tp5将aop文件夹放到vendor ;   生成支付宝alipay_url 上代码:
    //阿里url证书
    public function aliUrlZhengshu($data)
    {
        //需要在AopCertClient.php文件中加入 
        //namespace app\api\controller;
        //use think\Exception;
        //引入文件 用来实例化
        require_once VENDOR_PATH . 'aop/AopCertClient.php';
        $c = new AopCertClient;
    
    
        $appCertPath = VENDOR_PATH . 'aop/crt/appCertPublicKey.crt';//应用证书路径(要确保证书文件可读)
        $alipayCertPath = VENDOR_PATH . 'aop/crt/alipayCertPublicKey_RSA2.crt';//支付宝公钥证书路径(要确保证书文件可读)
        $rootCertPath = VENDOR_PATH . 'aop/crt/alipayRootCert.crt';//支付宝根证书路径(要确保证书文件可读)
        $c->gatewayUrl = "https://openapi.alipay.com/gateway.do";
        $c->appId = $this->config['ali_app_app_id'];
        $c->rsaPrivateKey = $this->config['ali_app_rsa_pri_key'];
        $c->format = "json";
        $c->charset = "UTF-8";
        $c->signType = "RSA2";
        //调用getPublicKey从支付宝公钥证书中提取公钥
        $c->alipayrsaPublicKey = $c->getPublicKey($alipayCertPath);
        //是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
        $c->isCheckAlipayPublicCert = true;
        //调用getCertSN获取证书序列号
        $c->appCertSN = $c->getCertSN($appCertPath);
        //调用getRootCertSN获取支付宝根证书序列号
        $c->alipayRootCertSN = $c->getRootCertSN($rootCertPath);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.open.public.template.message.industry.modify
    
    
        //文件中加入 namespace app\api\controller; 即可
        require_once VENDOR_PATH . 'aop/request/AlipayTradeAppPayRequest.php';
        $request = new AlipayTradeAppPayRequest();
        
    
        //此次只是参数展示,未进行字符串转义,实际情况下请转义
        $request->setBizContent($this->getcontent($data));
        $response = $c->sdkExecute($request);
        return $response;
    }

     

  3. 一定有人发现 getcontent 方法不存在 嘿嘿  上代码: 

//业务数据
public function getcontent($data)
{
    $biz_content = array(
        'out_trade_no' => $data['out_order_no'],    //之前咱们自定义的订单号 out_trade_no
        'product_code' => 'QUICK_MSECURITY_PAY',    //定死了 别动
        'total_amount' => $data['fee'] / 100,       //单位换算
        'subject' => $data['subject'],              //之前定好的 标题
        'method' => 'alipay.trade.app.pay',         //定死了 别动
        'notify_url' => 'https://******.com/api/pay/verificationSign',//回调接口需要配置到支付宝
        'body' => $data['body'],                    //之前定好的 内容
        'timeout_express' => '1m',                  //支付超时时间 文档去支付宝搜索咯 1m-15d
    );
    return json_encode($biz_content);
}

 三、开始生成orderInfo 给前端吊起支付宝咯

$res = 获取字节跳动的订单号(一、获取字节跳动订单)
if ($res['result']['response']['code'] != 10000) {
    $this->error('错误', $res['result']['response']['code']);
} elseif ($res) {

    $out_order_no = $res['out_order_no'];//自定义的订单号
    $aliurl = $this->aliUrlZhengshu($res);//获取 alipay_url
    $arr = [
        'merchant_id' => $this->config['merchant_id'],//字节跳动商户号 前提条件->字节跳动->4 完成填写后
        'app_id' => $this->config['tt_pay_app_id'],//字节跳动APPID  前提条件->字节跳动->4 完成填写后
        'sign_type' => 'MD5',//定死的别动!!!
        'timestamp' => strval($res['time']),//需要为字符串类型的时间戳
        'version' => '2.0',//定死的别动!!!
        'trade_type' => 'H5',//定死的别动!!!
        'product_code' => 'pay',//定死的别动!!!
        'payment_type' => 'direct',//定死的别动!!!
        'out_order_no' => strval($out_order_no),//自定义的订单号
        'uid' => $this->openid,// 用户的openid 登录后可以获取到
        'total_amount' => $res['fee'],//金额 这里单位:分
        'currency' => 'CNY',//定死的别动!
        'trade_no' => $res['trade_no'],//刚刚获取的字节跳动订单 忘了往上找找
        'subject' => $res['subject'],//之前定好的标题
        'body' => $res['body'],//之前定好的内容
        'trade_time' => strval($res['time']),//一定要和 上面的 timestamp 字段相同
        'valid_time' => '3000',//测试留的时间长
        'notify_url' => 'https://tp-pay.snssdk.com/paycallback',//定死的别动!!!
        'alipay_url' => $aliurl,//刚刚生成的 记得不
    ];


    $stringToBeSigned = $this->getSignContent($arr);//这里待签名处理.方法下面
    $sign = md5($stringToBeSigned . $this->config['tt_pay_app_secret']);//这生成签名咯, 不要乱, 签名好多的
    
    //这两个字段的写入原因: 在待签名字符串 getSignContent 方法中不能有 sign和risk_info 所以在生成签名($sign)之后写入到里面
    $arr['sign'] = $sign;
    $arr['risk_info'] = json_encode(['ip' => request()->ip()]);
    //这两个字段的写入原因: 在待签名字符串  getSignContent 方法中不能有 sign和risk_info 所以在生成签名($sign)之后写入到里面
    
    $res = htmlspecialchars_decode(json_encode($arr));//这里html的编译解析, 防止html编译
    $this->success('返回orderinfo', $res);
}

这里是处理待签名的方法咯 一共三个别落下:

/**
 * 签名处理
 * @param $params
 * @param $charset
 * @return string
 */
public function getSignContent($params, $charset = 'utf-8')
{
    ksort($params);
    $stringToBeSigned = "";
    $i = 0;
    foreach ($params as $k => $v) {
        if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
            // 转换成目标字符集
            $v = $this->characet($v, $charset);
            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . "$v";
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
            }
            $i++;
        }
    }
    unset ($k, $v);
    return $stringToBeSigned;
}
/**
 * 校验$value是否非空
 * @param $value
 * @return  boolean;
 *  if not set ,return true;
 *  if is null , return true;
 **/
public function checkEmpty($value)
{
    if (!isset($value))
        return true;
    if ($value === null)
        return true;
    if (trim($value) === "")
        return true;
    return false;
}

/**
 * 转换字符集编码
 * @param $data
 * @param $targetCharset
 * @return string
 */
public function characet($data, $targetCharset)
{
    if (!empty($data)) {
        $fileType = "UTF-8";
        if (strcasecmp($fileType, $targetCharset) != 0) {
            $data = mb_convert_encoding($data, $targetCharset, $fileType);
        }
    }
    return $data;
}

 

总结哈 keke

$res 就是我们要的orderInfo 处理好之后是个json串 所以前端取到数据后需要json反序列化一下.

前端uniapp写的. 

可以分享下我们前端 重要的是 错误代码(错误代码:CD0015 CD0025 这个是字节跳动的错误)

_this.getOrderPayInfo().then(e => { //调用后端接口得到orderInfo
    let currenttime = Math.round(new Date() / 1000);
	let order = JSON.parse(e.data.data);
	if(e.data){
        uni.requestPayment({
			provider: 'toutiao',
			service: 4, // 不拉起字节跳动小程序收银台
			 _debug: 1,
			payChannel: {
            default_pay_channel: 'alipay' // wx || alipay
			},
			orderInfo: order, // 订单信息
			getOrderStatus(res) {
            let { out_order_no } = res;
			    return new Promise(function (resolve, reject) {

                })
			},
			success: (res) => {
            console.log("成功");
            console.log(res);
        },
			fail: (res) => {
            console.log("失败");
            console.log(res);  // 错误代码:CD0015 CD0025
        }
		})
		// _this.loadModal = false;
	}
})

 

 

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用的内容,uniapp抖音支付需要使用抖音小程序所需要的orderInfo字段,该字段必须是string类型的数据格式。你需要在onShow()函数中调用uni.getProvider()方法以获取支付服务提供商,并将其存储在本地缓存中。 对于字节跳动抖音支付支持的版本是抖音iOS 9.1.0版本/Android 8.7.0版本。你需要在字节跳动开放平台进行企业认证,并在开发管理中设置小程序Key和服务器域名。然后,在功能管理中选择支付,完成相应信息的填写与提交测试版。 对于支付宝,你需要注册支付宝开放平台账号,并完成企业认证。然后,在开发者中心控制台选择创建网页和移动应用,并选择支付接入。填写与抖音小程序相同的名称,选择网页应用,添加APP支付能力。接下来,进行签约,签约的APP名称必须填写测试版字节跳动小程序的名称。完成签约后,在应用信息中设置接口加签方式,并保存下载相应文件。关于授权回调地址,可以暂时不管它。 综上所述,uniapp抖音支付需要通过uni.getProvider()方法获取支付服务提供商,并完成相应的认证和设置,才能实现支付功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [字节抖音小程序,使用 uniapp 调起内置支付](https://blog.csdn.net/GrootBaby/article/details/131913729)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [字节跳动小程序(抖音) uniapp PHP 支付宝SDK 开发支付功能](https://blog.csdn.net/weixin_41415511/article/details/108049639)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值