这方面国内的文档很少,也踩了不少的坑,今天有空记录一下
- 准备工作,商户配置,沙盒测试账号配置,需要在applepay 开发者 官网中配置,测试卡号也需要使用官方的沙盒 测试账号;
- 需要将官网的证书下载下来,一同放到服务器,证书有过期时间
- 前端需要在https 的环境下,才能进行调试,本地调试需要搭建环境,nginx 之类的进行转发
直接上前端代码
import PropTypes from 'prop-types';
import { useEffect, useState } from 'react';
import scriptLoader from 'react-async-script-loader';
import { useSelector } from 'react-redux';
// 这是后端提供的一个接口,获取applepay的token,需要拿到这个token 做鉴权;
import getApplePaySession from 'services/controller/checkout/getApplePaySession';
import { ButtonWrapper } from './ApplePayButton.style';
let applePayPayment = {};
function ApplyPayButton({
isScriptLoaded,
isScriptLoadSucceed,
onSave,
initiateResponse = {},
}) {
const [showButton, setShowButton] = useState(false);
const ckeckoutUpdate = {
newTotal: {
label: 'demo',
amount:totalToPay,
},
newLineItems: [
{
label: 'Product Amount',
amount:productAmount,
},
{
label: 'Shipping Fee',
amount: shippingFee,
},
{
label: 'Tax',
amount: totalTax,
},
],
};
function onApplePayButtonClicked() {
try {
const request = {
countryCode: '',
currencyCode: '',
merchantCapabilities: [],
supportedNetworks: [],
total: {
label: label,
type: 'final',
amount: totalToPay,
},
};
console.log('apple payment request', request);
console.log('storeInfo', storeInfo);
// Create ApplePaySession
// eslint-disable-next-line no-undef
const session = new ApplePaySession(3, request);
session.onvalidatemerchant = async (event) => {
console.log('event', event);
// Call your own server to request a new merchant session.
const hostName = window.location.host;
const merchantSession = await getApplePaySession(
applePayConfig,
event.validationURL,
hostName
);
console.log('merchantSession', merchantSession);
session.completeMerchantValidation(merchantSession);
};
session.onpaymentmethodselected = (event) => {
console.log('paymentChange', event);
// Define ApplePayPaymentMethodUpdate based on the selected payment method.
// No updates or errors are needed, pass an empty object.
session.completePaymentMethodSelection(ckeckoutUpdate);
};
session.onshippingmethodselected = (event) => {
console.log('shippingMethodChange', event);
// Define ApplePayShippingMethodUpdate based on the selected shipping method.
session.completeShippingMethodSelection(ckeckoutUpdate);
};
session.onshippingcontactselected = (event) => {
console.log('onshippingcontactselected', event);
// Define ApplePayShippingContactUpdate based on the selected shipping contact.
session.completeShippingContactSelection(ckeckoutUpdate);
};
session.onpaymentauthorized = (event) => {
const billingAddressInfo = {
countryId: 'US',
zipCode: '',
city: '',
lastName: '',
state: '',
firstName: '',
addressLine2: '',
addressLine1: '',
};
console.log('Success1', event.payment);
// eslint-disable-next-line no-undef
console.log('SuccessStatus', ApplePaySession.STATUS_SUCCESS);
const result = {
// eslint-disable-next-line no-undef
status: ApplePaySession.STATUS_SUCCESS,
};
applePayPayment = {
applePayEncryptedPaymentBundle: {
data: event.payment?.token.paymentData?.data,
signature: event.payment?.token.paymentData.signature,
header: event.payment?.token.paymentData.header,
protocolVersion: event.payment?.token.paymentData.version,
},
digitalWalletType: 'ApplePay',
digitalWalletLatitudeLongitude: '1,1',
cardType:
event.payment?.token?.paymentMethod?.network === 'AmEx'
? 'Amex'
: event.payment?.token?.paymentMethod?.network,
billingAddressInfo,
};
console.log('applyPayPayment', applePayPayment);
onSave(applePayPayment);
session.completePayment(result);
};
session.oncancel = (event) => {
// Payment cancelled by WebKit
console.log('cancel', event);
};
session.begin();
} catch (e) {
console.log('error', e);
}
}
useEffect(() => {
if (isScriptLoaded && isScriptLoadSucceed) {
// eslint-disable-next-line no-undef
if (window.ApplePaySession && ApplePaySession.canMakePayments) {
setShowButton(true);
}
// onApplePayButtonClicked();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isScriptLoadSucceed, isScriptLoaded]);
return (
<ButtonWrapper>
{showButton && (
<>
<button
onClick={onApplePayButtonClicked}
type='button'
label
className='apple-pay-button'
style={{ width: '293px', height: '50px' }}
/>
</>
)}
</ButtonWrapper>
);
}
ApplyPayButton.defaultProps = {
isScriptLoaded: false,
isScriptLoadSucceed: false,
};
ApplyPayButton.propTypes = {
onSave: PropTypes.func.isRequired,
isScriptLoaded: PropTypes.bool,
isScriptLoadSucceed: PropTypes.bool,
initiateResponse: PropTypes.func,
};
export default scriptLoader(['https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js'])(
ApplyPayButton
);
代码基本都是官网的代码,这个比官网看的更直接一点;
- window.ApplePaySession && ApplePaySession.canMakePayments 判断浏览器是否支持
- getApplePaySession 这个是自己封装的方法,核心代码就是调用后端接口,取回数据,数据结构applepay 官网有,返回一样的结构体就行