Background
The secure private images feature lets you define images on passes that don't need to be accessible from a publicly facing URL (a requirement for regular images to properly render them on passes). You use the Wallet API to upload an image and receive an identifier that can be used to reference that image on a Wallet pass object.
The following pass types are supported;
- Event Ticket
- Boarding pass
- Transit pass
- Offer Card
- Gift Card
- Loyalty pass
- Generic pass
Feature example
|
| Membership card using secure private image |
Use Cases
Secure private images enable the use of images that don't need to be publicly accessible and therefore could be used for things like a profile photo. This enables use cases such as, but not limited to, the following;
- Annual membership pass
- Business Card
- Transit Pass
Note: Secure private images are not intended to be used for representing passes as government issued identification along with additional guidelines defined in the acceptable use policy
Some considerations when using Wallet Feature
- Cannot be used with Generic Private Passes
- Can only be added to pass Objects (not Classes)
- Can only be used with a single Object
- Can only be used with ImageModuleData (not other images, e.g. logo and wide header logo)
Features In Development
- Web Support
- Private images on hero images
Integration Steps
- Upload your private image using the Google Wallet API to receive a
privateImageId. - Add an image to the pass object (for example,
ImageModuleData). Instead of setting thesourceUrifield on the image, you will set theprivateImageIdfield with the value obtained from the previous step.
Sequence Diagram
|
| Secure private image sequence |
Example Code
Upload the image
String issuerId = "12345"; String keyFilePath = "/path/to/key.json"; GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(keyFilePath)) .createScoped(Arrays.asList("https://www.googleapis.com/auth/wallet_object.issuer")); HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); // Prepare request to upload image String contentType = "image/jpeg"; // MIME type of image String imageFilePath = "/path/to/image.jpg"; HttpContent content = new ByteArrayContent( contentType, ByteStreams.toByteArray(new FileInputStream(imageFilePath))); String url = String.format( "https://walletobjects.googleapis.com/upload/walletobjects/v1/privateContent/%s/uploadPrivateImage", issuerId); // Make request to upload image HttpResponse response = httpTransport .createRequestFactory(credential) .buildPostRequest(new GenericUrl(url), content) .execute(); // Get privateImageId from response Gson gson = new Gson(); JsonObject jsonObject = gson.fromJson(response.parseAsString(), JsonObject.class); String privateImageId = jsonObject.get("privateImageId").getAsString();
Use the Private Image on the pass object
// Build GenericObject with privateImageId in ImageModuleData (also adding an optional TextModuleData) Image image = new Image().setPrivateImageId(privateImageId); ImageModuleData imageModuleData = new ImageModuleData().setId("imageId").setMainImage(image); TextModuleData textModuleData = new TextModuleData().setId("textId").setHeader("Card holder").setBody("John Doe"); GenericObject genericObject = new GenericObject() .setId(issuerId + ".objectId") // class must be inserted before inserting object .setClassId(issuerId + ".classId") .setCardTitle("Business name") .setHeader("My membership card") .setImageModulesData(Arrays.asList(imageModuleData)) .setTextModulesData(Arrays.asList(textModuleData)); // Insert GenericObject (or can use in JWT without inserting ahead of time) Walletobjects service = new Walletobjects.Builder(httpTransport, GsonFactory.getDefaultInstance(), credential) .setApplicationName("My Application") .build(); service.genericobject().insert(genericObject).execute();
Update the Pass to show the image on the front
You can use the secure private image on any imageModulesDatafield. The following is an example of how to use an imageModulesData field to position the image on the front of the card using a template override. Here's an example of inserting a class with a template override:
CardTemplateOverride cardTemplateOverride =
new CardTemplateOverride()
.setCardRowTemplateInfos(
Arrays.asList(
new CardRowTemplateInfo()
.setTwoItems(
new CardRowTwoItems()
// The ids chosen here must be set on the object's TextModuleData and ImageModuleData
.setStartItem(
createTemplateItem("object.textModulesData['textId']"))
.setEndItem(
createTemplateItem("object.imageModulesData['imageId']")))));
GenericClass genericClass =
new GenericClass()
.setId(issuerId + ".classId")
.setClassTemplateInfo(
new ClassTemplateInfo().setCardTemplateOverride(cardTemplateOverride));
service.genericclass().insert(genericClass);
...
private static TemplateItem createTemplateItem(String fieldPath) {
return new TemplateItem()
.setFirstValue(
new FieldSelector()
.setFields(Arrays.asList(new FieldReference().setFieldPath(fieldPath))));
}Exception handling
Potential errors may happen with incorrect use of the Wallet FeatureAPI which can include;
| Message | Reason |
|---|---|
| Image cannot have both source_uri and private_image_id | Issuer tried to set a source_uri and private_image_id on a single image, which is not allowed |
| Couldn't find private image with id %s for issuer %s | Setting a non-existent private image id on an object |
| Couldn't add private image with id %s for issuer %s to object %s because it is already used with object %s. A private image can only be used with one object. | Trying to use the same private image on more than one object. To use the same private image with more than one object, it must be re-uploaded and you'll get a new private image id, which can be used with the second object |