Explorar no Dialogflow
Clique em Continue (Continuar) para importar nosso exemplo do Notifications no Dialogflow. Depois, siga as etapas abaixo para implantar e testar o exemplo:
- Insira um nome de agente e crie um novo agente do Dialogflow para a amostra.
- Depois que a importação do agente for concluída, clique em Go to agent.
- No menu de navegação principal, acesse Fulfillment.
- Ative o Inline Editor e clique em Implantar. O editor contém o código de amostra.
- No menu de navegação principal, acesse Integrações e clique em Google Assistente.
- Na janela modal exibida, ative a opção Auto-preview changes e clique em Test para abrir o simulador do Actions.
- No simulador, insira
Talk to my test app
para testar a amostra.
Sua Ação pode enviar notificações push aos usuários sempre que for relevante, por exemplo, enviar um lembrete quando a data de conclusão de uma tarefa estiver próxima.
Neste guia, usamos o exemplo de dicas do Actions on Google como referência para mostrar como configurar notificações push para sua ação. Quando o usuário invoca essa ação, ela pergunta se ele quer ouvir uma dica sobre como desenvolver a própria ação. Os usuários podem escolher uma categoria específica ou selecionada aleatoriamente para a gorjeta ou ouvir a dica mais recente.
Plataformas com suporte
As notificações push estão disponíveis em dispositivos Android e iOS. Para receber essas notificações, os dispositivos iOS precisam ter o app Google Assistente instalado. No momento, eles não são compatíveis com alto-falantes ativados por voz, smart displays ou outras plataformas.
Pré-requisitos
Pelo menos uma das ações no projeto precisa ser configurada como uma intent de acionamento que será invocada quando o usuário tocar em uma notificação recebida do Google Assistente.
Não é possível configurar suas ações para acionar a intent de boas-vindas padrão em uma notificação push.
Configuração do console
Para adicionar suporte a notificações push à sua ação:
Acesse o Console do Actions e navegue até Build > Actions.
Clique na ação que corresponde à intent de acionamento extra para a qual você quer ativar as notificações push.
Para o exemplo de dicas do Actions on Google, selecione "tell_latest_tip".
Role para baixo até a seção Engajamento do usuário e ative a opção Quer enviar notificações push.
Insira um Título do conteúdo.
Para o exemplo de dicas do Actions on Google, o título pode ser "Nova dica adicionada".
Clique em Salvar.
Importações
Para os fins das próximas seções, você precisará declarar as seguintes importações no código de fulfillment:
const { dialogflow, UpdatePermission, Suggestions, } = require('actions-on-google');
const { actionssdk, UpdatePermission, Suggestions, } = require('actions-on-google');
Usuários com permissão
Antes de enviar notificações push aos usuários, é necessário solicitar a ativação. Para isso, mostre um ícone de sugestão para que a pessoa peça a permissão. Quando ele concede a permissão, você recebe um ID de atualização do usuário para enviar notificações push a ele.
Mostrar ícones de sugestão para ativação
Antes que os usuários possam receber notificações push da sua ação, é necessário mostrar um ícone de sugestão para convidá-los a ativar as notificações push.
O snippet de código a seguir envia ao usuário um ícone de sugestão "Alerte-me sobre novas dicas" junto com uma resposta de texto.
conv.ask('I can send you push notifications. Would you like that?'); conv.ask(new Suggestions('Send notifications'));
conv.ask(' I can send you push notifications. Would you like that?'); conv.ask(new Suggestions('Send notifications'));
responseBuilder .add("I can send you push notifications. Would you like that?") .addSuggestions(new String[] { "Send notifications" });
responseBuilder .add("I can send you push notifications. Would you like that?") .addSuggestions(new String[] { "Send notifications" });
Observe que o JSON abaixo descreve uma resposta do webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Hi! Welcome to Push Notifications!" } }, { "simpleResponse": { "textToSpeech": "I can send you push notifications. Would you like that?" } } ], "suggestions": [ { "title": "Send notifications" } ] } } } }
Observe que o JSON abaixo descreve uma resposta do webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Hi! Welcome to Push Notifications!" } }, { "simpleResponse": { "textToSpeech": " I can send you push notifications. Would you like that?" } } ], "suggestions": [ { "title": "Send notifications" } ] } } } ] }
Depois de tocar no ícone, você precisa pedir a permissão de UPDATE
.
O código a seguir mostra como fazer isso com a função askForUpdatePermission
da biblioteca de cliente Node.js.
- Abra seu agente no console do Dialogflow e selecione a intent que você está configurando para atualizações.
- Role para baixo até Resposta e abra a guia Google Assistente.
- Clique em Adicionar conteúdo da mensagem e selecione Ícones de sugestão.
- Defina o texto do ícone como algo que convide o usuário a aceitar. No exemplo de dicas do Actions on Google, o ícone é definido como Alertar sobre novas dicas.
- Adicione outra intent do Dialogflow chamada setup_push, por exemplo, e defina uma ação correspondente, como setup.push. A expressão do usuário dessa intent precisa corresponder ao texto do ícone de ativação. No exemplo, Alerte-me sobre novas dicas.
app.intent('Subscribe to Notifications', (conv) => { conv.ask(new UpdatePermission({ intent: 'Notification', })); });
Configure sua solução de PLN para acionar uma função que solicite a permissão se a expressão do usuário corresponder ao valor da solicitação de permissão das notificações push. Veja um exemplo bem básico baseado na correspondência de string:
conv.ask(new UpdatePermission({ intent: 'Notification', }));
- Abra seu agente no console do Dialogflow e selecione a intent que você está configurando para atualizações.
- Role para baixo até Resposta e abra a guia Google Assistente.
- Clique em Adicionar conteúdo da mensagem e selecione Ícones de sugestão.
- Defina o texto do ícone como algo que convide o usuário a aceitar. No exemplo de dicas do Actions on Google, o ícone é definido como Alertar sobre novas dicas.
- Adicione outra intent do Dialogflow chamada setup_push, por exemplo, e defina uma ação correspondente, como setup.push. A expressão do usuário dessa intent precisa corresponder ao texto do ícone de ativação. No exemplo, Alerte-me sobre novas dicas.
@ForIntent("Subscribe to Notifications") public ActionResponse subscribeToNotifications(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.add(new UpdatePermission().setIntent("Notification")); return responseBuilder.build(); }
Configure sua solução de PLN para acionar uma função que solicite a permissão se a expressão do usuário corresponder ao valor da solicitação de permissão das notificações push. Veja um exemplo bem básico baseado na correspondência de string:
ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.add(new UpdatePermission().setIntent("Notification")); return responseBuilder.build();
Observe que o JSON abaixo descreve uma resposta do webhook usando o Dialogflow.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.PERMISSION", "data": { "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec", "permissions": [ "UPDATE" ], "updatePermissionValueSpec": { "intent": "tell_latest_tip" } } } } } }
O JSON abaixo descreve uma resposta do webhook usando o SDK do Actions.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.PERMISSION", "inputValueData": { "@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec", "permissions": [ "UPDATE" ], "updatePermissionValueSpec": { "intent": "tell_latest_tip" } } } ] } ] }
Finalizar a assinatura
Para finalizar a assinatura do webhook do Node.js, você precisa salvar o ID de notificações do usuário e a intent que ele selecionou. Ambos serão passados como argumentos se o usuário conceder a permissão.
Se a ação foi criada com o Dialogflow, você precisa:
- Adicione uma intent que processe o
actions_intent_PERMISSION
. - Especifique o nome de Action da intent para algo que seu webhook possa filtrar mais tarde.
O código a seguir mostra como processar uma intent do Dialogflow com uma intent chamada finish_push_setup
com o nome finish.push.setup
da ação:
app.intent('Confirm Notifications Subscription', (conv) => { if (conv.arguments.get('PERMISSION')) { const updatesUserId = conv.arguments.get('UPDATES_USER_ID'); // Store user ID in database for later use conv.close(`Ok, I'll start alerting you.`); } else { conv.close(`Ok, I won't alert you.`); } });
app.intent('actions.intent.PERMISSION', (conv) => { if (conv.arguments.get('PERMISSION')) { const updatesUserId = conv.arguments.get('UPDATES_USER_ID'); // Store user ID in database for later use conv.close(`Ok, I'll start alerting you.`); } else { conv.close(`Ok, I won't alert you.`); } });
@ForIntent("Confirm Notifications Subscription") public ActionResponse confirmNotificationsSubscription(ActionRequest request) { // Verify the user has subscribed for push notifications ResponseBuilder responseBuilder = getResponseBuilder(request); if (request.isPermissionGranted()) { Argument userId = request.getArgument(ConstantsKt.ARG_UPDATES_USER_ID); if (userId != null) { // Store the user's ID in the database } responseBuilder.add("Ok, I'll start alerting you."); } else { responseBuilder.add("Ok, I won't alert you."); } responseBuilder.endConversation(); return responseBuilder.build(); }
@ForIntent("actions.intent.PERMISSION") public ActionResponse confirmNotificationsSubscription(ActionRequest request) { // Verify the user has subscribed for push notifications ResponseBuilder responseBuilder = getResponseBuilder(request); if (request.isPermissionGranted()) { Argument userId = request.getArgument(ConstantsKt.ARG_UPDATES_USER_ID); if (userId != null) { // Store the user's ID in the database } responseBuilder.add("Ok, I'll start alerting you."); } else { responseBuilder.add("Ok, I won't alert you."); } responseBuilder.endConversation(); return responseBuilder.build(); }
Observe que o JSON abaixo descreve uma solicitação para o webhook.
{ "responseId": "ee9e7ed5-fa1a-48c6-aac7-f9fbe94f1f58-712767ed", "queryResult": { "queryText": "actions_intent_PERMISSION", "action": "confirm.subscription", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentMessages": [ { "text": { "text": [ "" ] } } ], "outputContexts": [ { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_screen_output" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_account_linking" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_media_response_audio" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_audio_output" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_capability_web_browser" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/google_assistant_input_type_keyboard" }, { "name": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k/contexts/actions_intent_permission", "parameters": { "PERMISSION": true, "text": "yes", "UPDATES_USER_ID": "ABwppHHssyPbvEBF1mgN7Ddwb7mkhiVohW9PZ--I_svqy7zFElA4DHkf9pn04UBd5gwZo26_RfXCQ8otcztyIfe6MCQ" } } ], "intent": { "name": "projects/PROJECT_ID/agent/intents/c7f7b30b-5b88-4bb5-b0b8-1cd0862d1dd2", "displayName": "Confirm Notifications Subscription" }, "intentDetectionConfidence": 1, "languageCode": "en" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "user": { "permissions": [ "UPDATE" ], "locale": "en-US", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k", "type": "ACTIVE", "conversationToken": "[]" }, "inputs": [ { "intent": "actions.intent.PERMISSION", "rawInputs": [ { "inputType": "KEYBOARD", "query": "yes" } ], "arguments": [ { "name": "PERMISSION", "boolValue": true, "textValue": "true" }, { "name": "text", "rawText": "yes", "textValue": "yes" }, { "name": "UPDATES_USER_ID", "textValue": "ABwppHHssyPbvEBF1mgN7Ddwb7mkhiVohW9PZ--I_svqy7zFElA4DHkf9pn04UBd5gwZo26_RfXCQ8otcztyIfe6MCQ" } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "projects/PROJECT_ID/agent/sessions/ABwppHGIgmmU3zBcYMF_vWoHaM4JUo3wniYBHdbUF25l63G7EQWjRnlne8Ar7AOcRHWn1lrEKGy8qdP0UXLcWDBq93k" }
Observe que o JSON abaixo descreve uma solicitação para o webhook.
{ "user": { "permissions": [ "UPDATE" ], "locale": "en-US", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHEP6OAFZHkSGEiZ5HYM9qrlk8YtIH1DQmJ52cxXELSPvM-kSc_tMJ_5O6ITbgVJlY9i2FIsKWjE_HXLke48", "type": "NEW" }, "inputs": [ { "intent": "actions.intent.PERMISSION", "rawInputs": [ { "inputType": "KEYBOARD", "query": "yes" } ], "arguments": [ { "name": "PERMISSION", "boolValue": true, "textValue": "true" }, { "name": "text", "rawText": "yes", "textValue": "yes" }, { "name": "UPDATES_USER_ID", "textValue": "ABwppHFvBKC-tMYUsUjJkm3YECgZvd6A3sOc7KuQvO4ZdQX3bGLmyoQ41dh4Zmtlzv_kaOKBt1Sf6eRpNbayynrl" } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" } ] }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] }
Envie notificações
Você pode enviar notificações push aos usuários usando a API Actions. Para usar essa API, você precisa ativá-la no projeto do Google Cloud e configurar e fazer o download de uma chave de conta de serviço JSON. Consulte a etapa 8 nas instruções no exemplo de código aqui.
Depois, use a biblioteca de cliente OAuth2 do Google para trocar a chave da conta de serviço por um token de acesso e usá-lo para autenticar as solicitações para a API Actions.
Gerar uma chave da conta de serviço
- Acesse esse URL, substituindo "example-project-1" no final pelo ID do projeto no Console do Actions: https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
- Se houver um botão Ativar, clique nele. Caso contrário, prossiga para a etapa 3.
- Acesse esse URL, substituindo "example-project-1" no final pelo ID do projeto no Console do Actions: https://console.developers.google.com/apis/credentials?project=example-project-1
- Clique em Criar credenciais > Chave da conta de serviço.
- Clique na caixa Selecionar em Conta de serviço e clique em Nova conta de serviço.
- Dê um nome à conta de serviço, como "notificações" e o Papel de Proprietário do projeto.
- Selecione o tipo de chave JSON e clique em Criar. Uma chave de conta de serviço JSON é transferida por download para sua máquina local.
Trocar a chave por um token de acesso e enviar uma notificação
Para enviar uma notificação pela API Actions, você precisa trocar a chave da conta de serviço por um token de acesso. Para isso, recomendamos o uso de uma biblioteca de cliente das APIs do Google. Na série de snippets de código a seguir, estamos usando a biblioteca de cliente Node.js da API do Google.
- Instale a biblioteca de cliente da API do Google e solicite:
npm install googleapis request --save
- Use o código a seguir para receber um token de acesso da chave da conta de serviço e enviar uma notificação push:
const {google} = require('googleapis'); const request = require('request'); const jwtClient = new google.auth.JWT( serviceAccount.client_email, null, serviceAccount.private_key, ['https://www.googleapis.com/auth/actions.fulfillment.conversation'], null ); jwtClient.authorize((err, tokens) => { if (!err) { request.post('https://actions.googleapis.com/v2/conversations:send', { auth: { bearer: tokens.access_token, }, json: true, body: { customPushMessage: { userNotification: { title: 'Push Notification Title', }, target: { userId: '<UPDATES_USER_ID>', intent: 'Notification Intent', }, }, isInSandbox: true, }, }, (err, httpResponse, body) => { console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`); }); } });
const {google} = require('googleapis'); const request = require('request'); const jwtClient = new google.auth.JWT( serviceAccount.client_email, null, serviceAccount.private_key, ['https://www.googleapis.com/auth/actions.fulfillment.conversation'], null ); jwtClient.authorize((err, tokens) => { if (!err) { request.post('https://actions.googleapis.com/v2/conversations:send', { auth: { bearer: tokens.access_token, }, json: true, body: { customPushMessage: { userNotification: { title: 'Push Notification Title', }, target: { userId: '<UPDATES_ORDER_ID>', intent: 'Notification Intent', }, }, isInSandbox: true, }, }, (err, httpResponse, body) => { console.log(`${httpResponse.statusCode}: ${httpResponse.statusMessage}`); }); } });
final class Notification { private final String title; Notification(String title) { this.title = title; } String getTitle() { return title; } } final class Target { private final String userId; private final String intent; private final String locale; Target(String userId, String intent, String locale) { this.userId = userId; this.intent = intent; this.locale = locale; } String getUserId() { return userId; } String getIntent() { return intent; } String getLocale() { return locale; } } final class PushMessage { private final Notification userNotification; private final Target target; PushMessage(Notification userNotification, Target target) { this.userNotification = userNotification; this.target = target; } Notification getUserNotification() { return userNotification; } Target getTarget() { return target; } } final class PushNotification { private final PushMessage customPushMessage; private boolean isInSandbox; PushNotification(PushMessage customPushMessage, boolean isInSandbox) { this.customPushMessage = customPushMessage; this.isInSandbox = isInSandbox; } PushMessage getCustomPushMessage() { return customPushMessage; } boolean getIsInSandbox() { return isInSandbox; } } private PushNotification createNotification(String title, String userId, String intent, String locale) { Notification notification = new Notification(title); Target target = new Target(userId, intent, locale); PushMessage message = new PushMessage(notification, target); boolean isInSandbox = true; return new PushNotification(message, isInSandbox); } private ServiceAccountCredentials loadCredentials() throws IOException { String actionsApiServiceAccountFile = this.getClass().getClassLoader().getResource("service-account.json").getFile(); InputStream actionsApiServiceAccount = new FileInputStream(actionsApiServiceAccountFile); ServiceAccountCredentials serviceAccountCredentials = ServiceAccountCredentials.fromStream(actionsApiServiceAccount); return (ServiceAccountCredentials) serviceAccountCredentials.createScoped( Collections.singleton( "https://www.googleapis.com/auth/actions.fulfillment.conversation")); } private String getAccessToken() throws IOException { AccessToken token = loadCredentials().refreshAccessToken(); return token.getTokenValue(); } public void sendNotification(String title, String userId, String intent, String locale) throws IOException { Preconditions.checkNotNull(title, "title cannot be null."); Preconditions.checkNotNull(userId, "userId cannot be null."); Preconditions.checkNotNull(intent, "intent cannot be null."); Preconditions.checkNotNull(locale, "locale cannot be null"); PushNotification notification = createNotification(title, userId, intent, locale); HttpPost request = new HttpPost("https://actions.googleapis.com/v2/conversations:send"); String token = getAccessToken(); request.setHeader("Content-type", "application/json"); request.setHeader("Authorization", "Bearer " + token); StringEntity entity = new StringEntity(new Gson().toJson(notification)); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); request.setEntity(entity); HttpClient httpClient = HttpClientBuilder.create().build(); httpClient.execute(request); }
final class Notification { private final String title; Notification(String title) { this.title = title; } String getTitle() { return title; } } final class Target { private final String userId; private final String intent; Target(String userId, String intent) { this.userId = userId; this.intent = intent; } String getUserId() { return userId; } String getIntent() { return intent; } } final class PushMessage { private final Notification userNotification; private final Target target; PushMessage(Notification userNotification, Target target) { this.userNotification = userNotification; this.target = target; } Notification getUserNotification() { return userNotification; } Target getTarget() { return target; } } final class PushNotification { private final PushMessage customPushMessage; private boolean isInSandbox; PushNotification(PushMessage customPushMessage, boolean isInSandbox) { this.customPushMessage = customPushMessage; this.isInSandbox = isInSandbox; } PushMessage getCustomPushMessage() { return customPushMessage; } boolean getIsInSandbox() { return isInSandbox; } } private PushNotification createNotification(String title, String userId, String intent) { Notification notification = new Notification(title); Target target = new Target(userId, intent); PushMessage message = new PushMessage(notification, target); boolean isInSandbox = true; return new PushNotification(message, isInSandbox); } private ServiceAccountCredentials loadCredentials() throws IOException { String actionsApiServiceAccountFile = this.getClass().getClassLoader().getResource("service-account.json").getFile(); InputStream actionsApiServiceAccount = new FileInputStream(actionsApiServiceAccountFile); ServiceAccountCredentials serviceAccountCredentials = ServiceAccountCredentials.fromStream(actionsApiServiceAccount); return (ServiceAccountCredentials) serviceAccountCredentials.createScoped( Collections.singleton( "https://www.googleapis.com/auth/actions.fulfillment.conversation")); } private String getAccessToken() throws IOException { AccessToken token = loadCredentials().refreshAccessToken(); return token.getTokenValue(); } public void sendNotification(String title, String userId, String intent) throws IOException { Preconditions.checkNotNull(title, "title cannot be null."); Preconditions.checkNotNull(userId, "userId cannot be null."); Preconditions.checkNotNull(intent, "intent cannot be null."); PushNotification notification = createNotification(title, userId, intent); HttpPost request = new HttpPost("https://actions.googleapis.com/v2/conversations:send"); String token = getAccessToken(); request.setHeader("Content-type", "application/json"); request.setHeader("Authorization", "Bearer " + token); StringEntity entity = new StringEntity(new Gson().toJson(notification)); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); request.setEntity(entity); HttpClient httpClient = HttpClientBuilder.create().build(); httpClient.execute(request); }