תהליך פיתוח כרטיס ל-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"
      }
    }
  }
}
    

בשביל מה צריך אותו

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

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

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

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

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

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

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

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

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

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

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

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

לדוגמה, בדוגמה הבאה מוצג JWT עם אובייקט מסוג Passes Class ו-Passes Classs חדש שמוגדר באמצעות המאפיינים payload.eventTicketClasses ו-payload.eventTicketObjects. שימו לב שהמאפיינים האלה הם מערכים, כך שהם יכולים לקבל אובייקט מסוג Passes או Passes אחד או יותר. אפשר גם לציין רק אובייקט כרטיסים חדש ב-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": ""
        }
      }]
    }
  }