web 端對接 applepay

這方面國內(nèi)的文檔很少趟薄,也踩了不少的坑贱枣,今天有空記錄一下

  1. 準(zhǔn)備工作冤馏,商戶配置日麸,沙盒測試賬號配置,需要在applepay 開發(fā)者 官網(wǎng)中配置逮光,測試卡號也需要使用官方的沙盒 測試賬號代箭;
  2. 需要將官網(wǎng)的證書下載下來墩划,一同放到服務(wù)器,證書有過期時間
  3. 前端需要在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)看的更直接一點;

  1. window.ApplePaySession && ApplePaySession.canMakePayments 判斷瀏覽器是否支持
  2. getApplePaySession 這個是自己封裝的方法沟涨,核心代碼就是調(diào)用后端接口恤批,取回數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)applepay 官網(wǎng)有裹赴,返回一樣的結(jié)構(gòu)體就行
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喜庞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子棋返,更是在濱河造成了極大的恐慌延都,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睛竣,死亡現(xiàn)場離奇詭異晰房,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)射沟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門殊者,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人验夯,你說我怎么就攤上這事猖吴。” “怎么了挥转?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵海蔽,是天一觀的道長。 經(jīng)常有香客問我绑谣,道長党窜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任域仇,我火速辦了婚禮刑然,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暇务。我一直安慰自己泼掠,他們只是感情好怔软,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著择镇,像睡著了一般挡逼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腻豌,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天家坎,我揣著相機(jī)與錄音,去河邊找鬼吝梅。 笑死虱疏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苏携。 我是一名探鬼主播做瞪,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼右冻!你這毒婦竟也來了装蓬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤纱扭,失蹤者是張志新(化名)和其女友劉穎牍帚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乳蛾,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡暗赶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了屡久。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忆首。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖被环,靈堂內(nèi)的尸體忽然破棺而出糙及,到底是詐尸還是另有隱情,我是刑警寧澤筛欢,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布浸锨,位于F島的核電站,受9級特大地震影響版姑,放射性物質(zhì)發(fā)生泄漏柱搜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一剥险、第九天 我趴在偏房一處隱蔽的房頂上張望聪蘸。 院中可真熱鬧,春花似錦、人聲如沸健爬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娜遵。三九已至蜕衡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間设拟,已是汗流浹背慨仿。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留纳胧,地道東北人镰吆。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像躲雅,于是被迫代替她去往敵國和親鼎姊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容