SlideShare a Scribd company logo
1 of 23
Google Wallet Instant Buy
Android API
13年5月29日水曜日
本APIは現時点でI/O参加者にしか
開放されていません!
一般公開を楽しみにお待ちくださいm(_ _)m
13年5月29日水曜日
このAPIは何か?
13年5月29日水曜日
このAPIは何か?
• 物理商品を販売するAndroidアプリにGoogle Wallet
決済を簡単に提供
• 顧客はGoogle Walletに安全に決済情報や配送先を
保存
• 業者にクレジットカードを直接渡さないため安全
• 実際には決済毎にワンタイムの仮想デビットカー
ドで決済が行われる
13年5月29日水曜日
重要用語
• Masked Wallet Request / Response
• カードや住所が一部隠された情報
• Full Wallet Request / Response
• 決済を完了するための正当な情報
(詳しくは後述)
13年5月29日水曜日
決済の流れ
13年5月29日水曜日
決済の流れ
1. アプリからMasked Walletを要求
2. GoogleがMasked Walletを返すので、アプリでは確認
表示などに用いる
3. アプリからFull Walletを要求
4. Full Walletの情報が、ワンタイムの仮想カード情報
と共に返される
5. 決済が完了したらTransaction StatusをGoogleに送信
13年5月29日水曜日
具体的なAPIの流れ
13年5月29日水曜日
• Buy with Google Wallet button を設置
• onConnected()
• ボタンをクリック
• onMaskedWalletLoaded()
• 過去に情報を入力していればそれを使い、無ければ新規入力を
促す ( startResolutionForResult() )
• 注文を確定 (loadFullWallet)
• onFullWalletLoaded()
• Full Walletと一緒に返されるワンタイムカードの情報を使って決済
• Transactionの成否をWallet Clientを通じてGoogleに返す
13年5月29日水曜日
WalletClient mWalletClient = new WalletClient(
      context, environment, accountName
      connectionCallbackListener,
connectionFailedListener);
mWalletClient.connect();
Wallet Client 初期化
13年5月29日水曜日
初期化のCallback
public void onConnected(connectionHint) {
  mWalletClient.checkForPreAuthorization(this);
13年5月29日水曜日
Masked Wallet Request
MaskedWalletRequest mwRequest =
  MaskedWalletRequest.newBuilder()
  .setMerchantName(Constants.MERCHANT_NAME)
  .setPhoneNumberRequired(true)
  .setShippingAddressRequired(true)
  .setCurrencyCode("USD")
  .setEstimatedTotalPrice("150.00")
  .build();
mWalletClient.loadMaskedWallet(mwRequest,
maskedWalletLoadedListener);
13年5月29日水曜日
callback
@Override
public void onMaskedWalletLoaded(ConnectionResult result,
      MaskedWallet wallet) {
  if (result.isSuccess()) {
    // handling for case where user has preauthorized
     . . .
  } else {
    if (result.hasResolution()) {
      try {
        result.startResolutionForResult(activity, requestCode);
      } catch (SendIntentException e) {
        mWalletClient.connect();
      }
    }
  }
}
13年5月29日水曜日
事前登録してある場合
@Override
public void onMaskedWalletLoaded(ConnectionResult
result,
    MaskedWallet wallet) {
  if (result.isSuccess()) {
    mMaskedWallet = wallet;
    launchConfirmationPage();
  }
}
13年5月29日水曜日
startResolutionForResult() の場合
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == requestCode used in startResolutionForResult) {
    switch (resultCode) {
      case Activity.RESULT_OK:
        mMaskedWallet =
          data.getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);
        break;
      case Activity.RESULT_CANCELED:
        // fetch a new ConnectionResult as below or you may
        //go back to previous app flow
        mWalletClient.loadMaskedWallet(
        mwRequest,
        maskedWalletLoadedListener);
        break;
      default:
        int errorCode = data.getIntExtra(WalletConstants.EXTRA_ERROR_CODE,
          -1);
        handleError(errorCode);
    }
  }
}
13年5月29日水曜日
Full Wallet Request
FullWalletRequest fullWalletRequest = FullWalletRequest.newBuilder()
  .setGoogleTransactionId(googleTransactionId)
  .setCart(Cart.newBuilder()
          .setCurrencyCode(Constants.CURRENCY_CODE_USD)
          .setTotalPrice(toDollars(context, itemInfo.getTotalPrice()))
          .addLineItem(LineItem.newBuilder()
                  .setCurrencyCode(Constants.CURRENCY_CODE_USD)
                  .setDescription(itemInfo.name)
                  .setQuantity("1")
                  .setUnitPrice(toDollars(context, itemInfo.priceMicros))
                  .setTotalPrice(toDollars(context, itemInfo.priceMicros))
                  .build())
          .addLineItem(LineItem.newBuilder()
                  .setCurrencyCode(Constants.CURRENCY_CODE_USD)
                  .setDescription(Constants.DESCRIPTION_LINE_ITEM_SHIPPING)
                  .setRole(LineItem.Role.SHIPPING)
                  .setTotalPrice(toDollars(context, itemInfo.shippingPriceMicros))
                  .build())
          .addLineItem(LineItem.newBuilder()
                  .setCurrencyCode(Constants.CURRENCY_CODE_USD)
                  .setDescription(Constants.DESCRIPTION_LINE_ITEM_TAX)
                  .setRole(LineItem.Role.TAX)
                  .setTotalPrice(toDollars(context, itemInfo.taxMicros))
                  .build())
          .build())
  .build();
mWalletClient.loadFullWallet(fullWalletRequest, fullWalletLoadedListener);
13年5月29日水曜日
callback
@Override
public void onFullWalletLoaded(ConnectionResult result, FullWallet
fullWallet) {
  if (result.isSuccess()) {
    // The full wallet is received here
     . . .
  } else if (result.hasResolution()) {
    try {
      result.startResolutionForResult(getActivity(),
            Constants.REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET);
    } catch (SendIntentException e) {
      // retry loading the full wallet
       . . .
    }
  }
}
13年5月29日水曜日
仮想カード情報
String accountNumber  =  
mFullWallet.getProxyCard().getPan();
String securityCvv  =
mFullWallet.getProxyCard().getCvn();
int expirationYear =
mFullWallet.getExpirationYear();
int expirationMonth =
mFullWallet.getExpirationMonth();
Address billingAddress =
mFullWallet.getBillingAddress();
Address shippingAddress =
mFullWallet.getShippingAddress();
13年5月29日水曜日
Notify the Transaction Result
NotifyTransactionStatusRequest notifyTxRequest =
NotifyTransactionStatusRequest.newBuilder()
  .setGoogleTransactionId(googleTransactionId)
  .setStatus(NotifyTransactionStatusRequest.Status.SUCCESS)
  .build();
mWalletClient.notifyTransactionStatus(notifyTxRequest)
13年5月29日水曜日
clean up
@Override
public void onStop() {
  super.onStop();
  mWalletClient.disconnect();
}
13年5月29日水曜日
デモ
13年5月29日水曜日
Card Type Card Number CSC Expiration Date
American Express 3782 8224 6310 005 any four digits any future date
Discover 6011 0999 0037 2372 any three digits any future date
MasterCard 5555 5555 5555 4444 any three digits any future date
Visa 4111 1111 1111 1111 any three digits any future date
13年5月29日水曜日
一般公開をお楽しみに!
@fushiroyama
13年5月29日水曜日

More Related Content

More from Fumihiko Shiroyama

GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例Fumihiko Shiroyama
 
GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発Fumihiko Shiroyama
 
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFirebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFumihiko Shiroyama
 
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようRxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようFumihiko Shiroyama
 
絶対落ちないアプリの作り方
絶対落ちないアプリの作り方絶対落ちないアプリの作り方
絶対落ちないアプリの作り方Fumihiko Shiroyama
 
Ops worksに今後期待するところ
Ops worksに今後期待するところOps worksに今後期待するところ
Ops worksに今後期待するところFumihiko Shiroyama
 

More from Fumihiko Shiroyama (8)

RxJava - Subject 入門
RxJava - Subject 入門RxJava - Subject 入門
RxJava - Subject 入門
 
GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例
 
GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発
 
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFirebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
 
AndroidでEither
AndroidでEitherAndroidでEither
AndroidでEither
 
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようRxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしよう
 
絶対落ちないアプリの作り方
絶対落ちないアプリの作り方絶対落ちないアプリの作り方
絶対落ちないアプリの作り方
 
Ops worksに今後期待するところ
Ops worksに今後期待するところOps worksに今後期待するところ
Ops worksに今後期待するところ
 

Wallet api

  • 1. Google Wallet Instant Buy Android API 13年5月29日水曜日
  • 4. このAPIは何か? • 物理商品を販売するAndroidアプリにGoogle Wallet 決済を簡単に提供 • 顧客はGoogle Walletに安全に決済情報や配送先を 保存 • 業者にクレジットカードを直接渡さないため安全 • 実際には決済毎にワンタイムの仮想デビットカー ドで決済が行われる 13年5月29日水曜日
  • 5. 重要用語 • Masked Wallet Request / Response • カードや住所が一部隠された情報 • Full Wallet Request / Response • 決済を完了するための正当な情報 (詳しくは後述) 13年5月29日水曜日
  • 7. 決済の流れ 1. アプリからMasked Walletを要求 2. GoogleがMasked Walletを返すので、アプリでは確認 表示などに用いる 3. アプリからFull Walletを要求 4. Full Walletの情報が、ワンタイムの仮想カード情報 と共に返される 5. 決済が完了したらTransaction StatusをGoogleに送信 13年5月29日水曜日
  • 9. • Buy with Google Wallet button を設置 • onConnected() • ボタンをクリック • onMaskedWalletLoaded() • 過去に情報を入力していればそれを使い、無ければ新規入力を 促す ( startResolutionForResult() ) • 注文を確定 (loadFullWallet) • onFullWalletLoaded() • Full Walletと一緒に返されるワンタイムカードの情報を使って決済 • Transactionの成否をWallet Clientを通じてGoogleに返す 13年5月29日水曜日
  • 10. WalletClient mWalletClient = new WalletClient(       context, environment, accountName       connectionCallbackListener, connectionFailedListener); mWalletClient.connect(); Wallet Client 初期化 13年5月29日水曜日
  • 11. 初期化のCallback public void onConnected(connectionHint) {   mWalletClient.checkForPreAuthorization(this); 13年5月29日水曜日
  • 12. Masked Wallet Request MaskedWalletRequest mwRequest =   MaskedWalletRequest.newBuilder()   .setMerchantName(Constants.MERCHANT_NAME)   .setPhoneNumberRequired(true)   .setShippingAddressRequired(true)   .setCurrencyCode("USD")   .setEstimatedTotalPrice("150.00")   .build(); mWalletClient.loadMaskedWallet(mwRequest, maskedWalletLoadedListener); 13年5月29日水曜日
  • 13. callback @Override public void onMaskedWalletLoaded(ConnectionResult result,       MaskedWallet wallet) {   if (result.isSuccess()) {     // handling for case where user has preauthorized      . . .   } else {     if (result.hasResolution()) {       try {         result.startResolutionForResult(activity, requestCode);       } catch (SendIntentException e) {         mWalletClient.connect();       }     }   } } 13年5月29日水曜日
  • 14. 事前登録してある場合 @Override public void onMaskedWalletLoaded(ConnectionResult result,     MaskedWallet wallet) {   if (result.isSuccess()) {     mMaskedWallet = wallet;     launchConfirmationPage();   } } 13年5月29日水曜日
  • 15. startResolutionForResult() の場合 public void onActivityResult(int requestCode, int resultCode, Intent data) {   if (requestCode == requestCode used in startResolutionForResult) {     switch (resultCode) {       case Activity.RESULT_OK:         mMaskedWallet =           data.getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);         break;       case Activity.RESULT_CANCELED:         // fetch a new ConnectionResult as below or you may         //go back to previous app flow         mWalletClient.loadMaskedWallet(         mwRequest,         maskedWalletLoadedListener);         break;       default:         int errorCode = data.getIntExtra(WalletConstants.EXTRA_ERROR_CODE,           -1);         handleError(errorCode);     }   } } 13年5月29日水曜日
  • 16. Full Wallet Request FullWalletRequest fullWalletRequest = FullWalletRequest.newBuilder()   .setGoogleTransactionId(googleTransactionId)   .setCart(Cart.newBuilder()           .setCurrencyCode(Constants.CURRENCY_CODE_USD)           .setTotalPrice(toDollars(context, itemInfo.getTotalPrice()))           .addLineItem(LineItem.newBuilder()                   .setCurrencyCode(Constants.CURRENCY_CODE_USD)                   .setDescription(itemInfo.name)                   .setQuantity("1")                   .setUnitPrice(toDollars(context, itemInfo.priceMicros))                   .setTotalPrice(toDollars(context, itemInfo.priceMicros))                   .build())           .addLineItem(LineItem.newBuilder()                   .setCurrencyCode(Constants.CURRENCY_CODE_USD)                   .setDescription(Constants.DESCRIPTION_LINE_ITEM_SHIPPING)                   .setRole(LineItem.Role.SHIPPING)                   .setTotalPrice(toDollars(context, itemInfo.shippingPriceMicros))                   .build())           .addLineItem(LineItem.newBuilder()                   .setCurrencyCode(Constants.CURRENCY_CODE_USD)                   .setDescription(Constants.DESCRIPTION_LINE_ITEM_TAX)                   .setRole(LineItem.Role.TAX)                   .setTotalPrice(toDollars(context, itemInfo.taxMicros))                   .build())           .build())   .build(); mWalletClient.loadFullWallet(fullWalletRequest, fullWalletLoadedListener); 13年5月29日水曜日
  • 17. callback @Override public void onFullWalletLoaded(ConnectionResult result, FullWallet fullWallet) {   if (result.isSuccess()) {     // The full wallet is received here      . . .   } else if (result.hasResolution()) {     try {       result.startResolutionForResult(getActivity(),             Constants.REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET);     } catch (SendIntentException e) {       // retry loading the full wallet        . . .     }   } } 13年5月29日水曜日
  • 18. 仮想カード情報 String accountNumber  =   mFullWallet.getProxyCard().getPan(); String securityCvv  = mFullWallet.getProxyCard().getCvn(); int expirationYear = mFullWallet.getExpirationYear(); int expirationMonth = mFullWallet.getExpirationMonth(); Address billingAddress = mFullWallet.getBillingAddress(); Address shippingAddress = mFullWallet.getShippingAddress(); 13年5月29日水曜日
  • 19. Notify the Transaction Result NotifyTransactionStatusRequest notifyTxRequest = NotifyTransactionStatusRequest.newBuilder()   .setGoogleTransactionId(googleTransactionId)   .setStatus(NotifyTransactionStatusRequest.Status.SUCCESS)   .build(); mWalletClient.notifyTransactionStatus(notifyTxRequest) 13年5月29日水曜日
  • 20. clean up @Override public void onStop() {   super.onStop();   mWalletClient.disconnect(); } 13年5月29日水曜日
  • 22. Card Type Card Number CSC Expiration Date American Express 3782 8224 6310 005 any four digits any future date Discover 6011 0999 0037 2372 any three digits any future date MasterCard 5555 5555 5555 4444 any three digits any future date Visa 4111 1111 1111 1111 any three digits any future date 13年5月29日水曜日