這方面國內(nèi)的文檔很少趟薄,也踩了不少的坑贱枣,今天有空記錄一下
- 準(zhǔn)備工作冤馏,商戶配置日麸,沙盒測試賬號配置,需要在applepay 開發(fā)者 官網(wǎng)中配置逮光,測試卡號也需要使用官方的沙盒 測試賬號代箭;
- 需要將官網(wǎng)的證書下載下來墩划,一同放到服務(wù)器,證書有過期時間
- 前端需要在https 的環(huán)境下嗡综,才能進(jìn)行調(diào)試乙帮,本地調(diào)試需要搭建環(huán)境,nginx 之類的進(jìn)行轉(zhuǎn)發(fā)
直接上前端代碼
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 做鑒權(quán)碑幅;
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
);
代碼基本都是官網(wǎng)的代碼戴陡,這個比官網(wǎng)看的更直接一點;
- window.ApplePaySession && ApplePaySession.canMakePayments 判斷瀏覽器是否支持
- getApplePaySession 這個是自己封裝的方法沟涨,核心代碼就是調(diào)用后端接口恤批,取回數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)applepay 官網(wǎng)有裹赴,返回一樣的結(jié)構(gòu)體就行