Todas as indústrias do cartão têm casos de uso comuns. Por exemplo, todos os cartões de fidelidade, vales-presente, ofertas, ingressos de eventos, cartões de embarque para voos e cartões de transporte público podem ser adicionados ao app Google Pay de várias maneiras. Selecione um destes métodos para saber mais:
Em um app Android
Use os métodos a seguir para adicionar o botão Salvar no Google Pay ao seu app Android:
Usar o SDK do Android
A API Android permite salvar cartões no Google Pay. Ao integrar o botão Salvar no Google Pay ao app, fica mais fácil para os clientes salvarem o cartão no Google Pay.
Os passos a seguir descrevem como adicionar o botão Salvar no Google Pay no cartão de fidelidade, mas o processo usado é o mesmo em todos os cartões.
1. Criar uma classe
Primeiro, defina a LoyaltyClass
. O exemplo a seguir mostra um recurso JSON que
representa uma LoyaltyClass
:
{ "accountIdLabel": "Member Id", "accountNameLabel": "Member Name", "id": "2945482443380251551.ExampleClass1", "issuerName": "Baconrista", "kind": "walletobjects#loyaltyClass", "textModulesData": [ { "header": "Rewards details", "body": "Welcome to Baconrista rewards. Enjoy your rewards for being a loyal customer. " + "10 points for every dollar spent. Redeem your points for free coffee, bacon and more!" } ], "linksModuleData": { "uris": [ { "kind": "walletobjects#uri", "uri": "https://maps.google.com/map?q=google", "description": "Nearby Locations" }, { "kind": "walletobjects#uri", "uri": "tel:6505555555", "description": "Call Customer Service" } ] }, "imageModulesData": [ { "mainImage": { "kind": "walletobjects#image", "sourceUri": { "kind": "walletobjects#uri", "uri": "https://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", "description": "Coffee beans" } } } ], "messages": [{ "header": "Welcome to Banconrista Rewards!", "body": "Featuring our new bacon donuts.", "kind": "walletobjects#walletObjectMessage" }], "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001 },{ "kind": "walletobjects#latLongPoint", "latitude": 37.424354, "longitude": -122.09508869999999 },{ "kind": "walletobjects#latLongPoint", "latitude": 37.7901435, "longitude": -122.39026709999997 },{ "kind": "walletobjects#latLongPoint", "latitude": 40.7406578, "longitude": -74.00208940000002 }], "programLogo": { "kind": "walletobjects#image", "sourceUri": { "kind": "walletobjects#uri", "uri": "https://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg" } }, "programName": "Baconrista Rewards", "rewardsTier": "Gold", "rewardsTierLabel": "Tier", "reviewStatus": "underReview", "hexBackgroundColor": "#ffffff", "heroImage": { "kind": "walletobjects#image", "sourceUri": { "kind": "walletobjects#uri", "uri": "https://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg" } } }
2. Criar um objeto
Depois de criar a classe, defina o LoyaltyObject
, conforme mostrado no snippet
a seguir:
{ "classId": "2945482443380251551.ExampleClass1", "id": "2945482443380251551.ExampleObject1", "accountId": "1234567890", "accountName": "Jane Doe", "barcode": { "alternateText": "12345", "type": "qrCode", "value": "28343E3" }, "textModulesData": [{ "header": "Jane's Baconrista Rewards", "body": "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." }], "linksModuleData": { "uris": [ { "kind": "walletobjects#uri", "uri": "https://www.baconrista.com/myaccount?id=1234567890", "description": "My Baconrista Account" }] }, "infoModuleData": { "labelValueRows": [{ "columns": [{ "label": "Next Reward in", "value": "2 coffees" }, { "label": "Member Since", "value": "01/15/2013" }] }, { "columns": [{ "label": "Local Store", "value": "Mountain View" }] }], "showLastUpdateTime": "true" }, "loyaltyPoints": { "balance": { "string": "5000" }, "label": "Points", "pointsType": "points" }, "messages": [{ "header": "Jane, welcome to Banconrista Rewards!", "body": "Thanks for joining our program. Show this message to " + "our barista for your first free coffee on us!" }], "state": "active" }
3. Codificar um JWT não assinado
Depois de criar o objeto, codifique o LoyaltyClass
e o LoyaltyObject
em um JWT não assinado, como mostrado no snippet a seguir:
{ "iss": "example_service_account@developer.gserviceaccount.com", "aud": "google", "typ": "savetoandroidpay", "iat": 1368029586, "payload": { "eventTicketClasses": [{ ... //Event ticket Class JSON }], "eventTicketObjects": [{ ... //Event ticket Object JSON }], "flightClasses": [{ ... //Flight Class JSON }], "flightObjects": [{ ... //Flight Object JSON }], "giftCardClasses": [{ ... //Gift card Class JSON }], "giftCardObjects": [{ ... //Gift card Object JSON }], "loyaltyClasses": [{ ... //Loyalty Class JSON }], "loyaltyObjects": [{ ... //Loyalty Object JSON }], "offerClasses": [{ ... //Offer Class JSON }], "offerObjects": [{ ... //Offer Object JSON }], "transitClasses": [{ ... //Transit Class JSON }], "transitObjects": [{ ... //Transit Object JSON }] }, "origins": ["http://baconrista.com", "https://baconrista.com"] }
4. Escolher um formato de solicitação para usar
O SDK do Android permite fazer solicitações com um dos formatos a seguir:
- O método
savePasses
usa um payload de string JSON. - O método
savePassesJwt
usa um payload de token de string JWT.
Para ver mais detalhes sobre como fazer uma solicitação, consulte Chamar o SDK do Android.
savePasses
As solicitações para o método savePasses
têm um payload de string JSON. Isso significa que é possível
usar diretamente o JSON para o objeto criado na etapa 3.
É possível fazer solicitações para o "Salvar no Google Pay" para classes e objetos que já existem ou que são inseridos como parte do processo de salvamento. Também é possível salvar vários cartões na mesma solicitação se a indústria de cartões for compatível com essa funcionalidade. Não é possível inserir/atualizar classes e objetos que já existem.
Para melhorar a segurança, alguns campos são considerados confidenciais e, nesses casos, não é possível salvar cartões que já existem apenas ao especificar o campo de ID do objeto. Só é possível salvar objetos que já existem se os campos confidenciais na solicitação corresponderem aos campos dos objetos atuais. Os seguintes campos são considerados confidenciais:
object.barcode.value
object.smartTapRedemptionValue
savePassesJwt
As solicitações para o método savePassesJwt
têm um payload de token de string JWT. Para criar o
JWT, assine o objeto da etapa 3 com a chave privada
da conta de serviço do OAuth 2.0. Os snippets a seguir mostram como codificar um JWT em várias linguagens:
Java
WobCredentials credentials = null; WobUtils utils = null; // Instantiate the WobUtils class which contains handy functions // Wob utils can be found in the quickstart sample try { credentials = new WobCredentials( ServiceAccountEmailAddress, ServiceAccountPrivateKeyPath, ApplicationName, IssuerId); utils = new WobUtils(credentials); } catch (GeneralSecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // Add valid domains for the Save to Wallet button List<String> origins = new ArrayList<String>(); origins.add("http://baconrista.com"); origins.add("https://baconrista.com"); origins.add(req.getScheme() + "://" + req.getServerName() + ":" + req.getLocalPort()); //Generate Objects and Classes here //........ WobPayload payload = new WobPayload(); payload.addObject({WalletObject/WalletClass}); // Convert the object into a Save to Android Pay Jwt String jwt = null; try { jwt = utils.generateSaveJwt(payload, origins); } catch (SignatureException e) { e.printStackTrace(); }
PHP
$requestBody = [ "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS, "aud" => "google", "typ" => "savetoandroidpay", "iat"=> time(), "payload" => { "eventTicketClasses" => [ ], # Event ticket classes "eventTicketObjects" => [ ], # Event ticket objects "flightClasses" => [ ], # Flight classes "flightObjects" => [ ], # Flight objects "giftCardClasses" => [ ], # Gift card classes "giftCardObjects" => [ ], # Gift card objects "loyaltyClasses" => [ ], # Loyalty classes "loyaltyObjects" => [ ], # Loyalty objects "offerClasses" => [ ], # Offer classes "offerObjects" => [ ], # Offer objects "transitClasses" => [ ], # Transit classes "transitObjects" => [ ] # Transit objects }, "origins" => ["http://baconrista.com", "https://baconrista.com"] ] // Generate the Save to Android Pay Jwt echo $jwt = $assertObj->makeSignedJwt($requestBody, $client);
Python
jwt = { 'iss': config.SERVICE_ACCOUNT_EMAIL_ADDRESS, 'aud': 'google', 'typ': 'savetoandroidpay', 'iat': int(time.time()), 'payload': { 'webserviceResponse': { 'result': 'approved', 'message': 'Success.' }, 'eventTicketClasses': [], # Event ticket classes 'eventTicketObjects': [], # Event ticket objects 'flightClasses': [], # Flight classes 'flightObjects': [], # Flight objects 'giftCardClasses': [], # Gift card classes 'giftCardObjects': [], # Gift card objects 'loyaltyClasses': [], # Loyalty classes 'loyaltyObjects': [], # Loyalty objects 'offerClasses': [], # Offer classes 'offerObjects': [], # Offer objects 'transitClasses': [], # Transit classes 'transitObjects': [] # Transit objects }, 'origins' : ['http://baconrista.com', 'https://baconrista.com'] } // Generate the Save to Android Pay Jwt signer = crypt.Signer.from_string(app_key) signed_jwt = crypt.make_signed_jwt(signer, jwt) response = webapp2.Response(signed_jwt)
É possível fazer solicitações para o "Salvar no Google Pay" para classes e objetos que já existem ou que são inseridos como parte do processo de salvamento. Também é possível salvar vários cartões na mesma solicitação se a indústria de cartões for compatível com essa funcionalidade. Não é possível inserir/atualizar classes e objetos que já existem. Os JWTs dinâmicos podem ser usados, desde que as classes e objetos já existam.
5. Chamar o SDK do Android
Primeiro, use o método getPayApiAvailabilityStatus
para verificar se os
métodos savePasses
ou savePassesJwt
estão disponíveis, conforme mostrado no
exemplo a seguir:
import com.google.android.gms.common.api.UnsupportedApiCallException; import com.google.android.gms.pay.Pay; import com.google.android.gms.pay.PayApiAvailabilityStatus; import com.google.android.gms.pay.PayClient; … PayClient payClient = Pay.getClient(this); payClient // Use PayClient.RequestType.SAVE_PASSES_JWT for the savePassesJwt API .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES) .addOnSuccessListener( status -> { switch (status) { case PayApiAvailabilityStatus.AVAILABLE: // You can call the savePasses API or savePassesJwt API ... break; case PayApiAvailabilityStatus.NOT_ELIGIBLE: default: // We recommend to either: // 1) Hide the save button // 2) Fall back to a different Save Passes integration (e.g. JWT link) // Note however that the user *will* only be able to access their // passes on web // A not eligible user might become eligible in the future. ... break; } }) .addOnFailureListener( exception -> { if (exception instanceof UnsupportedApiCallException) { // Google Play Services too old. We could not check API availability or // user eligibility. We recommend to either: // 1) Fall back to a different Save Passes integration (e.g. JWT link) // Note however that the user *may* only be able to access their // passes on web // 2) Hide the save button ... } else { // Very old version of Google Play Services or unexpected error! ... } });
Se a API estiver disponível, chame o método savePasses
ou savePassesJwt
quando o usuário tocar no botão Salvar no Google Pay.
savePasses
private static final int SAVE_TO_GOOGLE_PAY = 1000; … String jsonString = … // Build or fetch JSON request PayClient payClient = Pay.getClient(this); payClient.savePasses(jsonString, this, SAVE_TO_GOOGLE_PAY);
savePassesJwt
private static final int SAVE_TO_GOOGLE_PAY = 1000; … String jwtString = … // Fetch JWT from a secure server PayClient payClient = Pay.getClient(this); payClient.savePassesJwt(jwtString, this, SAVE_TO_GOOGLE_PAY);
Essa chamada aciona o fluxo de salvamento. Depois que o fluxo termina, seu app resolve o resultado com
onActivityResult
. Na sua atividade, esse receptor precisa ser definido desta
forma:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // `data` will only have information in the `SAVE_ERROR` case if (requestCode == SAVE_TO_GOOGLE_PAY) { switch (resultCode) { case Activity.RESULT_OK: // Save successful ... break; case Activity.RESULT_CANCELED: // Save canceled ... break; case PayClient.SavePassesResult.API_ERROR: // API error - this should not happen if getPayApiAvailabilityStatus is // used correctly ... break; case PayClient.SavePassesResult.SAVE_ERROR: // Save error - check EXTRA_API_ERROR_MESSAGE to debug the issue // Most save errors indicate an error in the app fingerprint or the Json // request payload. In most cases prompting the user to try again will not // help. if (data != null && !isEmpty(data.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE))) { ... } else { // Unexpected! A save error should always have a debug message associated // with it ... } break; case PayClient.SavePassesResult.INTERNAL_ERROR: default: // Internal error - prompt the user to try again, if the error persists // disable the button ... break; } } else { ... } }
6. Adicionar o botão "Salvar no Google Pay" à IU
O Google Pay oferece um botão do SDK do Android para você fazer a integração ao app. Os recursos do botão estão disponíveis nas diretrizes da marca.
Este toolkit contém imagens vetoriais dos botões.
Para incorporar um botão ao aplicativo, copie a imagem do botão do toolkit para a
pasta res
do app e adicione o código a seguir ao arquivo de layout do
Android. Cada botão exige a string contentDescription
exclusiva e
o valor minWidth
, além do valor correto de src
.
<ImageButton android:layout_width="match_parent" android:layout_height="48dp" android:minWidth="200dp" android:clickable="true" android:src="@drawable/s2ap" />
A layout_height
do botão é de 48 dp, e a minWidth
precisa ser de
200 dp.
Usar o método de intent e link do JWT
Siga estes passos para salvar o cartão no Google Pay pelo app:
- Conclua as etapas em Adicionar o botão "Salvar no Google Pay" ao seu e-mail ou SMS.
Use uma intent
ACTION_VIEW
para abrir o link direto pelo botão Salvar no Google Pay.Verifique se o botão que aciona a intent usa as diretrizes da marca.
Veja a seguir um exemplo de resumo de fluxo:
- Em algum momento antes de salvar seu cartão, uma classe é criada no back-end com a API REST.
- Quando o usuário final pede para salvar um cartão, o back-end do servidor envia ao
app cliente para Android um
JWT
que representa um objeto. - O app cliente para Android inclui um botão Salvar no Google Pay que segue nossas
diretrizes da marca.
Quando você clicar nele, uma intent
ACTION_VIEW
será aberta para um URI que contém o JWT no caminho. Veja um exemplo:https://pay.google.com/gp/v/save/{jwt_generated}
Usar o método de solicitação JWT POST
O método de solicitação JWT POST
é uma alternativa usada na criação de classes e objetos de passagens aéreas ou ingressos de eventos em apps para Android. Ela é usada quando é muito difícil implementar o trabalho de back-end necessário para criar e inserir uma classe antes que um objeto seja salvo. Esse método é mais útil para ingressos de eventos e passagens aéreas, porque eles são cartões que podem ter várias classes criadas ao longo do tempo. Esse fluxo é resumido da seguinte forma:
- Quando o usuário final faz check-in no voo ou resgata o ingresso de um evento, o back-end do servidor renderiza um JWT para o app Android cliente que inclui a classe e o objeto.
- O app Android cliente inclui um botão Salvar no Google, que segue nossas diretrizes da marca. Veja o que acontece quando você clica nele:
- Uma solicitação
POST
envia o JWT para um endpoint do Google por HTTPS. - Um URI do corpo de resposta HTTP resultante é enviado de volta. Use-o
para abrir uma intent
ACTION_VIEW
.
O método de solicitação POST
do JWT também requer
uma chave de API. Ela é anexada como um
parâmetro de consulta à chamada da API REST.
Criação de classes
Uma nova classe será criada no nosso back-end somente quando for apresentada com um class.id
que não foi salvo anteriormente. Portanto, mesmo que você consiga transmitir os detalhes da classe para o Google pelo JWT várias vezes, o back-end reconhece que a classe já está salva e não cria classes novas toda vez que um cartão de embarque é salvo.
Atualizações de classes
Após o primeiro cartão de embarque, o objeto é salvo com a classe. É possível usar o class.id
com nossa API REST para executar as operações ADDMESSAGE
, GET
, LIST
, PATCH
e UPDATE
, conforme o esperado.
Para alterar os detalhes da classe, use a API Class Update. Se você criar uma classe com class.id
=XYZ e outros detalhes e depois tentar criar mais uma classe com class.id
=XYZ, mas com detalhes diferentes, a classe original será mantida e nenhuma alteração será aplicada.
Formato JWT
O formato do JWT que você envia está descrito com detalhes na nossa documentação de referência sobre
o JWT da Google Pay API for Passes.
Nesse payload
, é necessário transmitir uma entrada para objetos, que representa o objeto criado
por você, e uma entrada para classes, que contém a classe que você criou.
Solicitação HTTP
É possível usar o método INSERT
para inserir classes e objetos especificados em um JWT. A chave da API precisa ser definida como um parâmetro de consulta.
Método JWT INSERT
Ao receber um JWT, o método INSERT
insere as classes e objetos especificados no JWT. Caso esse processo seja bem-sucedido, você verá a mensagem de HTTP 200.
Solicitação HTTP
POST https://walletobjects.googleapis.com/walletobjects/v1/jwt/
Autorização
Esta solicitação não requer autorização. No entanto, o JWT precisa ser assinado com o método RSA-SHA256. A chave de assinatura é aquela gerada pela conta de serviço do OAuth.
Corpo da solicitação
No corpo da solicitação, forneça dados com esta estrutura:
{ “jwt” : string }
Corpo da resposta
Se o método for bem-sucedido um corpo de resposta com a seguinte estrutura será exibido:
{ "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, ... ] } }
Um saveUri
é um URI que, quando aberto, permite que o usuário final salve os objetos identificados no JWT na própria Conta do Google. Esse URI é válido apenas uma semana após o
retorno.
Consulte a documentação de referência do endpoint do JWT para ver mais detalhes.
Diagramas de fluxo
Veja os fluxos comuns da API para diagramas de fluxo.