1. 程式人生 > >Android整合Paypal

Android整合Paypal

最近在專案中原生化支付模組,由於專案是面向美國加拿大使用者的,所以需要整合Paypal支付和信用卡支付。本人菜鳥一個,第一次做專案,就被安排完成支付模組,我也是很無語啊,沒辦法,只能硬著頭皮上啊。經過閱讀文件,不斷測試,最終成功了!!!(鼓掌)

今天主要講一下信用卡和Paypal支付兩部分。

一.信用卡

信用卡需要自己定義UI,所以輸入信用卡資訊都是自己處理。信用卡資訊的獲取分為手動填寫掃描獲取

1. 手動填寫

信用卡賬號輸入處理:

/**
     * 信用卡號每隔四位加入一個空格
     */
    private TextWatcher mCreditCardNumWatcher = new
TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { modifyCardIcon(s.toString().replace(" ", "")); if
(TextUtils.isEmpty(s)) { return; } //判斷是否是在中間輸入,需要重新計算 boolean isMiddle = (start + count) < (s.length()); //在末尾輸入時,是否需要加入空格 boolean isNeedSpace = false; if (!isMiddle && s.length() > 0 && s.length() % 5
== 0) { isNeedSpace = true; } if (isMiddle || isNeedSpace || count > 1) { String newStr = s.toString(); newStr = newStr.replace(" ", ""); StringBuilder sb = new StringBuilder(); for (int i = 0; i < newStr.length(); i += 4) { if (i > 0) { sb.append(" "); } if (i + 4 <= newStr.length()) { sb.append(newStr.substring(i, i + 4)); } else { sb.append(newStr.substring(i, newStr.length())); } } mCreditCardNum.removeOnTextChangedListener(this); mCreditCardNum.setText(sb); //如果是在末尾的話,或者加入的字元個數大於零的話(輸入或者貼上) if (!isMiddle || count > 1) { mCreditCardNum.setSelection(sb.length()); } else if (isMiddle) { //如果是刪除 if (count == 0) { //如果刪除時,游標停留在空格的前面,游標則要往前移一位 if ((start - before + 1) % 5 == 0) { mCreditCardNum.setSelection((start - before) > 0 ? start - before : 0); } else { mCreditCardNum.setSelection((start - before + 1) > sb.length() ? sb.length() : (start - before + 1)); } } //如果是增加 else { if ((start - before + count) % 5 == 0) { mCreditCardNum.setSelection((start + count - before + 1) < sb.length() ? (start + count - before + 1) : sb.length()); } else { mCreditCardNum.setSelection(start + count - before); } } } mCreditCardNum.addOnTextChangedListener(this); } } @Override public void afterTextChanged(Editable s) { } };


信用卡有效期輸入處理:

/**
     * 有效期的格式為MM/YY
     */
    private TextWatcher mCreditCardExpirationDateWatcher = new TextWatcher() {
        String beforeTC;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            beforeTC = s.toString();
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            String currentInputDesc = "";
            //插入
            if (count != 0) {
                String temp = s.toString();
                if (temp.length() >= 1) {
                    currentInputDesc = temp.charAt(temp.length() - 1) + "";
                }
                if (ZERO.equals(beforeTC)) {
                    if (ZERO.equals(currentInputDesc)) {
                        // 第一位是零,輸入的數字也是零,則設定為0
                        mCreditCardExpirationDate.setText(ZERO);
                        mCreditCardExpirationDate.setSelection(ZERO.length());
                    } else {
                        // 第一位是零,輸入的數字不是零,補全斜槓
                        String aTemp = s.toString() + BACK_SLASH;
                        mCreditCardExpirationDate.setText(aTemp);
                        mCreditCardExpirationDate.setSelection(aTemp.length());
                    }
                }
                if (ONE.equals(beforeTC)) {
                    // 之前等於1
                    if (currentInputDesc.equals(ZERO)
                            || currentInputDesc.equals(ONE)
                            || currentInputDesc.equals(TWO)) {
                        // 並且輸入的第二位數字滿足 0,1,2月份要求
                        String aTemp = ONE + currentInputDesc + BACK_SLASH;
                        mCreditCardExpirationDate.setText(aTemp);
                        mCreditCardExpirationDate.setSelection(aTemp.length());
                    } else {
                        mCreditCardExpirationDate.setText(ONE);
                        mCreditCardExpirationDate.setSelection(ONE.length());
                    }
                }
                if (TextUtils.isEmpty(beforeTC)) {
                    temp = temp.replaceAll("/", "");
                    if (temp.length() == 1) {
                        //輸入
                        if (!currentInputDesc.equals(ZERO)
                                && !currentInputDesc.equals(ONE)) {
                            // 直接輸入數字
                            String aTemp = ZERO + s.toString() + BACK_SLASH;
                            mCreditCardExpirationDate.setText(aTemp);
                            mCreditCardExpirationDate.setSelection(aTemp.length());
                        }
                    } else if (temp.length() > 1) {
                        String firstChar = temp.charAt(0) + "";
                        if (!firstChar.equals(ZERO) && !firstChar.equals(ONE)) {
                            temp = ZERO + temp;
                        }
                        temp = temp.substring(0, 2) + "/" + temp.substring(2, temp.length());
                        mCreditCardExpirationDate.setText(temp);
                        if (temp.length() > 5) {
                            mCreditCardExpirationDate.setSelection(5);
                        } else {
                            mCreditCardExpirationDate.setSelection(temp.length());
                        }
                    }
                }
            } else { //刪除
                int selectionStart = mCreditCardExpirationDate.getSelectionStart();
                int textLength = mCreditCardExpirationDate.getText().length();
                // 判斷游標有沒有移動,移動的話不刪除文字,
                if (selectionStart != textLength) {
                    mCreditCardExpirationDate.setText(beforeTC);
                    mCreditCardExpirationDate
                            .setSelection(mCreditCardExpirationDate.getText().length());
                } else {
                    // 如果在最後,則刪除
                    mCreditCardExpirationDate.setSelection(s.toString().length());
                    if (s.length() == 2) {
                        // 當只剩下三個字元的時候一下刪除兩個字元
                        int index = mCreditCardExpirationDate.getSelectionStart();
                        Editable editable = mCreditCardExpirationDate.getText();
                        editable.delete(index - 1, index);
                    }
                }
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    };

2.掃描獲取

  • SDK要求:
    Android SDK版本16(Android 4.1)或更高版本。

  • 整合過程:

    1. 在你的build.gradle:

      compile 'io.card:android-sdk:5.5.1'
    2. 首先,我們假設你要從一個按鈕啟動掃描器,並且已經onClick在佈局XML中通過設定按鈕的處理器android:onClick=”onScanPress”。然後,新增方法如下:

      public void onScanPress(View v) {
          Intent scanIntent = new Intent(this, CardIOActivity.class);
      
          // customize these values to suit your needs.
          scanIntent.putExtra(CardIOActivity.EXTRA_REQUIRE_EXPIRY, true); // default: false
          scanIntent.putExtra(CardIOActivity.EXTRA_REQUIRE_CVV, false); // default: false
          scanIntent.putExtra(CardIOActivity.EXTRA_REQUIRE_POSTAL_CODE, false); // default: false
      
          // MY_SCAN_REQUEST_CODE is arbitrary and is only used within this activity.
          startActivityForResult(scanIntent, MY_SCAN_REQUEST_CODE);
      }
    3. 接下來,我們將覆蓋onActivityResult()獲取掃描結果。

      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      
      if (requestCode == MY_SCAN_REQUEST_CODE) {
          String resultDisplayStr;
          if (data != null && data.hasExtra(CardIOActivity.EXTRA_SCAN_RESULT)) {
              CreditCard scanResult = data.getParcelableExtra(CardIOActivity.EXTRA_SCAN_RESULT);
      
              // Never log a raw card number. Avoid displaying it, but if necessary use getFormattedCardNumber()
              resultDisplayStr = "Card Number: " + scanResult.getRedactedCardNumber() + "\n";
      
              // Do something with the raw number, e.g.:
              // myService.setCardNumber( scanResult.cardNumber );
      
              if (scanResult.isExpiryValid()) {
                  resultDisplayStr += "Expiration Date: " + scanResult.expiryMonth + "/" + scanResult.expiryYear + "\n";
              }
      
              if (scanResult.cvv != null) {
                  // Never log or display a CVV
                  resultDisplayStr += "CVV has " + scanResult.cvv.length() + " digits.\n";
              }
      
              if (scanResult.postalCode != null) {
                  resultDisplayStr += "Postal Code: " + scanResult.postalCode + "\n";
              }
          }
          else {
              resultDisplayStr = "Scan was canceled.";
          }
          // do something with resultDisplayStr, maybe display it in a textView
          // resultTextView.setText(resultDisplayStr);
      }
      // else handle other activity results
      }


      信用卡的整個過程還是比較簡單的,就不做過多的描述。

二.Paypal

今天的重點來了,Paypal支付,廢話不多說,直接進入主題。
我們專案中使用的是Braintree支付,這裡要來講一下Braintree和Paypal的區別與聯絡:

支付閘道器(Payment Gateway)是在商戶的線上商城網站和商戶的銀行收款賬戶之間,搭建一個加密的支付資訊通道,以便安全地將消費者通過瀏覽器在網站上購買時所輸入的賬戶資訊(如信用卡、姓名等)安全地傳輸到銀行端,並將付款行的授權返回給收款行。Braintree就是支付閘道器。

支付處理系統(Processor)是連結消費者賬戶銀行和商戶收款銀行之間的交易系統,確保交易資金可以順利地從消費者付款行賬戶進入到商戶的收款行賬戶。Paypal就是支付管理系統。

具體的怎麼操作就不用管了,這是他們後臺支付的問題。不需要我們來處理。現在來看一下Braintree的支付流程:
這裡寫圖片描述

  1. 客戶端向伺服器請求Token
  2. 伺服器生成併發送Token給客戶端, 發起支付請求
  3. BrainTree返回支付資訊Nonce給客戶端
  4. 客戶端傳送Nonce給伺服器
  5. 收到Nonce後, 伺服器帶著Nonce去BrainTree進行支付

重點來了,整合:

SDK要求:Android API >= 16
1. 安裝
  1. 在你的build.gradle,新增以下內容:

    dependencies {
      compile 'com.braintreepayments.api:braintree:2.+'
    }
  2. 對於PayPal,必須將URL方案定義為接受返回瀏覽器開關。編輯你AndroidManifest.xml的包含BraintreeBrowserSwitchActivity並設定android:scheme:

    <activity android:name="com.braintreepayments.api.BraintreeBrowserSwitchActivity"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="${applicationId}.braintree" />
        </intent-filter>
    </activity> 
2. 初始化

設定BraintreeFragment只是一個呼叫BraintreeFragment.newInstance(activity, authorization)與當前Activity和客戶端令牌。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    try {
      mBraintreeFragment = BraintreeFragment.newInstance(this, mAuthorization);
      // mBraintreeFragment is ready to use!
    } catch (InvalidArgumentException e) {
      // There was an issue with your authorization string.
    }
}

這個方法將會:

  • 準備一個BraintreeFragment。
  • 新增BraintreeFragment到給定的活動。
  • 檢查給定mAuthorization字串的有效性。

註冊監聽事件:

  1. PaymentMethodNonceCreatedListener當a PaymentMethodNonce被成功標記時被呼叫。從這傳送nonce PaymentMethodNonce到你的伺服器來建立一個事務。

    @Override
    public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
      // Send this nonce to your server
      String nonce = paymentMethodNonce.getNonce();
    }
  2. BraintreeCancelListener在BraintreeFragment被通知Activity#RESULT_CANCELED結果程式碼時被呼叫Fragment#onActivityResult。

    @Override
    public void onCancel(int requestCode) {
      // Use this to handle a canceled activity, if the given requestCode is important.
      // You may want to use this callback to hide loading indicators, and prepare your UI for input
    }
  3. BraintreeErrorListener在出現錯誤時呼叫。ErrorWithResponse在請求發生驗證錯誤時呼叫。Exception在發生網路問題或伺服器錯誤等錯誤時引發。

    @Override
    public void onError(Exception error) {
      if (error instanceof ErrorWithResponse) {
        ErrorWithResponse errorWithResponse = (ErrorWithResponse) error;
        BraintreeError cardErrors = errorWithResponse.errorFor("creditCard");
        if (cardErrors != null) {
          // There is an issue with the credit card.
          BraintreeError expirationMonthError = cardErrors.errorFor("expirationMonth");
          if (expirationMonthError != null) {
            // There is an issue with the expiration month.
            setErrorMessage(expirationMonthError.getMessage());
          }
        }
      }
    }
3.從伺服器獲取 Client Token

您的伺服器負責生成客戶端令牌,其中包含您的客戶端初始化客戶端SDK所需的授權和配置詳細資訊。

從您的伺服器請求客戶端令牌,然後初始化Braintree並提供下拉式UI(本示例使用Android非同步Http客戶端從伺服器請求客戶端令牌 - 適應您自己的設定):

AsyncHttpClient client = new AsyncHttpClient();
client.get("https://your-server/client_token", new TextHttpResponseHandler() {
    @Override
    public void onSuccess(int statusCode, Header[] headers, String clientToken) {
        this.clientToken = clientToken;
    }
});
4.Paypal 配置

一次性結賬是使用PayPal建立單個交易的簡單方法。首先,確保你已經定義了你的URL方案。然後,PayPal.requestOneTimePayment用來開始這個過程。一個示例整合可能如下所示:

public void setupBraintreeAndStartExpressCheckout() {
    PayPalRequest request = new PayPalRequest("1")
        .currencyCode("USD")
        .intent(PayPalRequest.INTENT_AUTHORIZE);
    PayPal.requestOneTimePayment(mBraintreeFragment, request);
}

支付事件的監聽:

yourButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
      setupBraintreeAndStartExpressCheckout();
    }
});

當您收到回撥時onPaymentMethodNonceCreated,您可以查詢PayPalAccountNonce您返回的物件以獲取特定的客戶資訊。

@Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
    // Send nonce to server
    String nonce = paymentMethodNonce.getNonce();

}
5.傳送Nonce到伺服器

將生成的付款方式隨機數傳送到您的伺服器:

void postNonceToServer(String nonce) {
  AsyncHttpClient client = new AsyncHttpClient();
  RequestParams params = new RequestParams();
  params.put("payment_method_nonce", nonce);
  client.post("http://your-server/checkout", params,
    new AsyncHttpResponseHandler() {
      // Your implementation here
    }
  );
}


好吧,整個流程完了。開始的時候不瞭解,踩了很多坑。國內也沒有完整的教程,所以就自己做的過程整理了一下。第一次寫,寫的不好,請大家多多包涵。

相關推薦

Android整合Paypal

最近在專案中原生化支付模組,由於專案是面向美國加拿大使用者的,所以需要整合Paypal支付和信用卡支付。本人菜鳥一個,第一次做專案,就被安排完成支付模組,我也是很無語啊,沒辦法,只能硬著頭皮上啊。經過閱讀文件,不斷測試,最終成功了!!!(鼓掌) 今天主要講一下

Android 如何整合Paypal支付

最近做一個專案用到Paypal支付,官網上有整合文件,但是感覺有點複雜,我再這裡把步驟優化一下,方便大家整合!1:支付流程:Paypal 的支付流程很簡單,我們把錢支付到商家paypal成功以後,paypal會返回給我們一個支付ID,我們拿著支付ID傳給伺服器,伺服器進行驗證

spring mvc+mybatis ios android整合cms內容發布平臺

減少 連接 jquer 登錄 jdk版本 sso href com 分享圖片 開發語言: java、ios、android 部署平臺: linux、window jdk版本:JDK1.7以上版本 開發工具: eclipse、idea等 服務器中間件:Tomcat

Android 整合百度地圖實現裝置定位

Android 整合百度地圖實現裝置定位步驟1:申請android 端SDK :http://lbsyun.baidu.com/步驟2:下載基礎版SDK步驟3:下載示例程式步驟4:開始整合:ak加入libs加入SDKInitializer.setCoordType(CoordType.BD09LL);圖示類

使用最新Android Studio搭建Android整合開發環境

1. 準備工具   物理機版本:Win 8(64位)   Java SDK版本:jdk-11.0.1_windows-x64_bin.zip   Android Studio版本:android-studio-ide-181.5056338-windows.exe   注:物理機

Android整合Glide(支援回撥)

背景 Glide是當前非常流程的圖片載入框架,功能強大而且非常穩定。 整合指導 最簡整合方式 1.dependencies中增加依賴 implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProc

Android 整合華為推送 push

由於專案需要我們不得不對華為push進行研究。 按照國際慣例先百度一波,發現各個大牛都是對於華為push的填坑,很明顯,這個推送的問題還是有很多的。 這裡引用:Android整合華為推送踩坑問題總結 使用老版push還是新版push PushReceiver中的onEve

Android 整合華為推送

Android的推送業務現狀還是比較混亂,手機廠商各有一套推送機制和SDK需要你去整合,今天先談一談華為的推送服務整合吧 整合背景:React Native專案,已經集成了一套JPush,但是目前相當一部分Android機型極光推送在應用殺掉之後是不能喚醒的,Android和Appl

Android整合百度地圖-----顯示地圖、定位、長按顯示地址資訊

一、基礎部分 轉載請註明出處:https://blog.csdn.net/Hunter2916/article/details/82867205 1、下載百度地圖的SDK 下載地址:http://lbsyun.baidu.com/index.php?title=android-locsd

android整合環信sdk出現app:transformClassesWithDexForDebug.” ---finished with non-zero exit value 2解決方法

android整合環信sdk出現app:transformClassesWithDexForDebug.” —finished with non-zero exit value 2解決方法 通常是架包衝突問題。 首先找到Gradle Scripts 然後找到 解決: impleme

Android 整合 X5 WebView

AndroidManifest.xml 1.新增jar包 在libs目錄下新增sdk中的jar包 將Demo中的jniLibs目錄複製到 main資料夾下 2.需要新增許可權 <uses-permission android:name="android.permission.WRITE_EXTERNA

Android整合友盟整合推送方案調研

Android整合友盟整合推送方案調研 鑑於專案apk瘦身的需求,經過調研,發現現有的推送整合方案可以優化。現有的推送方案是華為 + 小米 + 友盟推送,分別針對的是華為(包括榮耀)手機、小米手機、其他型別手機。這樣做的好處是,華為、小米系列的手機都可以支援離線訊息,推送訊息送達率有

Android整合支付——微信支付,能調啟微信為何調啟不了微信支付問題

整合微信支付的時候會遇到很多問題,此文章只介紹處理【能調啟微信為何調啟不了微信支付】問題。 1、微信能調啟來,說明你的整合已經成功。但還是注意商戶的微信id是否統一,因為在調啟支付介面的時候需要註冊微信id。 2、調啟不了微信支付/調啟微信支付閃退並跳轉到回撥頁進行提示失

Android整合html中呼叫拍照功能拍照後無法上傳問題分析解決

最近在做專案的時候遇到一個很詭異的問題,後來找到原因以後,發現原因很簡單,修改很easy,不多大多數情況下我們都容易忽略。 問題描述:使用Android手機中的html介面呼叫拍照功能(未使用第三方外掛),發現照片無法傳上去,但是使用從相簿選擇功能,就可以正常上傳照片。後來我把上次通過拍照儲

PHP中整合PayPal標準支付(非form提交方式)

需求 老闆:咱們公司想打歐美市場,線上支付這一塊再用支付寶和微信就不合適了,你找一個比較適合國外人的支付方式,把他們的錢裝進咱們公司的口袋裡; 經過深思熟慮和多出調研;paypal是最適合國際市場的一種支付方式 概述 paypal官網:https://www.

在手機上開發程式之AIDE(Android整合開發環境)介紹

AIDE簡介         AIDE是一個Android/Java整合開發環境,可以在Android系統內進行Android軟體和遊戲的開發。     AIDE不僅僅是一個編輯器,而是支援編寫-編譯-除錯的IDE,開發人員可以在Android手機或者平板機上建立新的專案

android 整合weex

android端整合weex:              1》、gradle:             minSdkVersion 16  大於16                          implementation 'com.android.support:re

Android 整合okhttp3、listview解析json資料

上上篇文章寫了個Android的模擬介面,終於派上用場了 現在我們將接口裡面的json資料通過ListView顯示出來,效果如下: 先講一下ListView吧, 講ListView之前,肯定要講Adapter,在Android應用程式中,採用資料和顯示分開實現的資料處理方式,由於資料來

android整合sharesdk遇到的坑無法返回app等

整合sharesdk後    遇到一個問題  分享到微信和朋友圈  點選返回的時候發現無法回到app private void sharedToThirdPlatform() { OnekeyShare oks = new OnekeyShare()

android整合weex sdk原始碼

         git clone https://github.com/apache/incubator-weex.git  下的 android → sdk 整合依賴包  ( Weex_Sdk\i