תהליך הפיתוח של כרטיס Google Wallet

Google Wallet API מספק קבוצה מוגדרת מראש של סוגי כרטיסים שמותאמים לתרחישי שימוש ספציפיים, כמו כרטיסי מתנה, כרטיסי עלייה למטוס, כרטיסים לאירועים ועוד. יש גם סוג כרטיס גנרי שמיועד למקרים שבהם סוג כרטיס מסוים לא זמין.

המאמר הזה נועד להציג את השלבים הבסיסיים הנדרשים ליצירה ולהנפקה של כרטיס באמצעות Google Wallet API. יש כמה דרכים לבצע חלק מהשלבים שמפורטים בהמשך, אבל ברמה גבוהה כל סוגי הכרטיסים נוצרים לפי אותו תהליך פיתוח בסיסי.

להדרכה מפורטת בנושא יצירת כרטיס, אפשר לעיין במדריכים לאינטרנט, לאימייל ול-SMS או לאפליקציות ל-Android.

בשביל מה צריך

סיווג כרטיסים מגדיר קבוצה של מאפיינים שמשותפים למספר כרטיסים, בדומה לתבנית. לדוגמה, אם אתם מנפיקים כרטיסים לאירוע, מחלקת הכרטיסים תגדיר שדות זהים בכל הכרטיסים, כמו שם האירוע, תאריך ושעה.

בכל כרטיס שאתם מנפיקים צריך לציין מחלקה של כרטיסים. בנוסף, עליכם להקצות מזהה ייחודי לכל מחלקת כרטיסים שאתם יוצרים. המזהה הזה ישמש לצורך התייחסות אליו בזמן יצירת הכרטיסים.

איך עושים את זה

מחלקה של כרטיסים מוגדרת בפורמט JSON, ואפשר ליצור אותה באמצעות Google Wallet API ל-REST, באמצעות Android SDK או ב-Google Wallet Business Console.

הצגת דוגמה של מחלקת כרטיסים

{
  "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 מגדיר את המאפיינים של כרטיס ייחודי שיונפק למשתמש ספציפי. לדוגמה, אובייקט הכרטיסים של כרטיס לאירוע יגדיר שדות ייחודיים לכרטיס ספציפי, כמו מספר המושב או קוד QR של הכרטיס הזה.

כשנוצר אובייקט Passes (כרטיסים), ה-API של Google Wallet שומר כרטיס חדש ומשייך אותו לחשבון המנפיק. הכרטיס השמור הזה הוא שילוב של המאפיינים הייחודיים של האובייקט 'כרטיסים' ומאפייני התבנית של מחלקת הכרטיסים המשויכת.

כמו כן, עליכם להקצות לכל אובייקט Pass מזהה ייחודי שישמש כהפניה אליו בזמן הנפקת האישור.

איך עושים את זה

אובייקט 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 Class ו-Passes ב-JSON Web Token (JWT). פורמט JWT הוא תקן מקובל ופתוח לייצוג תביעות בין שני צדדים. במקרה של הנפקת כרטיסים באמצעות Google Wallet API, אסימוני JWT משמשים לשליחת הצהרה שלמשתמש יש זכות לגשת לכרטיס ספציפי שמשויך לחשבון המנפיק שלכם.

כאשר JWT נשלח אל Google Wallet API, הנתונים המקודדים משמשים לזיהוי כרטיס ספציפי ולהנפיק אותו למשתמש. אם הכרטיס כבר הונפק, הנתונים האלה מאפשרים ל-Google Wallet API לזהות שהכרטיס הוא עותק כפול, כך שהוא לא יתווסף ל-Google Wallet של המשתמש יותר מפעם אחת.

איך עושים את זה

אסימוני 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. במסגרת החתימה, נעשה שימוש בפרטי הכניסה שלך כדי להצפין את ה-JWT, כך שהכרטיסים נשארים מאובטחים, וכדי לאפשר ל-Google Wallet API לאמת שפרטי הכרטיס שמקודדים בו תקפים ומשויכים לחשבון המנפיק.

איך עושים את זה

ספריות הלקוח של Google Wallet ו-Android SDK מספקות שיטות נוחות לחתימה על אסימוני ה-JWT. יש גם אינספור ספריות קוד פתוח שבעזרתן תוכלו לבחור מביניהן את המורכבות של חתימת קוד.

עבור מי שמשתמש ב-Google Wallet API ל-REST כדי להנפיק כרטיסים, ה-JWT חתום באמצעות מפתח של חשבון שירות ב-Google Cloud. אם אתם משתמשים ב-Android SDK של Google Wallet, ה-SDK מטפל באופן אוטומטי בחתימת ה-JWT באמצעות טביעת האצבע מסוג SHA-1 של אישור חתימת האפליקציה.

כדי להגן על פרטי הכניסה שלך, עליך לחתום על אסימוני JWT רק בשרת שלך או להשתמש ב-Android SDK של Google Wallet באפליקציה שלך.

הצגת דוגמה לחתימת קוד

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. כדי לעשות זאת, מציגים למשתמש לחצן או קישור מסוג 'הוספה ל-Google Wallet'. כשמשתמש לוחץ על הלחצן או על ההיפר-קישור, ה-JWT החתום נשלח אל Google Wallet API, שמפענח אותו באמצעות פרטי הכניסה ששמרתם. לאחר אימות חתימת ה-JWT, הכרטיס יונפק למשתמש לצורך שמירה ב-Google Wallet.

איך עושים את זה

כדי ליצור לחצן 'הוספה ל-Google Wallet' לאפליקציה ל-Android, צריך להשתמש ב-Google Wallet ל-Android SDK שמספק שיטות ליצירת הלחצן. בכל שאר הפלטפורמות, כולל באינטרנט, באימייל ובהודעות טקסט, צריך ליצור היפר-קישור בפורמט 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 API או Android SDK. לאחר יצירת הכרטיסים, הם משמשים להנפקת כרטיסים באמצעות התעודה המזהה שלהם.

לחלופין, אפשר גם ליצור אובייקטים של Passes Classes ו-Passes 'בדיוק בזמן' על ידי הטמעת ה-JSON שלהם ישירות ב-JWT שמשמש להנפקת הכרטיס למשתמש. בשיטה הזו, האובייקטים של מחלקות וכרטיסים של כרטיסים נוצרים על ידי Google Wallet API כאשר ה-JWT החתום נשלח באמצעות לחצן 'הוספה ל-Google Wallet' או קישור.

לדוגמה, למטה מוצג JWT עם אובייקט 'סיווגי כרטיסים' ואובייקט Passes חדש שמוגדר באמצעות המאפיינים payload.eventTicketClasses ו-payload.eventTicketObjects. שימו לב שהמאפיינים האלה הם מערכים, ולכן הם יכולים לקבל אובייקט אחד או יותר מסוג Passes Classes או Passes Objectes. אפשר גם לציין ב-JWT רק אובייקט כרטיסים חדש שמפנה לסיווג כרטיסים קיים באמצעות המזהה שלו.

הצגת 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": ""
        }
      }]
    }
  }