ขั้นตอนการพัฒนาบัตร Google Wallet

Google Wallet API มีชุดประเภทบัตรที่กำหนดไว้ล่วงหน้าและปรับให้เหมาะกับกรณีการใช้งานเฉพาะ เช่น บัตรของขวัญ บอร์ดดิ้งพาส ตั๋วเข้างาน และอื่นๆ นอกจากนี้ ยังมีประเภทบัตรทั่วไปสำหรับกรณีการใช้งานที่ไม่มีประเภทบัตรที่เฉพาะเจาะจงด้วย

บทความนี้จัดทำขึ้นเพื่อทำความคุ้นเคยกับขั้นตอนพื้นฐานที่จำเป็นในการสร้างและออกบัตรโดยใช้ Google Wallet API การดำเนินการบางขั้นตอนที่อธิบายไว้ด้านล่างมีหลายวิธี แต่ในระดับสูง บัตรทุกประเภทจะสร้างขึ้นด้วยขั้นตอนการพัฒนาพื้นฐานเดียวกัน

สำหรับคำแนะนำโดยละเอียดเกี่ยวกับการสร้างบัตร โปรดดูคำแนะนำสำหรับเว็บ อีเมล และ SMS หรือแอป Android

มีไว้เพื่ออะไร

คลาสบัตรกำหนดชุดพร็อพเพอร์ตี้ที่ใช้ร่วมกันในบัตรหลายใบ คล้ายกับเทมเพลต ตัวอย่างเช่น หากคุณออกตั๋วกิจกรรม คลาส Passes จะกำหนดช่องที่เหมือนกันในตั๋วทั้งหมด เช่น ชื่อกิจกรรม วันที่ และเวลา

บัตรทุกใบที่คุณออกจะต้องอ้างอิงถึงคลาส Passes นอกจากนี้ คุณต้องกำหนดรหัสที่ไม่ซ้ำกันให้กับบัตรทุกคลาสที่คุณสร้าง ซึ่งใช้อ้างอิงรหัสเมื่อสร้างบัตร

วิธีการทำงาน

คลาส Passes จะกำหนดไว้ในรูปแบบ JSON และสามารถสร้างด้วย Google Wallet REST API, Android SDK หรือในคอนโซลธุรกิจของ Google Wallet ได้

แสดงตัวอย่างคลาสของบัตร

{
  "id": "ISSUER_ID.EVENT_CLASS_ID",
  "issuerName": "[TEST ONLY] Heraldic Event",
  "localizedIssuerName": {
    "defaultValue": {
      "language": "en-US",
      "value": "[TEST ONLY] Heraldic Event"
    }
  },
  "logo": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "LOGO_IMAGE_DESCRIPTION"
      }
    }
  },
  "eventName": {
    "defaultValue": {
      "language": "en-US",
      "value": "Google Live"
    }
  },
  "venue": {
    "name": {
      "defaultValue": {
        "language": "en-US",
        "value": "Shoreline Amphitheater"
      }
    },
    "address": {
      "defaultValue": {
        "language": "en-US",
        "value": "ADDRESS_OF_THE_VENUE"
      }
    }
  },
  "dateTime": {
    "start": "2023-04-12T11:30"
  },
  "reviewStatus": "UNDER_REVIEW",
  "hexBackgroundColor": "#264750",
  "heroImage": {
    "sourceUri": {
      "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
    },
    "contentDescription": {
      "defaultValue": {
        "language": "en-US",
        "value": "HERO_IMAGE_DESCRIPTION"
      }
    }
  }
}
    

มีไว้เพื่ออะไร

ออบเจ็กต์ Passes จะกำหนดพร็อพเพอร์ตี้ของบัตรที่ไม่ซ้ำกัน ซึ่งจะออกให้กับผู้ใช้ที่เฉพาะเจาะจง เช่น ออบเจ็กต์บัตรสำหรับตั๋วเข้างานจะกำหนดช่องเฉพาะของตั๋วใบหนึ่งๆ เช่น หมายเลขที่นั่งหรือคิวอาร์โค้ดสำหรับตั๋วนั้นๆ

เมื่อสร้างออบเจ็กต์ Passes แล้ว Google Wallet API จะจัดเก็บบัตรใบใหม่และเชื่อมโยงกับบัญชีผู้ออกบัตร บัตรที่จัดเก็บไว้นี้เป็นการรวมพร็อพเพอร์ตี้เฉพาะของออบเจ็กต์บัตรและพร็อพเพอร์ตี้เทมเพลตของคลาสบัตรที่เกี่ยวข้อง

นอกจากนี้ คุณต้องกำหนดรหัสที่ไม่ซ้ำกันให้กับออบเจ็กต์ Passes แต่ละรายการ ซึ่งจะใช้อ้างอิงเมื่อออกบัตร

วิธีการทำงาน

ออบเจ็กต์ Passes ได้รับการกำหนดรูปแบบ JSON และสามารถสร้างด้วย Google Wallet REST API หรือ Android SDK

แสดงตัวอย่างออบเจ็กต์บัตร

{
  "id": "ISSUER_ID.OBJECT_ID",
  "classId": "ISSUER_ID.EVENT_CLASS_ID",
  "state": "ACTIVE",
  "seatInfo": {
    "seat": {
      "defaultValue": {
        "language": "en-us",
        "value": "5"
      }
    },
    "row": {
      "defaultValue": {
        "language": "en-us",
        "value": "G"
      }
    },
    "section": {
      "defaultValue": {
        "language": "en-us",
        "value": "40"
      }
    },
    "gate": {
      "defaultValue": {
        "language": "en-us",
        "value": "3A"
      }
    }
  },
  "barcode": {
    "type": "QR_CODE",
    "value": "BARCODE_VALUE",
    "alternateText": ""
  }
}
    

มีไว้เพื่ออะไร

หากต้องการออกบัตรผ่านให้กับผู้ใช้ คลาส Passes และออบเจ็กต์ Passes ต้องเข้ารหัสเป็น JSON Web Token (JWT) รูปแบบ JWT เป็นมาตรฐานร่วมและเปิดกว้างสำหรับการเป็นตัวแทนในการอ้างสิทธิ์ระหว่าง 2 ฝ่าย ในกรณีการออกบัตรด้วย Google Wallet API ระบบจะใช้ JWT เพื่อส่งการอ้างสิทธิ์ว่าผู้ใช้มีสิทธิ์เข้าถึงบัตรหนึ่งๆ ที่เชื่อมโยงกับบัญชีผู้ออกบัตรของคุณ

เมื่อมีการส่ง JWT ไปยัง Google Wallet API ระบบจะใช้ข้อมูลที่เข้ารหัสเพื่อระบุบัตรที่เฉพาะเจาะจงและออกบัตรให้กับผู้ใช้ หากมีการออกบัตรแล้ว ข้อมูลนี้จะช่วยให้ Google Wallet API ระบุได้ว่าบัตรดังกล่าวซ้ำกัน เพื่อไม่ให้ระบบเพิ่มบัตรลงใน Google Wallet ของผู้ใช้มากกว่า 1 ครั้ง

วิธีการทำงาน

JWT จะกำหนดเป็นรูปแบบ JSON ตามข้อกำหนด JWT หากต้องการกำหนด JWT สำหรับการออกบัตรด้วย Google Wallet API คุณต้องระบุข้อมูลเกี่ยวกับบัตรที่ต้องการออกในพร็อพเพอร์ตี้ payload ของ JWT

แสดงตัวอย่าง JWT

{
  "iss": "issuer@example.com",
  "aud": "google",
  "typ": "savetowallet",
  "iat": 1696877738,
  "origins": [
    "www.example.com"
  ],
  "payload": {
    "eventTicketObjects": [
      {
        "id": "ISSUER_ID.LOYALTY_OBJECT_SUFFIX"
      }
    ]
  }
}
    

มีไว้เพื่ออะไร

JWT ทั้งหมดที่ส่งไปยัง Google Wallet API เพื่อออกบัตรจะต้องได้รับการลงนามด้วยข้อมูลเข้าสู่ระบบที่คุณให้ไว้ก่อนหน้านี้ใน Google Wallet Business Console การลงนามจะใช้ข้อมูลเข้าสู่ระบบของคุณในการเข้ารหัส JWT เพื่อให้บัตรของคุณยังคงปลอดภัย และเพื่อให้ Google Wallet API สามารถตรวจสอบสิทธิ์ว่ารายละเอียดบัตรที่เข้ารหัสในบัตรนั้นถูกต้องและเชื่อมโยงกับบัญชีผู้ออกบัตร

วิธีการทำงาน

ไลบรารีของไคลเอ็นต์ Google Wallet และ Android SDK มอบวิธีที่สะดวกในการลงนาม JWT ของคุณ นอกจากนี้ ยังมีไลบรารีโอเพนซอร์สจำนวนมากที่พร้อมรองรับความซับซ้อนของการรับรองโค้ดให้คุณเลือก

สำหรับผู้ที่ใช้ Google Wallet REST API เพื่อออกบัตร JWT จะได้รับการลงนามด้วยคีย์บัญชีบริการ Google Cloud สำหรับผู้ที่ใช้ Google Wallet Android SDK ทาง SDK จะจัดการการลงนาม JWT ด้วยลายนิ้วมือ SHA-1 ของใบรับรอง App Signing โดยอัตโนมัติ

เพื่อปกป้องข้อมูลรับรองของคุณ JWT ควรเซ็นชื่อเฉพาะบนเซิร์ฟเวอร์ของคุณหรือใช้ Google Wallet Android SDK ในแอปของคุณ

แสดงตัวอย่างการรับรองโค้ด

Java

  // Create the JWT as a HashMap object
  HashMap claims = new HashMap();
  claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
  claims.put("aud", "google");
  claims.put("origins", Arrays.asList("www.example.com"));
  claims.put("typ", "savetowallet");

  // Create the Google Wallet payload and add to the JWT
  HashMap payload = new HashMap();
  payload.put("eventTicketObjects", Arrays.asList(newObject));
  claims.put("payload", payload);

  // Google Cloud service account credentials are used to sign the JWT
  Algorithm algorithm =
      Algorithm.RSA256(
          null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
  String token = JWT.create().withPayload(claims).sign(algorithm);
        

Node.JS

  // Create the JWT claims
  let claims = {
    iss: this.credentials.client_email,
    aud: 'google',
    origins: ['www.example.com'],
    typ: 'savetowallet',
    payload: {
      eventTicketObjects: [newObject]
    },
  };

  // The service account credentials are used to sign the JWT
  let token = jwt.sign(claims, this.credentials.private_key, { algorithm: 'RS256' });
        

Python

  # Create the JWT claims
  claims = {
      'iss': self.credentials.service_account_email,
      'aud': 'google',
      'origins': ['www.example.com'],
      'typ': 'savetowallet',
      'payload': {
          # The listed classes and objects will be created
          'eventTicketObjects': [new_object]
      }
  }

  # The service account credentials are used to sign the JWT
  signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
  token = jwt.encode(signer, claims).decode('utf-8')
        

มีไว้เพื่ออะไร

เมื่อคุณสร้าง JWT ที่ลงนามแล้ว คุณก็พร้อมที่จะออกบัตรให้กับผู้ใช้ Google Wallet ได้! ซึ่งทำได้ด้วยการแสดงปุ่มหรือลิงก์ "เพิ่มลงใน Google Wallet" แก่ผู้ใช้ เมื่อผู้ใช้คลิกปุ่มหรือไฮเปอร์ลิงก์ ระบบจะส่ง JWT ที่ลงนามแล้วไปยัง Google Wallet API ซึ่งจะถอดรหัสโดยใช้ข้อมูลเข้าสู่ระบบที่คุณบันทึกไว้ เมื่อลายเซ็น JWT ได้รับการตรวจสอบสิทธิ์แล้ว ระบบจะออกบัตรให้ผู้ใช้เพื่อบันทึกใน Google Wallet

วิธีการทำงาน

หากต้องการสร้างปุ่ม "เพิ่มลงใน Google Wallet" สำหรับแอป Android ให้ใช้ Google Wallet Android SDK ซึ่งมอบวิธีสร้างปุ่มดังกล่าว สำหรับแพลตฟอร์มอื่นๆ ทั้งหมด ซึ่งรวมถึงเว็บ อีเมล และ SMS ให้สร้างไฮเปอร์ลิงก์ในรูปแบบ https://pay.google.com/gp/v/save/<signed_jwt> หากเป็นไปได้ เราขอแนะนำให้คุณส่งลิงก์นี้ให้กับผู้ใช้เป็นปุ่ม "เพิ่มลงใน Google Wallet"

ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ปุ่ม "เพิ่มลงใน Google Wallet" ได้ที่หลักเกณฑ์การใช้แบรนด์ Google Wallet API

แสดงตัวอย่างโค้ด

  https://pay.google.com/gp/v/save/<signed_jwt>
        

Android SDK

  private lateinit var walletClient: PayClient
  private val addToGoogleWalletRequestCode = 1000
  private lateinit var addToGoogleWalletButton: View

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    walletClient = Pay.getClient(this)
    addToGoogleWalletButton.setOnClickListener {
      walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)
    }
  }
        

เมื่อผู้ใช้บันทึกบัตรที่ออกแล้ว บัตรดังกล่าวจะปรากฏในแอป Google Wallet พร้อมกับบัตรอื่นๆ ที่ผู้ใช้บันทึกไว้

การสร้างออบเจ็กต์บัตรและคลาสบัตรใน JWT

คุณสามารถสร้างประเภทบัตรและออบเจ็กต์บัตรล่วงหน้าได้โดยใช้ Google Wallet REST API หรือ Android SDK เมื่อสร้างเรียบร้อยแล้ว ระบบจะใช้บัตรเหล่านั้นเพื่อออกบัตรโดยอ้างอิงบัตรประจำตัว

นอกจากนี้ คุณยังสร้างคลาสและออบเจ็กต์บัตร "ทันเวลา" ได้ด้วยการฝัง JSON ของออบเจ็กต์เหล่านั้นโดยตรงใน JWT ที่ใช้ในการออกบัตรให้กับผู้ใช้ ด้วยวิธีนี้ Google Wallet API จะสร้างออบเจ็กต์คลาสและบัตรของบัตรขึ้นเมื่อมีการส่ง JWT ที่ลงชื่อโดยใช้ปุ่มหรือลิงก์ "เพิ่มลงใน Google Wallet"

ตัวอย่างต่อไปนี้แสดง JWT ที่มีคลาส Passes และออบเจ็กต์ Passes ใหม่ซึ่งกำหนดโดยใช้พร็อพเพอร์ตี้ payload.eventTicketClasses และ payload.eventTicketObjects โปรดสังเกตว่าพร็อพเพอร์ตี้เหล่านี้เป็นอาร์เรย์ จึงยอมรับคลาสของบัตรหรือออบเจ็กต์บัตรได้อย่างน้อย 1 รายการ คุณยังสามารถระบุเฉพาะออบเจ็กต์ Passes ใหม่ใน JWT ที่อ้างอิงคลาส Passes ที่มีอยู่ตามรหัสของออบเจ็กต์ได้อีกด้วย

แสดงตัวอย่าง JWT

  {
    "iss": "issuer@example.com",
    "aud": "google",
    "typ": "savetowallet",
    "iat": 1696877738,
    "origins": [
      "www.example.com"
    ],
    "payload": {
      "eventTicketClasses": [{
        "id": "ISSUER_ID.EVENT_CLASS_ID",
        "issuerName": "[TEST ONLY] Heraldic Event",
        "localizedIssuerName": {
          "defaultValue": {
            "language": "en-US",
            "value": "[TEST ONLY] Heraldic Event"
          }
        },
        "logo": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1475721027785-f74eccf877e2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=660&h=660"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "LOGO_IMAGE_DESCRIPTION"
            }
          }
        },
        "eventName": {
          "defaultValue": {
            "language": "en-US",
            "value": "Google Live"
          }
        },
        "venue": {
          "name": {
            "defaultValue": {
              "language": "en-US",
              "value": "Shoreline Amphitheater"
            }
          },
          "address": {
            "defaultValue": {
              "language": "en-US",
              "value": "ADDRESS_OF_THE_VENUE"
            }
          }
        },
        "dateTime": {
          "start": "2023-04-12T11:30"
        },
        "reviewStatus": "UNDER_REVIEW",
        "hexBackgroundColor": "#264750",
        "heroImage": {
          "sourceUri": {
            "uri": "https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1032&h=336"
          },
          "contentDescription": {
            "defaultValue": {
              "language": "en-US",
              "value": "HERO_IMAGE_DESCRIPTION"
            }
          }
        }
      }],
      "eventTicketObjects": [{
        "id": "ISSUER_ID.OBJECT_ID",
        "classId": "ISSUER_ID.EVENT_CLASS_ID",
        "state": "ACTIVE",
        "seatInfo": {
          "seat": {
            "defaultValue": {
              "language": "en-us",
              "value": "5"
            }
          },
          "row": {
            "defaultValue": {
              "language": "en-us",
              "value": "G"
            }
          },
          "section": {
            "defaultValue": {
              "language": "en-us",
              "value": "40"
            }
          },
          "gate": {
            "defaultValue": {
              "language": "en-us",
              "value": "3A"
            }
          }
        },
        "barcode": {
          "type": "QR_CODE",
          "value": "BARCODE_VALUE",
          "alternateText": ""
        }
      }]
    }
  }