儲存至 Google Pay

各票證類別皆屬於日常用途。舉例來說,您可以透過下列方式將所有會員卡、儲值卡、優惠、活動票券、登機證和大眾運輸票證新增至 Google Pay 應用程式:

新增網站按鈕

將 [儲存至 Google Pay] 按鈕新增至您的網站,讓使用者能夠將任何會員卡、儲值卡、優惠、活動票券、登機證和大眾運輸票證儲存至 Google Pay 應用程式。

使用者只要按一下按鈕,代表使用者票證的 JSON Web Token (JWT) 就會傳送至 Google 伺服器。Google 伺服器隨後會根據 JWT 建立個別的 Object 資源,並將該資源連結至使用者的帳戶。

以下是將 [儲存至 Google Pay] 按鈕整合至網站的三個步驟:

  1. 定義物件要擴充的 Class
  2. 產生一個代表 Object 的 JWT。
  3. 將 [儲存至 Google Pay] 按鈕新增至您的網頁。

下列步驟以會員票證為例,但所有票證皆適用相同的程序。

1. 定義物件要擴充的類別

首先,定義 LoyaltyClass。如果要插入 LoyaltyClass,請發送 POST 要求至下列 REST URI:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass

如果要啟用嚴格錯誤剖析,並找出重複 ID 欄位等其他類錯誤,請依照下列範例 URI 所示,將 strict=true 參數新增至 REST URI:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass?strict=true

下列範例顯示代表 LoyaltyClass 的 JSON 資源。必須在 POST 要求的內容中傳送 JSON。下列程式碼範例具體示範如何定義和插入 LoyaltyClass

資源

    {
      "accountIdLabel": "Member Id",
      "accountNameLabel": "Member Name",
      "id": "2945482443380251551.ExampleClass1",
      "issuerName": "Baconrista",
      "kind": "walletobjects#loyaltyClass",
      "textModulesData": [
        {
          "header": "Rewards details",
          "body": "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. " +
                   "10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!"
        }
      ],
      "linksModuleData": {
        "uris": [
          {
            "kind": "walletobjects#uri",
            "uri": "https://maps.google.com/map?q=google",
            "description": "Nearby Locations"
          },
          {
            "kind": "walletobjects#uri",
            "uri": "tel:6505555555",
            "description": "Call Customer Service"
          }
        ]
      },
      "imageModulesData": [
        {
          "mainImage": {
            "kind": "walletobjects#image",
            "sourceUri": {
              "kind": "walletobjects#uri",
              "uri": "https://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
              "description": "Coffee beans"
            }
          }
        }
      ],
      "messages": [{
        "header": "Welcome to Banconrista Rewards!",
        "body": "Featuring our new bacon donuts.",
        "kind": "walletobjects#walletObjectMessage"
      }],
      "locations": [{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.424015499999996,
        "longitude": -122.09259560000001
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.424354,
        "longitude": -122.09508869999999
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.7901435,
        "longitude": -122.39026709999997
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 40.7406578,
        "longitude": -74.00208940000002
      }],
      "programLogo": {
        "kind": "walletobjects#image",
        "sourceUri": {
          "kind": "walletobjects#uri",
          "uri": "https://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
        }
      },
      "programName": "Baconrista Rewards",
      "rewardsTier": "Gold",
      "rewardsTierLabel": "Tier",
      "reviewStatus": "underReview",
      "hexBackgroundColor": "#ffffff",
      "heroImage": {
       "kind": "walletobjects#image",
       "sourceUri": {
         "kind": "walletobjects#uri",
         "uri": "https://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg"
       }
      }
    }
    

Java

    // Define the Image Module Data
    List<ImageModuleData> imageModuleData = new ArrayList<ImageModuleData>();

    ImageModuleData image = new ImageModuleData().setMainImage(
        new Image().setSourceUri(
            new ImageUri().setUri("http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")));

    imageModuleData.add(image);

    // Define Text Module Data
    List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();

    TextModuleData textModuleData = new TextModuleData().setHeader("Rewards details")
        .setBody(
            "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer.  10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more!");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List<Uri> uris = new ArrayList<Uri>();
    Uri uri1 = new Uri().setDescription("Nearby Locations").setUri("http://maps.google.com/?q=google");
    Uri uri2 = new Uri().setDescription("Call Customer Service").setUri("tel:6505555555");

    uris.add(uri1);
    uris.add(uri2);

    LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

    // Define general messages
    List<Message> messages = new ArrayList<Message>();
    Message message = new Message()
        .setHeader("Welcome to Baconrista")
        .setBody("Featuring our new bacon donuts.");
    messages.add(message);

    // Define Geofence locations
    List<LatLongPoint> locations = new ArrayList<LatLongPoint>();
    locations.add(new LatLongPoint().setLatitude(37.422601).setLongitude(
        -122.085286));
    locations.add(new LatLongPoint().setLatitude(37.424354).setLongitude(
        -122.09508869999999));
    locations.add(new LatLongPoint().setLatitude(40.7406578).setLongitude(
        -74.00208940000002));

    // Create class
    LoyaltyClass wobClass = new LoyaltyClass()
        .setId('2945482443380251551.ExampleClass1')
        .setIssuerName("Baconrista")
        .setProgramName("Baconrista Rewards")
        .setProgramLogo(
            new Image().setSourceUri(new ImageUri()
                .setUri("http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg")))
        .setRewardsTierLabel("Tier").setRewardsTier("Gold")
        .setImageModulesData(imageModuleData)
        .setTextModulesData(textModulesData)
        .setLinksModuleData(linksModuleData)
        .setAccountNameLabel("Member Name").setAccountIdLabel("Member Id")
        .setMessages(messages)
        .setReviewStatus("underReview").setMultipleDevicesAndHoldersAllowedStatus("multipleHolders")
        .setLocations(locations);

    LoyaltyClass response = client.loyaltyclass().insert(wobClass).execute();
    

PHP

    // Define text module data.
    $textModulesData = array(
        array(
            'header' => 'Rewards details',
            'body' => 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' .
                '10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!'
        )
    );
    // Define links module data.
    $linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
    $uris = array (
        array(
            'uri' => 'http://maps.google.com/map?q=google',
            'kind' => 'walletobjecs#uri',
            'description' => 'Nearby Locations'
        ),
        array(
            'uri' => 'tel:6505555555',
            'kind' => 'walletobjecs#uri',
            'description' => 'Call Customer Service'
        )
    );
    $linksModuleData->setUris($uris);

    $uriModuleImageInstance = new Google_Service_Walletobjects_ImageUri();
    $uriModuleImageInstance->setUri(
        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
    );
    $uriModuleImageInstance->setDescription('Coffee beans');
    $imageModuleImageInstance = new Google_Service_Walletobjects_Image();
    $imageModuleImageInstance->setSourceUri($uriModuleImageInstance);
    $imagesModuleData = new Google_Service_Walletobjects_ImageModuleData();
    $imagesModuleData->setMainImage($imageModuleImageInstance);
    $imagesModuleDataArr = array ($imagesModuleData);

    // Messages to be displayed to all users of Wallet Objects.
    $messages = array(array(
        'header' => 'Welcome to Banconrista Rewards!',
        'body' => 'Featuring our new bacon donuts.',
        'kind' => 'walletobjects#walletObjectMessage'
    ));
    $locations = array(
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.424015499999996,
            'longitude' => -122.09259560000001
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.424354,
            'longitude' => -122.09508869999999
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.7901435,
            'longitude' => -122.39026709999997
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 40.7406578,
            'longitude' => -74.00208940000002
        )
    );
    // Source uri of program logo.
    $uriInstance = new Google_Service_Walletobjects_ImageUri();
    $imageInstance = new Google_Service_Walletobjects_Image();
    $uriInstance->setUri(
        'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
    );
    $imageInstance->setSourceUri($uriInstance);
    // Create wallet class.
    $wobClass = new Google_Service_Walletobjects_LoyaltyClass();
    $wobClass->setId('2945482443380251551.ExampleClass1');
    $wobClass->setIssuerName('Baconrista');
    $wobClass->setProgramName('Baconrista Rewards');
    $wobClass->setProgramLogo($imageInstance);
    $wobClass->setRewardsTierLabel('Tier');
    $wobClass->setRewardsTier('Gold');
    $wobClass->setAccountNameLabel('Member Name');
    $wobClass->setAccountIdLabel('Member Id');
    $wobClass->setLinksModuleData($linksModuleData);
    $wobClass->setTextModulesData($textModulesData);
    $wobClass->setImageModulesData($imagesModuleDataArr);
    $wobClass->setMessages($messages);
    $wobClass->setReviewStatus('underReview');
    $wobClass->setMultipleDevicesAndHoldersAllowedStatus('multipleHolders');
    $wobClass->setLocations($locations);

    $service->loyaltyclass->insert($wobClass);
    

Python

    loyalty_class = {
      'accountIdLabel': 'Member Id',
      'accountNameLabel': 'Member Name',
      'multipleDevicesAndHoldersAllowedStatus': 'multipleHolders',
      'id': '2945482443380251551.ExampleClass1',
      'issuerName': 'Baconrista',
      'kind': 'walletobjects#loyaltyClass',
      'locations': [{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.424015499999996,
          'longitude': -122.09259560000001
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.424354,
          'longitude': -122.09508869999999
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.7901435,
          'longitude': -122.39026709999997
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 40.7406578,
          'longitude': -74.00208940000002
      }],
      'textModulesData': [{
        'header': 'Rewards details',
        'body': 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' +
                '10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more! '
      }],
      'linksModuleData': {
        'uris': [
          {
            'kind': 'walletobjects#uri',
            'uri': 'http://maps.google.com/map?q=google',
            'description': 'Nearby Locations'
          },{
            'kind': 'walletobjects#uri',
            'uri': 'tel:6505555555',
            'description': 'Call Customer Service'
          }]
      },
      'imageModulesData': [
        {
          'mainImage': {
            'kind': 'walletobjects#image',
            'sourceUri': {
              'kind': 'walletobjects#uri',
              'uri':  'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
              'description': 'Coffee beans'
            }
          }
        }
      ],
      'messages': [{
          'header': 'Welcome to Banconrista Rewards!',
          'body': 'Featuring our new bacon donuts.',
          'kind': 'walletobjects#walletObjectMessage'
      }],
      'programLogo': {
          'kind': 'walletobjects#image',
          'sourceUri': {
              'kind': 'walletobjects#uri',
              'uri': 'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
          }
      },
      'programName': 'Baconrista Rewards',
      'rewardsTier': 'Gold',
      'rewardsTierLabel': 'Tier',
      'reviewStatus': 'underReview',
    }

    api_request = service.loyaltyclass().insert(body=loyalty_class)
    api_response = api_request.execute()
    

如需所有 LoyaltyClass 欄位的完整清單,請參閱 LoyaltyClass 參考資料

2. 產生一個代表物件的 JWT

首先,按照下列程式碼片段所示定義 LoyaltyObject

資源

    {
      "classId": "2945482443380251551.ExampleClass1",
      "id": "2945482443380251551.ExampleObject1",
      "accountId": "1234567890",
      "accountName": "Jane Doe",
      "barcode": {
        "alternateText": "12345",
        "type": "qrCode",
        "value": "28343E3"
      },
      "textModulesData": [{
        "header": "Jane's Baconrista Rewards",
        "body": "Save more at your local Mountain View store Jane. " +
                  "You get 1 bacon fat latte for every 5 coffees purchased.  " +
                  "Also just for you, 10% off all pastries in the Mountain View store."
      }],
      "linksModuleData": {
        "uris": [
          {
            "kind": "walletobjects#uri",
            "uri": "https://www.baconrista.com/myaccount?id=1234567890",
            "description": "My Baconrista Account"
          }]
      },
      "infoModuleData": {
        "labelValueRows": [{
          "columns": [{
            "label": "Next Reward in",
            "value": "2 coffees"
          }, {
            "label": "Member Since",
            "value": "01/15/2013"
          }]
        }, {
          "columns": [{
            "label": "Local Store",
            "value": "Mountain View"
          }]
        }],
        "showLastUpdateTime": "true"
      },
      "loyaltyPoints": {
        "balance": {
          "string": "5000"
        },
        "label": "Points",
          "pointsType": "points"
      },
      "messages": [{
        "header": "Jane, welcome to Banconrista Rewards!",
        "body": "Thanks for joining our program. Show this message to " +
                  "our barista for your first free coffee on us!"
      }],
      "state": "active"
    }
    

Java

    // Define Barcode
    Barcode barcode = new Barcode().setType("qrCode")
        .setValue("28343E3")
        .setAlternateText("12345");

    // Define Points
    LoyaltyPoints points = new LoyaltyPoints()
        .setLabel("Points")
        .setPointsType("points")
        .setBalance(new LoyaltyPointsBalance().setString("500"));

    // Define Text Module Data
    List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();
    TextModuleData textModuleData = new TextModuleData()
        .setHeader("Jane's Baconrista Rewards")
        .setBody(
            "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List<Uri> uris = new ArrayList<Uri>();
    Uri uri1 = new Uri().setDescription("My Baconrista Account")
        .setUri("http://www.baconrista.com/myaccount?id=1234567890");
    uris.add(uri1);
    LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

    // Define Info Module
    List<LabelValue> row0cols = new ArrayList<LabelValue>();
    LabelValue row0col0 = new LabelValue().setLabel("Next Reward in")
        .setValue("2 coffees");
    LabelValue row0col1 = new LabelValue().setLabel("Member Since")
        .setValue("01/15/2013");
    row0cols.add(row0col0);
    row0cols.add(row0col1);

    List<LabelValue> row1cols = new ArrayList<LabelValue>();
    LabelValue row1col0 = new LabelValue().setLabel("Local Store")
        .setValue("Mountain View");
    row1cols.add(row1col0);

    List<LabelValueRow> rows = new ArrayList<LabelValueRow>();
    LabelValueRow row0 = new LabelValueRow().setColumns(row0cols);
    LabelValueRow row1 = new LabelValueRow().setColumns(row1cols);

    rows.add(row0);
    rows.add(row1);

    InfoModuleData infoModuleData = new InfoModuleData()
        .setShowLastUpdateTime(true)
        .setLabelValueRows(rows);

    // Define general messages
    List<Message> messages = new ArrayList<Message>();
    Message message = new Message()
        .setHeader("Hi Jane!")
        .setBody("Thanks for joining our program. Show this message to " +
            "our barista for your first free coffee on us!");
    messages.add(message);

    // Define Wallet Instance
    LoyaltyObject object = new LoyaltyObject()
        .setClassId('2945482443380251551.ExampleClass1').setId('2945482443380251551.ExampleObject1')
        .setState("active").setBarcode(barcode).setInfoModuleData(infoModuleData)
        .setAccountName("Jane Doe").setTextModulesData(textModulesData)
        .setMessages(messages).setLinksModuleData(linksModuleData)
        .setAccountId("1234567890").setLoyaltyPoints(points);
    

PHP

    $barcode = new Google_Service_Walletobjects_Barcode();
    $barcode->setAlternateText('12345');
    $barcode->setType('qrCode');
    $barcode->setValue('28343E3');
    // Define text module data.
    $textModulesData = array(
        array(
            'header' => 'Janes Baconrista Rewards',
            'body' => 'Save more at your local Mountain View store Jane. ' .
                      'You get 1 bacon fat latte for every 5 coffees purchased. ' .
                      'Also just for you, 10% off all pastries in the Mountain View store.'
        )
    );
    // Define links module data.
    $linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
    $uris = array (
        array(
            'uri' => 'http://www.baconrista.com/myaccount?id=1234567890',
            'kind' => 'walletobjecs#uri',
            'description' => 'My Baconrista Account'
        )
    );
    $linksModuleData->setUris($uris);
    // Define label values.
    $labelValueRows = array(
        array(
            'columns' => array(
                array(
                    'label' => 'Next Reward in',
                    'value' => '2 coffees'
                ), array(
                    'label' => 'Member Since',
                    'value' => '01/15/2013'
                )
            )
        ),
        array(
            'columns' => array(
                array(
                    'label' => 'Local Store',
                    'value' => 'Mountain View'
                )
            )
        )
    );
    // Define info module data.
    $infoModuleData = new Google_Service_Walletobjects_InfoModuleData();
    $infoModuleData->setShowLastUpdateTime(true);
    $infoModuleData->setLabelValueRows($labelValueRows);
    // Messages to be displayed.
    $messages = array(array(
        'header' => 'Jane, welcome to Banconrista Rewards!',
        'body' => 'Thanks for joining our program. Show this message to '.
                  'our barista for your first free coffee on us!',
        'kind' => 'walletobjects#walletObjectMessage'
    ));
    // Reward points a user has.
    $points = new Google_Service_Walletobjects_LoyaltyPoints();
    $balance = new Google_Service_Walletobjects_LoyaltyPointsBalance();
    $balance->setString('500');
    $points->setBalance($balance);
    $points->setLabel('Points');
    $points->setPointsType('points');
    // Create wallet object.
    $wobObject = new Google_Service_Walletobjects_LoyaltyObject();
    $wobObject->setClassId('2945482443380251551.ExampleClass1');
    $wobObject->setId('2945482443380251551.ExampleObject1');
    $wobObject->setState('active');
    $wobObject->setBarcode($barcode);
    $wobObject->setInfoModuleData($infoModuleData);
    $wobObject->setLinksModuleData($linksModuleData);
    $wobObject->setTextModulesData($textModulesData);
    $wobObject->setAccountName('Jane Doe');
    $wobObject->setAccountId('1234567890');
    $wobObject->setLoyaltyPoints($points);
    $wobObject->setMessages($messages);
    

Python

    loyalty_object = {
      'classId' : '2945482443380251551.ExampleClass1',
      'id' : '2945482443380251551.ExampleObject1',
      'accountId': '1234567890',
      'accountName': 'Jane Doe',
      'barcode': {
          'alternateText' : '12345',
          'type' : 'qrCode',
          'value' : '28343E3'
      },
      'textModulesData': [{
        'header': 'Jane\'s Baconrista Rewards',
        'body': 'Save more at your local Mountain View store Jane. ' +
                ' You get 1 bacon fat latte for every 5 coffees purchased.  ' +
                'Also just for you, 10% off all pastries in the Mountain View store.'
      }],
      'linksModuleData': {
        'uris': [
          {
            'kind': 'walletobjects#uri',
            'uri': 'http://www.baconrista.com/myaccount?id=1234567890',
            'description': 'My Baconrista Account'
          }]
      },
      'infoModuleData': {
        'labelValueRows': [{
            'columns': [{
              'label': 'Next Reward in',
              'value': '2 coffees'
            }, {
              'label': 'Member Since',
              'value': '01/15/2013'
            }]
          },{
            'columns': [{
              'label': 'Local Store',
              'value': 'Mountain View'
            }]
        }],
        'showLastUpdateTime': 'true'
      },
      'messages': [{
          'header': 'Jane, welcome to Banconrista Rewards',
          'body': 'Thanks for joining our program. Show this message to ' +
                  'our barista for your first free coffee on us!',
          'kind': 'walletobjects#walletObjectMessage'
      }],
      'loyaltyPoints': {
          'balance': {
              'string': '500'
          },
          'label': 'Points',
          'pointsType': 'points'
      },
      'state': 'active'
    }
    

使用 OAuth 2.0 服務帳戶私密金鑰,將 LoyaltyObject 編碼並插入 JWT。下列程式碼片段顯示如何以各種語言將 JWT 編碼。「通訊協定」分頁顯示未編碼的 JWT。如需 JWT 中各欄位的說明,請參考「Google Pay API for Passes JWT」。

通訊協定

    {
      "iss": "example_service_account@developer.gserviceaccount.com",
      "aud": "google",
      "typ": "savetoandroidpay",
      "iat": 1368029586,
      "payload": {
        "eventTicketClasses": [{
          ... //Event ticket Class JSON
        }],
        "eventTicketObjects": [{
          ... //Event ticket Object JSON
        }],
        "flightClasses": [{
          ... //Flight Class JSON
        }],
        "flightObjects": [{
          ... //Flight Object JSON
        }],
        "giftCardClasses": [{
          ... //Gift card Class JSON
        }],
        "giftCardObjects": [{
          ... //Gift card Object JSON
        }],
        "loyaltyClasses": [{
          ... //Loyalty Class JSON
        }],
        "loyaltyObjects": [{
          ... //Loyalty Object JSON
        }],
        "offerClasses": [{
          ... //Offer Class JSON
        }],
        "offerObjects": [{
          ... //Offer Object JSON
        }],
        "transitClasses": [{
          ... //Transit Class JSON
        }],
        "transitObjects": [{
          ... //Transit Object JSON
        }]
      },
      "origins": ["http://baconrista.com", "https://baconrista.com"]
    }
    

Java

    WobCredentials credentials = null;
    WobUtils utils = null;

    // Instantiate the WobUtils class which contains handy functions
    // Wob utils can be found in the quickstart sample
    try {
      credentials = new WobCredentials(
        ServiceAccountEmailAddress,
        ServiceAccountPrivateKeyPath,
        ApplicationName,
        IssuerId);
      utils = new WobUtils(credentials);
    } catch (GeneralSecurityException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    // Add valid domains for the Save to Wallet button
    List<String> origins = new ArrayList<String>();
    origins.add("http://baconrista.com");
    origins.add("https://baconrista.com");
    origins.add(req.getScheme() + "://" + req.getServerName() + ":" + req.getLocalPort());

    //Generate Objects and Classes here
    //........

    WobPayload payload = new WobPayload();
    payload.addObject({WalletObject/WalletClass});

    // Convert the object into a Save to Android Pay Jwt
    String jwt = null;
    try {
      jwt = utils.generateSaveJwt(payload, origins);
    } catch (SignatureException e) {
      e.printStackTrace();
    }
    

PHP

    $requestBody = [
      "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
      "aud" => "google",
      "typ" => "savetoandroidpay",
      "iat"=> time(),
      "payload" => {
        "eventTicketClasses" => [ ], # Event ticket classes
        "eventTicketObjects" => [ ], # Event ticket objects
        "flightClasses" => [ ],      # Flight classes
        "flightObjects" => [ ],      # Flight objects
        "giftCardClasses" => [ ],    # Gift card classes
        "giftCardObjects" => [ ],    # Gift card objects
        "loyaltyClasses" => [ ],     # Loyalty classes
        "loyaltyObjects" => [ ],     # Loyalty objects
        "offerClasses" => [ ],       # Offer classes
        "offerObjects" => [ ],       # Offer objects
        "transitClasses" => [ ],     # Transit classes
        "transitObjects" => [ ]      # Transit objects
      },
      "origins" => ["http://baconrista.com", "https://baconrista.com"]
    ]
    // Generate the Save to Android Pay Jwt
    echo $jwt = $assertObj->makeSignedJwt($requestBody, $client);
    

Python

    jwt = {
      'iss': config.SERVICE_ACCOUNT_EMAIL_ADDRESS,
      'aud': 'google',
      'typ': 'savetoandroidpay',
      'iat':  int(time.time()),
      'payload': {
        'webserviceResponse': {
          'result': 'approved',
          'message': 'Success.'
        },
        'eventTicketClasses': [], # Event ticket classes
        'eventTicketObjects': [], # Event ticket objects
        'flightClasses': [],      # Flight classes
        'flightObjects': [],      # Flight objects
        'giftCardClasses': [],    # Gift card classes
        'giftCardObjects': [],    # Gift card objects
        'loyaltyClasses': [],     # Loyalty classes
        'loyaltyObjects': [],     # Loyalty objects
        'offerClasses': [],       # Offer classes
        'offerObjects': [],       # Offer objects
        'transitClasses': [],     # Transit classes
        'transitObjects': []      # Transit objects
      },
      'origins' : ['http://baconrista.com', 'https://baconrista.com']
    }

    // Generate the Save to Android Pay Jwt
    signer = crypt.Signer.from_string(app_key)
    signed_jwt = crypt.make_signed_jwt(signer, jwt)
    response = webapp2.Response(signed_jwt)
    

經編碼的 JWT 的長度上限為 1800 個字元。您的 JWT 不應超過此限制。如果長度超過 1800 個字元,就會遭到網路瀏覽器截斷而無法儲存。經編碼並插入 JWT 的物件應精簡,且僅包含與使用者相關的資料。請試著將大部分的資料存放在物件的類別中,並在建立 JWT 前先建立類別。對於超過字元限制的大型物件,請考慮使用 REST API 來建立物件,且在 JWT 中只傳送物件 ID。

3. 新增 [儲存至 Google Pay] 按鈕

在您想要放置 [儲存至 Google Pay] 按鈕的頁面上,加入下列指令碼:

    <script src="https://apis.google.com/js/platform.js" type="text/javascript"></script>
    

接著,請插入 g:savetoandroidpay 命名空間標記,藉此定義 [儲存至 Google Pay] 按鈕的位置和屬性。加入先前產生的 JWT。

    <g:savetoandroidpay jwt="{jwt_generated}" onsuccess="successHandler"
    onfailure="failureHandler" size="small" theme="light" ></g:savetoandroidpay>
    

現在,您應該能在網頁中看見 [儲存至 Google Pay] 按鈕。

如要進一步瞭解 JavaScript 網站按鈕,請參閱 Google Pay API for Passes 的 Web API 參考資源說明文件。

如果要透過電子郵件將票證儲存至 Google Pay,請使用深層連結將按鈕加入電子郵件。

以下是將 [儲存至 Google Pay] 按鈕整合至電子郵件或簡訊的三個步驟:

  1. 定義物件要擴充的 Class
  2. 產生一個代表 Object 的 JWT
  3. 將 [儲存至 Google Pay] 按鈕新增至電子郵件或簡訊

下列步驟以會員票證為例,但所有票證皆適用相同的程序。

1. 定義物件要擴充的類別

首先,定義 LoyaltyClass。如果要插入 LoyaltyClass,請發送 POST 要求至下列 REST URI:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass

如果要啟用嚴格錯誤剖析,並找出重複 ID 欄位等其他類錯誤,請依照下列範例 URI 所示,將 strict=true 參數新增至 REST URI:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass?strict=true

下列範例顯示代表 LoyaltyClass 的 JSON 資源。必須在 POST 要求的內容中傳送 JSON。下列程式碼範例具體示範如何定義和插入 LoyaltyClass

資源

    {
      "accountIdLabel": "Member Id",
      "accountNameLabel": "Member Name",
      "id": "2945482443380251551.ExampleClass1",
      "issuerName": "Baconrista",
      "kind": "walletobjects#loyaltyClass",
      "textModulesData": [
        {
          "header": "Rewards details",
          "body": "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. " +
                   "10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!"
        }
      ],
      "linksModuleData": {
        "uris": [
          {
            "kind": "walletobjects#uri",
            "uri": "https://maps.google.com/map?q=google",
            "description": "Nearby Locations"
          },
          {
            "kind": "walletobjects#uri",
            "uri": "tel:6505555555",
            "description": "Call Customer Service"
          }
        ]
      },
      "imageModulesData": [
        {
          "mainImage": {
            "kind": "walletobjects#image",
            "sourceUri": {
              "kind": "walletobjects#uri",
              "uri": "https://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
              "description": "Coffee beans"
            }
          }
        }
      ],
      "messages": [{
        "header": "Welcome to Banconrista Rewards!",
        "body": "Featuring our new bacon donuts.",
        "kind": "walletobjects#walletObjectMessage"
      }],
      "locations": [{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.424015499999996,
        "longitude": -122.09259560000001
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.424354,
        "longitude": -122.09508869999999
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 37.7901435,
        "longitude": -122.39026709999997
        },{
        "kind": "walletobjects#latLongPoint",
        "latitude": 40.7406578,
        "longitude": -74.00208940000002
      }],
      "programLogo": {
        "kind": "walletobjects#image",
        "sourceUri": {
          "kind": "walletobjects#uri",
          "uri": "https://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
        }
      },
      "programName": "Baconrista Rewards",
      "rewardsTier": "Gold",
      "rewardsTierLabel": "Tier",
      "reviewStatus": "underReview",
      "hexBackgroundColor": "#ffffff",
      "heroImage": {
       "kind": "walletobjects#image",
       "sourceUri": {
         "kind": "walletobjects#uri",
         "uri": "https://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg"
       }
      }
    }
    

Java

    // Define the Image Module Data
    List<ImageModuleData> imageModuleData = new ArrayList<ImageModuleData>();

    ImageModuleData image = new ImageModuleData().setMainImage(
        new Image().setSourceUri(
            new ImageUri().setUri("http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")));

    imageModuleData.add(image);

    // Define Text Module Data
    List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();

    TextModuleData textModuleData = new TextModuleData().setHeader("Rewards details")
        .setBody(
            "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer.  10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more!");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List<Uri> uris = new ArrayList<Uri>();
    Uri uri1 = new Uri().setDescription("Nearby Locations").setUri("http://maps.google.com/?q=google");
    Uri uri2 = new Uri().setDescription("Call Customer Service").setUri("tel:6505555555");

    uris.add(uri1);
    uris.add(uri2);

    LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

    // Define general messages
    List<Message> messages = new ArrayList<Message>();
    Message message = new Message()
        .setHeader("Welcome to Baconrista")
        .setBody("Featuring our new bacon donuts.");
    messages.add(message);

    // Define Geofence locations
    List<LatLongPoint> locations = new ArrayList<LatLongPoint>();
    locations.add(new LatLongPoint().setLatitude(37.422601).setLongitude(
        -122.085286));
    locations.add(new LatLongPoint().setLatitude(37.424354).setLongitude(
        -122.09508869999999));
    locations.add(new LatLongPoint().setLatitude(40.7406578).setLongitude(
        -74.00208940000002));

    // Create class
    LoyaltyClass wobClass = new LoyaltyClass()
        .setId('2945482443380251551.ExampleClass1')
        .setIssuerName("Baconrista")
        .setProgramName("Baconrista Rewards")
        .setProgramLogo(
            new Image().setSourceUri(new ImageUri()
                .setUri("http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg")))
        .setRewardsTierLabel("Tier").setRewardsTier("Gold")
        .setImageModulesData(imageModuleData)
        .setTextModulesData(textModulesData)
        .setLinksModuleData(linksModuleData)
        .setAccountNameLabel("Member Name").setAccountIdLabel("Member Id")
        .setMessages(messages)
        .setReviewStatus("underReview").setMultipleDevicesAndHoldersAllowedStatus("multipleHolders")
        .setLocations(locations);

    LoyaltyClass response = client.loyaltyclass().insert(wobClass).execute();
    

PHP

    // Define text module data.
    $textModulesData = array(
        array(
            'header' => 'Rewards details',
            'body' => 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' .
                '10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!'
        )
    );
    // Define links module data.
    $linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
    $uris = array (
        array(
            'uri' => 'http://maps.google.com/map?q=google',
            'kind' => 'walletobjecs#uri',
            'description' => 'Nearby Locations'
        ),
        array(
            'uri' => 'tel:6505555555',
            'kind' => 'walletobjecs#uri',
            'description' => 'Call Customer Service'
        )
    );
    $linksModuleData->setUris($uris);

    $uriModuleImageInstance = new Google_Service_Walletobjects_ImageUri();
    $uriModuleImageInstance->setUri(
        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
    );
    $uriModuleImageInstance->setDescription('Coffee beans');
    $imageModuleImageInstance = new Google_Service_Walletobjects_Image();
    $imageModuleImageInstance->setSourceUri($uriModuleImageInstance);
    $imagesModuleData = new Google_Service_Walletobjects_ImageModuleData();
    $imagesModuleData->setMainImage($imageModuleImageInstance);
    $imagesModuleDataArr = array ($imagesModuleData);

    // Messages to be displayed to all users of Wallet Objects.
    $messages = array(array(
        'header' => 'Welcome to Banconrista Rewards!',
        'body' => 'Featuring our new bacon donuts.',
        'kind' => 'walletobjects#walletObjectMessage'
    ));
    $locations = array(
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.424015499999996,
            'longitude' => -122.09259560000001
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.424354,
            'longitude' => -122.09508869999999
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 37.7901435,
            'longitude' => -122.39026709999997
        ),
        array(
            'kind' => 'walletobjects#latLongPoint',
            'latitude' => 40.7406578,
            'longitude' => -74.00208940000002
        )
    );
    // Source uri of program logo.
    $uriInstance = new Google_Service_Walletobjects_ImageUri();
    $imageInstance = new Google_Service_Walletobjects_Image();
    $uriInstance->setUri(
        'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
    );
    $imageInstance->setSourceUri($uriInstance);
    // Create wallet class.
    $wobClass = new Google_Service_Walletobjects_LoyaltyClass();
    $wobClass->setId('2945482443380251551.ExampleClass1');
    $wobClass->setIssuerName('Baconrista');
    $wobClass->setProgramName('Baconrista Rewards');
    $wobClass->setProgramLogo($imageInstance);
    $wobClass->setRewardsTierLabel('Tier');
    $wobClass->setRewardsTier('Gold');
    $wobClass->setAccountNameLabel('Member Name');
    $wobClass->setAccountIdLabel('Member Id');
    $wobClass->setLinksModuleData($linksModuleData);
    $wobClass->setTextModulesData($textModulesData);
    $wobClass->setImageModulesData($imagesModuleDataArr);
    $wobClass->setMessages($messages);
    $wobClass->setReviewStatus('underReview');
    $wobClass->setMultipleDevicesAndHoldersAllowedStatus('multipleHolders');
    $wobClass->setLocations($locations);

    $service->loyaltyclass->insert($wobClass);
    

Python

    loyalty_class = {
      'accountIdLabel': 'Member Id',
      'accountNameLabel': 'Member Name',
      'multipleDevicesAndHoldersAllowedStatus': 'multipleHolders',
      'id': '2945482443380251551.ExampleClass1',
      'issuerName': 'Baconrista',
      'kind': 'walletobjects#loyaltyClass',
      'locations': [{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.424015499999996,
          'longitude': -122.09259560000001
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.424354,
          'longitude': -122.09508869999999
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 37.7901435,
          'longitude': -122.39026709999997
          },{
          'kind': 'walletobjects#latLongPoint',
          'latitude': 40.7406578,
          'longitude': -74.00208940000002
      }],
      'textModulesData': [{
        'header': 'Rewards details',
        'body': 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' +
                '10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more! '
      }],
      'linksModuleData': {
        'uris': [
          {
            'kind': 'walletobjects#uri',
            'uri': 'http://maps.google.com/map?q=google',
            'description': 'Nearby Locations'
          },{
            'kind': 'walletobjects#uri',
            'uri': 'tel:6505555555',
            'description': 'Call Customer Service'
          }]
      },
      'imageModulesData': [
        {
          'mainImage': {
            'kind': 'walletobjects#image',
            'sourceUri': {
              'kind': 'walletobjects#uri',
              'uri':  'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
              'description': 'Coffee beans'
            }
          }
        }
      ],
      'messages': [{
          'header': 'Welcome to Banconrista Rewards!',
          'body': 'Featuring our new bacon donuts.',
          'kind': 'walletobjects#walletObjectMessage'
      }],
      'programLogo': {
          'kind': 'walletobjects#image',
          'sourceUri': {
              'kind': 'walletobjects#uri',
              'uri': 'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
          }
      },
      'programName': 'Baconrista Rewards',
      'rewardsTier': 'Gold',
      'rewardsTierLabel': 'Tier',
      'reviewStatus': 'underReview',
    }

    api_request = service.loyaltyclass().insert(body=loyalty_class)
    api_response = api_request.execute()
    

如需所有 LoyaltyClass 欄位的完整清單,請參閱 LoyaltyClass 參考資料

2. 產生一個代表物件的 JWT

首先,按照下列程式碼片段所示定義 LoyaltyObject

資源

    {
      "classId": "2945482443380251551.ExampleClass1",
      "id": "2945482443380251551.ExampleObject1",
      "accountId": "1234567890",
      "accountName": "Jane Doe",
      "barcode": {
        "alternateText": "12345",
        "type": "qrCode",
        "value": "28343E3"
      },
      "textModulesData": [{
        "header": "Jane's Baconrista Rewards",
        "body": "Save more at your local Mountain View store Jane. " +
                  "You get 1 bacon fat latte for every 5 coffees purchased.  " +
                  "Also just for you, 10% off all pastries in the Mountain View store."
      }],
      "linksModuleData": {
        "uris": [
          {
            "kind": "walletobjects#uri",
            "uri": "https://www.baconrista.com/myaccount?id=1234567890",
            "description": "My Baconrista Account"
          }]
      },
      "infoModuleData": {
        "labelValueRows": [{
          "columns": [{
            "label": "Next Reward in",
            "value": "2 coffees"
          }, {
            "label": "Member Since",
            "value": "01/15/2013"
          }]
        }, {
          "columns": [{
            "label": "Local Store",
            "value": "Mountain View"
          }]
        }],
        "showLastUpdateTime": "true"
      },
      "loyaltyPoints": {
        "balance": {
          "string": "5000"
        },
        "label": "Points",
          "pointsType": "points"
      },
      "messages": [{
        "header": "Jane, welcome to Banconrista Rewards!",
        "body": "Thanks for joining our program. Show this message to " +
                  "our barista for your first free coffee on us!"
      }],
      "state": "active"
    }
    

Java

    // Define Barcode
    Barcode barcode = new Barcode().setType("qrCode")
        .setValue("28343E3")
        .setAlternateText("12345");

    // Define Points
    LoyaltyPoints points = new LoyaltyPoints()
        .setLabel("Points")
        .setPointsType("points")
        .setBalance(new LoyaltyPointsBalance().setString("500"));

    // Define Text Module Data
    List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();
    TextModuleData textModuleData = new TextModuleData()
        .setHeader("Jane's Baconrista Rewards")
        .setBody(
            "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List<Uri> uris = new ArrayList<Uri>();
    Uri uri1 = new Uri().setDescription("My Baconrista Account")
        .setUri("http://www.baconrista.com/myaccount?id=1234567890");
    uris.add(uri1);
    LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

    // Define Info Module
    List<LabelValue> row0cols = new ArrayList<LabelValue>();
    LabelValue row0col0 = new LabelValue().setLabel("Next Reward in")
        .setValue("2 coffees");
    LabelValue row0col1 = new LabelValue().setLabel("Member Since")
        .setValue("01/15/2013");
    row0cols.add(row0col0);
    row0cols.add(row0col1);

    List<LabelValue> row1cols = new ArrayList<LabelValue>();
    LabelValue row1col0 = new LabelValue().setLabel("Local Store")
        .setValue("Mountain View");
    row1cols.add(row1col0);

    List<LabelValueRow> rows = new ArrayList<LabelValueRow>();
    LabelValueRow row0 = new LabelValueRow().setColumns(row0cols);
    LabelValueRow row1 = new LabelValueRow().setColumns(row1cols);

    rows.add(row0);
    rows.add(row1);

    InfoModuleData infoModuleData = new InfoModuleData()
        .setShowLastUpdateTime(true)
        .setLabelValueRows(rows);

    // Define general messages
    List<Message> messages = new ArrayList<Message>();
    Message message = new Message()
        .setHeader("Hi Jane!")
        .setBody("Thanks for joining our program. Show this message to " +
            "our barista for your first free coffee on us!");
    messages.add(message);

    // Define Wallet Instance
    LoyaltyObject object = new LoyaltyObject()
        .setClassId('2945482443380251551.ExampleClass1').setId('2945482443380251551.ExampleObject1')
        .setState("active").setBarcode(barcode).setInfoModuleData(infoModuleData)
        .setAccountName("Jane Doe").setTextModulesData(textModulesData)
        .setMessages(messages).setLinksModuleData(linksModuleData)
        .setAccountId("1234567890").setLoyaltyPoints(points);
    

PHP

    $barcode = new Google_Service_Walletobjects_Barcode();
    $barcode->setAlternateText('12345');
    $barcode->setType('qrCode');
    $barcode->setValue('28343E3');
    // Define text module data.
    $textModulesData = array(
        array(
            'header' => 'Janes Baconrista Rewards',
            'body' => 'Save more at your local Mountain View store Jane. ' .
                      'You get 1 bacon fat latte for every 5 coffees purchased. ' .
                      'Also just for you, 10% off all pastries in the Mountain View store.'
        )
    );
    // Define links module data.
    $linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
    $uris = array (
        array(
            'uri' => 'http://www.baconrista.com/myaccount?id=1234567890',
            'kind' => 'walletobjecs#uri',
            'description' => 'My Baconrista Account'
        )
    );
    $linksModuleData->setUris($uris);
    // Define label values.
    $labelValueRows = array(
        array(
            'columns' => array(
                array(
                    'label' => 'Next Reward in',
                    'value' => '2 coffees'
                ), array(
                    'label' => 'Member Since',
                    'value' => '01/15/2013'
                )
            )
        ),
        array(
            'columns' => array(
                array(
                    'label' => 'Local Store',
                    'value' => 'Mountain View'
                )
            )
        )
    );
    // Define info module data.
    $infoModuleData = new Google_Service_Walletobjects_InfoModuleData();
    $infoModuleData->setShowLastUpdateTime(true);
    $infoModuleData->setLabelValueRows($labelValueRows);
    // Messages to be displayed.
    $messages = array(array(
        'header' => 'Jane, welcome to Banconrista Rewards!',
        'body' => 'Thanks for joining our program. Show this message to '.
                  'our barista for your first free coffee on us!',
        'kind' => 'walletobjects#walletObjectMessage'
    ));
    // Reward points a user has.
    $points = new Google_Service_Walletobjects_LoyaltyPoints();
    $balance = new Google_Service_Walletobjects_LoyaltyPointsBalance();
    $balance->setString('500');
    $points->setBalance($balance);
    $points->setLabel('Points');
    $points->setPointsType('points');
    // Create wallet object.
    $wobObject = new Google_Service_Walletobjects_LoyaltyObject();
    $wobObject->setClassId('2945482443380251551.ExampleClass1');
    $wobObject->setId('2945482443380251551.ExampleObject1');
    $wobObject->setState('active');
    $wobObject->setBarcode($barcode);
    $wobObject->setInfoModuleData($infoModuleData);
    $wobObject->setLinksModuleData($linksModuleData);
    $wobObject->setTextModulesData($textModulesData);
    $wobObject->setAccountName('Jane Doe');
    $wobObject->setAccountId('1234567890');
    $wobObject->setLoyaltyPoints($points);
    $wobObject->setMessages($messages);
    

Python

    loyalty_object = {
      'classId' : '2945482443380251551.ExampleClass1',
      'id' : '2945482443380251551.ExampleObject1',
      'accountId': '1234567890',
      'accountName': 'Jane Doe',
      'barcode': {
          'alternateText' : '12345',
          'type' : 'qrCode',
          'value' : '28343E3'
      },
      'textModulesData': [{
        'header': 'Jane\'s Baconrista Rewards',
        'body': 'Save more at your local Mountain View store Jane. ' +
                ' You get 1 bacon fat latte for every 5 coffees purchased.  ' +
                'Also just for you, 10% off all pastries in the Mountain View store.'
      }],
      'linksModuleData': {
        'uris': [
          {
            'kind': 'walletobjects#uri',
            'uri': 'http://www.baconrista.com/myaccount?id=1234567890',
            'description': 'My Baconrista Account'
          }]
      },
      'infoModuleData': {
        'labelValueRows': [{
            'columns': [{
              'label': 'Next Reward in',
              'value': '2 coffees'
            }, {
              'label': 'Member Since',
              'value': '01/15/2013'
            }]
          },{
            'columns': [{
              'label': 'Local Store',
              'value': 'Mountain View'
            }]
        }],
        'showLastUpdateTime': 'true'
      },
      'messages': [{
          'header': 'Jane, welcome to Banconrista Rewards',
          'body': 'Thanks for joining our program. Show this message to ' +
                  'our barista for your first free coffee on us!',
          'kind': 'walletobjects#walletObjectMessage'
      }],
      'loyaltyPoints': {
          'balance': {
              'string': '500'
          },
          'label': 'Points',
          'pointsType': 'points'
      },
      'state': 'active'
    }
    

使用 OAuth 2.0 服務帳戶私密金鑰,將 LoyaltyObject 編碼並插入 JWT。下列程式碼片段顯示如何以各種語言將 JWT 編碼。「通訊協定」分頁顯示未編碼的 JWT。如需 JWT 中各欄位的說明,請參考「Google Pay API for Passes JWT」。

通訊協定

    {
      "iss": "example_service_account@developer.gserviceaccount.com",
      "aud": "google",
      "typ": "savetoandroidpay",
      "iat": 1368029586,
      "payload": {
        "eventTicketClasses": [{
          ... //Event ticket Class JSON
        }],
        "eventTicketObjects": [{
          ... //Event ticket Object JSON
        }],
        "flightClasses": [{
          ... //Flight Class JSON
        }],
        "flightObjects": [{
          ... //Flight Object JSON
        }],
        "giftCardClasses": [{
          ... //Gift card Class JSON
        }],
        "giftCardObjects": [{
          ... //Gift card Object JSON
        }],
        "loyaltyClasses": [{
          ... //Loyalty Class JSON
        }],
        "loyaltyObjects": [{
          ... //Loyalty Object JSON
        }],
        "offerClasses": [{
          ... //Offer Class JSON
        }],
        "offerObjects": [{
          ... //Offer Object JSON
        }],
        "transitClasses": [{
          ... //Transit Class JSON
        }],
        "transitObjects": [{
          ... //Transit Object JSON
        }]
      },
      "origins": ["http://baconrista.com", "https://baconrista.com"]
    }
    

Java

    WobCredentials credentials = null;
    WobUtils utils = null;

    // Instantiate the WobUtils class which contains handy functions
    // Wob utils can be found in the quickstart sample
    try {
      credentials = new WobCredentials(
        ServiceAccountEmailAddress,
        ServiceAccountPrivateKeyPath,
        ApplicationName,
        IssuerId);
      utils = new WobUtils(credentials);
    } catch (GeneralSecurityException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    // Add valid domains for the Save to Wallet button
    List<String> origins = new ArrayList<String>();
    origins.add("http://baconrista.com");
    origins.add("https://baconrista.com");
    origins.add(req.getScheme() + "://" + req.getServerName() + ":" + req.getLocalPort());

    //Generate Objects and Classes here
    //........

    WobPayload payload = new WobPayload();
    payload.addObject({WalletObject/WalletClass});

    // Convert the object into a Save to Android Pay Jwt
    String jwt = null;
    try {
      jwt = utils.generateSaveJwt(payload, origins);
    } catch (SignatureException e) {
      e.printStackTrace();
    }
    

PHP

    $requestBody = [
      "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
      "aud" => "google",
      "typ" => "savetoandroidpay",
      "iat"=> time(),
      "payload" => {
        "eventTicketClasses" => [ ], # Event ticket classes
        "eventTicketObjects" => [ ], # Event ticket objects
        "flightClasses" => [ ],      # Flight classes
        "flightObjects" => [ ],      # Flight objects
        "giftCardClasses" => [ ],    # Gift card classes
        "giftCardObjects" => [ ],    # Gift card objects
        "loyaltyClasses" => [ ],     # Loyalty classes
        "loyaltyObjects" => [ ],     # Loyalty objects
        "offerClasses" => [ ],       # Offer classes
        "offerObjects" => [ ],       # Offer objects
        "transitClasses" => [ ],     # Transit classes
        "transitObjects" => [ ]      # Transit objects
      },
      "origins" => ["http://baconrista.com", "https://baconrista.com"]
    ]
    // Generate the Save to Android Pay Jwt
    echo $jwt = $assertObj->makeSignedJwt($requestBody, $client);
    

Python

    jwt = {
      'iss': config.SERVICE_ACCOUNT_EMAIL_ADDRESS,
      'aud': 'google',
      'typ': 'savetoandroidpay',
      'iat':  int(time.time()),
      'payload': {
        'webserviceResponse': {
          'result': 'approved',
          'message': 'Success.'
        },
        'eventTicketClasses': [], # Event ticket classes
        'eventTicketObjects': [], # Event ticket objects
        'flightClasses': [],      # Flight classes
        'flightObjects': [],      # Flight objects
        'giftCardClasses': [],    # Gift card classes
        'giftCardObjects': [],    # Gift card objects
        'loyaltyClasses': [],     # Loyalty classes
        'loyaltyObjects': [],     # Loyalty objects
        'offerClasses': [],       # Offer classes
        'offerObjects': [],       # Offer objects
        'transitClasses': [],     # Transit classes
        'transitObjects': []      # Transit objects
      },
      'origins' : ['http://baconrista.com', 'https://baconrista.com']
    }

    // Generate the Save to Android Pay Jwt
    signer = crypt.Signer.from_string(app_key)
    signed_jwt = crypt.make_signed_jwt(signer, jwt)
    response = webapp2.Response(signed_jwt)
    

經編碼的 JWT 的長度上限為 1800 個字元。您的 JWT 不應超過此限制。如果長度超過 1800 個字元,就會遭到網路瀏覽器截斷而無法儲存。經編碼並插入 JWT 的物件應精簡,且僅包含與使用者相關的資料。請試著將大部分的資料存放在物件的類別中,並在建立 JWT 前先建立類別。對於超過字元限制的大型物件,請考慮使用 REST API 來建立物件,且在 JWT 中只傳送物件 ID。

填入產生的 JWT 和類別 ID:

https://pay.google.com/gp/v/save/{jwt_generated}

務必在網址中的參數前方加上斜線。

深層連結網址的長度上限為 1800 個字元。您的深層連結不應超過此限制。如果長度超過 1800 個字元,就會遭到網路瀏覽器截斷而無法儲存。經編碼並插入 JWT 的物件應精簡,且僅包含與使用者相關的資料。請試著將大部分的資料存放在物件的類別中,並在建立 JWT 前先建立類別。對於超過字元限制的大型物件,請考慮使用 REST API 來建立物件,且在 JWT 中只傳送物件 ID。

請參考品牌規範,瞭解如何下載 [儲存至 Google Pay] 按鈕圖片,以及如何正確放置圖片並加上您的連結。如要進一步瞭解深層連結與 [儲存至 Google Pay],請觀看儲存至 Android Pay 深層連結簡介影片。

透過前往動作,您可以在 Gmail 中將頂層按鈕放置於電子郵件的主旨行。舉例來說,您可能想要加入標示為 [儲存至 Google Pay] 的按鈕,此按鈕會顯示在電子郵件的主旨行,讓使用者直接從收件匣儲存優惠。如果要啟用此功能,請使用上方深層連結在電子郵件中加入「檢視動作」。

從原生 Android 應用程式中操作

您可以使用下列方法將 [儲存至 Google Pay] 按鈕新增至您的原生 Android 應用程式:

利用下列步驟,從應用程式將票證儲存到 Google Pay:

  1. 完成在電子郵件或簡訊中新增連結一節所述的步驟。
  2. 使用 ACTION_VIEW 意圖,透過 [儲存至 Google Pay] 按鈕開啟深層連結。

    確認觸發意圖的按鈕符合品牌規範的規定。

以下是流程摘要的範例:

  1. 在使用者儲存票證以前,系統會透過 REST API 在後端建立類別。
  2. 使用者提出票證儲存要求時,您的伺服器後端會將 JWT 傳送至代表物件的 Android 用戶端應用程式。
  3. 您的 Android 用戶端應用程式包含符合品牌規範的 [儲存至 Google Pay] 按鈕。使用者點選按鈕之後,系統會開啟 URI 的 ACTION_VIEW 意圖,其路徑中包含該組 JWT。請見下方例子:
        https://pay.google.com/gp/v/save/{jwt_generated}
        

使用 JWT POST 要求方法

您可以選擇透過 JWT POST 要求方法,為 Android 應用程式建立航班機票或活動票券類別與物件。如果您較難實作物件儲存前用於建立及插入類別的後端工作,這種方法就能派上用場。這個方法非常適合用於活動票券和登機證,因為這類票證會隨著時間建立許多類別。流程概述如下:

  1. 使用者登機報到或使用活動票券時,您的伺服器後端會將「同時」包含類別和物件的 JWT 轉譯至 Android 用戶端應用程式。
  2. 您的 Android 用戶端應用程式包含符合品牌規範的 [儲存至 Google Pay] 按鈕。當您點選按鈕時,就會發生下列情況:
    1. POST 要求透過 HTTPS 將 JWT 傳送至 Google 端點。
    2. 系統會傳回 HTTP 回應結果內容中的 URI,方便您在開啟 ACTION_VIEW 意圖時使用。

JWT POST 要求方法還必須具備 API 金鑰,以做為查詢參數附加至 REST API 呼叫。

建立類別

只有在取得先前未曾儲存過的 class.id 時,後端才會建立新類別。因此,雖然您可能會透過 JWT 將類別詳細資料傳送至 Google 多次,後端仍會將該類別視為已儲存,而不會在每次儲存登機證時都建立新的類別。

更新類別

使用者儲存第一張登機證之後,系統就會一併儲存物件和類別。在正常情況下,您可以搭配使用 class.id 和 REST API 來執行 ADDMESSAGEGETLISTPATCHUPDATE 作業。

如要變更類別詳細資料,您必須使用 Class Update API。如果您已透過 class.id=XYZ 建立類別和其他幾項類別詳細資料,之後卻嘗試透過 class.id=XYZ 建立含有不同類別詳細資料的類別,則系統仍會保留原本的類別,不會套用任何變更。

JWT 格式

我們的 Google Pay API for Passess JWT 參考說明文件詳述傳送 JWT 時應採用的格式。以這項 payload 而言,您會傳送一個物件項目 (用於代表您要建立的物件) 和一個類別項目 (當中包含您先前建立的類別)。

HTTP 要求

您可以使用 INSERT 方法插入 JWT 中指定的類別和物件,而且必須將 API 金鑰設為查詢參數。

JWT INSERT 方法

在您提供 JWT 後,INSERT 方法會插入在 JWT 中指定的類別和物件。如果插入成功,要求就會傳回 200 HTTP 回應。

HTTP 要求
    POST https://walletobjects.googleapis.com/walletobjects/v1/jwt/
    

授權

這項要求不需經過授權,不過 JWT 必須使用 RSA-SHA256 進行簽署,簽署金鑰為 OAuth 服務帳戶產生的金鑰。

要求內容

在要求內容中,請提供具有以下結構的資料:

    { “jwt” : string }
    

回應內容

如果要求成功,這個方法就會在回應內容中傳回下列結構:

    {
        "saveUri": string,
        "resources": {
          "eventTicketClasses": [ eventTicketClass resource, ... ],
          "eventTicketObjects": [ eventTicketObject resource, ... ],
          "flightClasses": [ flightClass resource, ... ],
          "flightObjects": [ flightObject resource, ... ],
          "giftCardClasses": [ giftCardClass resource, ... ],
          "giftCardObjects": [ giftCardObject resource, ... ],
          "loyaltyClasses": [ loyaltyClass resource, ... ],
          "loyaltyObjects": [ loyaltyObject resource, ... ],
          "offerClasses": [ offerClass resource, ... ],
          "offerObjects": [ offerObject resource, ... ],
          "transitClasses": [ transitClass resource, ... ],
          "transitObjects": [ transitObject resource, ... ]
        }
    }
    

在您開啟 saveUri 這個 URI 之後,使用者就能將 JWT 中指定的物件儲存至 Google 帳戶。不過請注意,系統傳回的 URI 效期僅有一週。

如要瞭解詳情,請參閱 JWT 端點參考資料

流程圖

如要查看流程圖,請參閱一般 API 流程一文。

使用原生 Android SDK

Android API 可協助您將票證儲存到 Google Pay。只要將 [儲存至 Google Pay] 按鈕整合至您的應用程式,您的客戶就能輕鬆地將票證儲存至 Google Pay。

下列步驟說明如何針對會員票證,新增 [儲存至 Google Pay] 按鈕。

1. 將 [儲存至 Google Pay] 按鈕新增至您的 UI。

第一步請將 [儲存至 Google Pay] 按鈕新增至您的應用程式。Google Pay 會提供 Android SDK 按鈕給您,讓您整合至應用程式。您可在品牌規範中找到按鈕素材資源。

此工具包內含按鈕的向量圖片。

如果要在應用程式中整合按鈕,請將按鈕圖片從工具包複製到應用程式的 res 資料夾,並新增下列程式碼至您的 Android 版面配置檔案。請注意,每個按鈕都需要唯一的 contentDescription 字串和 minWidth 值 (除了正確的 src 值以外)。

    <ImageButton
                 android:layout_width="match_parent"
                 android:layout_height="48dp"
                 android:minWidth="200dp"
                 android:clickable="true"
                 android:src="@drawable/s2ap" />
    

按鈕的 layout_height 應為 48 dp,minWidth 則須為 200 dp。

2. 建立會員類別

您可透過 Google Pay API for Passes Merchant Center 來建立類別。在 Merchant Center 的「類別」頁面中選取 [建立類別],即可建立 loyaltyclass。紅色外框的輸入欄位為必填,其餘欄位則為選填。針對所有具有網址的欄位,確認連結可公開存取。建立重要物件時,系統會參考已建立的類別。

3. 建立會員物件

下一步是建立會員物件。下面是使用建立工具模式來建立會員物件的範例:

    // Define Points
    LoyaltyPoints points = LoyaltyPoints.newBuilder()
        .setLabel("Points")
        .setType("points")
        .setBalance(LoyaltyPointsBalance.newBuilder().setString("500").build()).build();

    // Define Text Module Data
    List textModulesData = new ArrayList();
    TextModuleData textModuleData = new TextModuleData("Jane's Baconrista Rewards", "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List uris = new ArrayList();
    UriData uri1 = new UriData("http://www.baconrista.com/myaccount?id=1234567890","My Baconrista Account");
    uris.add(uri1);

    List imageUris = new ArrayList();
    UriData uri2 = new UriData("http://examplesite/images/exampleimage2.jpg", "Image Description");
    imageUris.add(uri2);

    // Define Info Module
    List row0cols = new ArrayList();
    LabelValue row0col0 = new LabelValue("Next Reward in","2 coffees");
    LabelValue row0col1 = new LabelValue("Member Since", "01/15/2013");
    row0cols.add(row0col0);
    row0cols.add(row0col1);

    List row1cols = new ArrayList();
    LabelValue row1col0 = new LabelValue("Local Store", "Mountain View");
    row1cols.add(row1col0);

    List rows = new ArrayList();
    LabelValueRow row0 = LabelValueRow.newBuilder().addColumns(row0cols).build();
    LabelValueRow row1 = LabelValueRow.newBuilder().addColumns(row1cols).build();

    rows.add(row0);
    rows.add(row1);

    // Define general messages
    List messages = new ArrayList();
    WalletObjectMessage message =  WalletObjectMessage.newBuilder()
        .setHeader("Hi Jane!")
        .setBody("Thanks for joining our program. Show this message to " +
            "our barista for your first free coffee on us!")
        .build();
    messages.add(message);

    // Define Geolocations

    LatLng location = new LatLng(37.422601, -122.085286);

    List locations = new ArrayList();
    locations.add(location);

    LoyaltyWalletObject wob = LoyaltyWalletObject
        .newBuilder()
        .setClassId("2967745143867465930.LoyaltyClass")
        .setId("2967745143867465930.LoyaltyObject")
        .setState(WalletObjectsConstants.State.ACTIVE)
        .setAccountId("1234567890")
        .setAccountName("Jane Doe")
        .setIssuerName("Baconrista")
        .setProgramName("Baconrista Rewards")
        .setBarcodeType("qrCode")
        .setBarcodeValue("28343E3")
        .setBarcodeAlternateText("12345")
        .setLoyaltyPoints(points)
        .addTextModulesData(textModulesData)
        .addLinksModuleDataUris(uris)
        .addInfoModuleDataLabelValueRows(rows)
        .addImageModuleDataMainImageUris(imageUris)
        .addMessages(messages)
        .addLocations(locations)
        .build();

此物件是使用下節所述之 createWalletObject 呼叫取得的第一個參數。

4. 初始化要求以儲存會員物件

walletObjectsClient 類別會成為電子錢包物件函式的進入點。

下列程式碼片段示範應用程式如何為用戶端建立例項,以將物件儲存至 Google Pay:

    CreateWalletObjectsRequest request = new CreateWalletObjectsRequest(wob);
    Wallet.WalletOptions walletOptions = new Wallet.WalletOptions.Builder()
            .setTheme(WalletConstants.THEME_LIGHT)
            .setEnvironment(WalletConstants.ENVIRONMENT_PRODUCTION)
            .build();

    walletObjectsClient = Wallet.getWalletObjectsClient(this, walletOptions);
    Task task = walletObjectsClient.createWalletObjects(request);
    AutoResolveHelper.resolveTask(task, this, SAVE_TO_ANDROID);
    

您也可使用 GoogleApiClient 來初始化要求:

    Wallet.WalletObjects.createWalletObjects(googleApiClient, request, SAVE_TO_ANDROID);
    

5. 處理 onActivityResult

定義 onActivityResult 來針對成功、失敗或被取消的作業做出回應,如下所示:

    public void onActivityResult(int requestCode, int resultCode, Intent data){
      EditText textBox = (EditText) findViewById(R.id.s2wResponse);

      switch(requestCode){
        case SAVE_TO_ANDROID:
          switch (resultCode) {
            case Activity.RESULT_OK:
              textBox.setText("saved");
              break;
            case Activity.RESULT_CANCELED:
              textBox.setText("canceled");
              break;
            default:
              int errorCode =
                  data.getIntExtra(
                      WalletConstants.EXTRA_ERROR_CODE, -1);
              textBox.setText("failed error code: " + errorCode);
              break;
          }