將票證儲存至 Google Pay

所有票證類別都有共通的使用方式。舉例來說,所有會員卡、禮物卡、優惠、活動票券、登機證和大眾運輸票證都能以多種方式新增至 Google Pay 應用程式。選取下列其中一種方式即可瞭解詳情:


從原生 Android 應用程式中操作

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

請按照下列步驟將票證從應用程式儲存至 Google Pay:

  1. 完成將「儲存至 Google Pay」按鈕新增至電子郵件或簡訊一節中所述的步驟。
  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. 使用者在登機報到或兌換活動票券時,伺服器後端會向您的 Android 用戶端應用程式提供含有類別「和」物件的 JWT。
  2. 您的 Android 用戶端應用程式含有符合品牌規範的「儲存至 Google Pay」按鈕。點擊按鈕之後,將會發生下列情況:
    1. POST 要求透過 HTTPS 將 JWT 傳送至 Google 端點。
    2. 接著,系統會在 HTTP 回應內容產生後傳送當中的 URI,這個 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 Passes 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 版面配置檔案。請注意,除了正確的 src 值以外,每個按鈕都需要專屬的 contentDescription 字串和 minWidth 值。

<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;
      }