在 Dialogflow 中探索
点击继续,将我们的通知示例导入 Dialogflow。然后,按照 部署和测试示例的步骤如下:
- 输入代理名称并为示例创建新的 Dialogflow 代理。
- 代理导入完成后,点击转到代理 (Go to agent)。
- 在主导航菜单中,前往 Fulfillment。
- 启用内嵌编辑器,然后点击部署。编辑器包含示例 代码。
- 在主导航菜单中,前往 Integrations(集成),然后点击 Google Google 助理。
- 在显示的模态窗口中,启用 Auto-preview changes(自动预览更改),然后点击 Test(测试) 打开 Actions 模拟器。
- 在模拟器中,输入
Talk to my test app
以测试该示例!
你的 Action 可以适时向用户推送通知,例如发送 在任务的截止日期临近时发送提醒。
在本指南中,我们将使用 Actions on Google 提示示例 作为参考,向您展示如何为 Action 设置推送通知。 当用户调用此 Action 时,它会询问他们是否要听到提示 如何开发自己的 Action。用户可以 为小费选择一个具体类别或随机选择类别,也可以 选择收听最新提示。
支持的表面
推送通知适用于 Android 和 iOS 设备(iOS 设备必须 已安装 Google 助理应用以接收推送通知)。它们不是 目前支持声控音箱、智能显示屏或其他平台。
前提条件
您的 Actions 项目中必须至少有一个操作配置为 触发 intent,当用户点按从 Google 助理。
您无法将 Action 配置为从推送通知触发默认欢迎 intent。
控制台设置
如需向 Action 添加对推送通知的支持,请执行以下操作:
前往 Actions 控制台并浏览 到构建 >操作。
点击与您要匹配的其他触发 intent 匹配的操作 启用推送通知。
对于 Actions on Google 提示示例,您需要选择“tell_latest_tip”。
向下滚动到用户互动部分,然后开启 你想发送推送通知吗。
输入内容标题。
对于 Actions on Google 提示示例,标题可能是“添加了新提示”。
点击保存。
导入
在后面的部分中,您需要在执行方式代码中 需要声明以下导入:
<ph type="x-smartling-placeholder">const {
dialogflow,
UpdatePermission,
Suggestions,
} = require('actions-on-google');
const {
actionssdk,
UpdatePermission,
Suggestions,
} = require('actions-on-google');
选择订阅的用户
您必须先请求用户选择接收,然后才能向用户发送推送通知。 为此,您可以向他们显示建议内容信息卡,请求他们授予权限。 他们授予权限后,您会收到要发送的更新用户 ID 向该用户发送推送通知
显示选择启用的建议内容信息卡
您必须向用户显示 邀请用户选择接收推送通知的建议内容信息卡。
以下代码段向用户发送“有新提示的提醒我”建议 条状标签。
<ph type="x-smartling-placeholder">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"
});
请注意,下面的 JSON 描述的是 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"
}
]
}
}
}
}
请注意,下面的 JSON 描述的是 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"
}
]
}
}
}
]
}
孩子点按条状标签后,你必须请求UPDATE
权限。
以下代码展示了如何使用 askForUpdatePermission
执行此操作。
函数。
- 在 Dialogflow 控制台中打开您的代理,然后选择要配置为进行更新的意图。
- 向下滚动到响应 (Response) 并打开 Google 助理标签页。
- 点击添加邮件内容,然后选择建议内容信息条。
- 将条状标签文本设置为邀请用户选择的内容。在 Actions on Google 提示示例,我们将条状标签设置为有新提示时提醒我。
- 添加另一个 Dialogflow intent,例如 setup_push,并 设置相应的操作,例如 setup.push。 此 intent 的用户表述必须与“选择启用”条状标签的文本匹配, 有新提示时请提醒我。
app.intent('Subscribe to Notifications', (conv) => {
conv.ask(new UpdatePermission({
intent: 'Notification',
}));
});
您应该将 NLU 解决方案配置为触发一个函数,要求 权限(如果用户表述与推送通知的值匹配) 选择启用提示。下面是一个基于字符串匹配的最基本示例:
conv.ask(new UpdatePermission({
intent: 'Notification',
}));
- 在 Dialogflow 控制台中打开您的代理,然后选择要配置为进行更新的意图。
- 向下滚动到响应 (Response) 并打开 Google 助理标签页。
- 点击添加邮件内容,然后选择建议内容信息条。
- 将条状标签文本设置为邀请用户选择的内容。在 Actions on Google 提示示例,我们将条状标签设置为有新提示时提醒我。
- 添加另一个 Dialogflow intent,例如 setup_push,并 设置相应的操作,例如 setup.push。 此 intent 的用户表述必须与“选择启用”条状标签的文本匹配, 有新提示时请提醒我。
@ForIntent("Subscribe to Notifications")
public ActionResponse subscribeToNotifications(ActionRequest request) {
ResponseBuilder responseBuilder = getResponseBuilder(request);
responseBuilder.add(new UpdatePermission().setIntent("Notification"));
return responseBuilder.build();
}
您应该将 NLU 解决方案配置为触发一个函数,要求 权限(如果用户表述与推送通知的值匹配) 选择启用提示。下面是一个基于字符串匹配的最基本示例:
ResponseBuilder responseBuilder = getResponseBuilder(request);
responseBuilder.add(new UpdatePermission().setIntent("Notification"));
return responseBuilder.build();
请注意,下面的 JSON 描述了使用 Dialogflow 的 webhook 响应。
{
"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"
}
}
}
}
}
}
请注意,以下 JSON 描述了使用 Actions SDK 的网络钩子响应。
{
"expectUserResponse": true,
"expectedInputs": [
{
"possibleIntents": [
{
"intent": "actions.intent.PERMISSION",
"inputValueData": {
"@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"permissions": [
"UPDATE"
],
"updatePermissionValueSpec": {
"intent": "tell_latest_tip"
}
}
}
]
}
]
}
完成订阅
要从 Node.js webhook 完成订阅,您需要保存 用户的通知 ID 以及他们选择的 intent。两者均作为 参数。
如果您的 Action 是使用 Dialogflow 构建的,您需要执行以下操作:
- 添加用于处理
actions_intent_PERMISSION
的 intent。 - 将 intent 的 Action 名称指定为网络钩子可以执行的名称 以供日后查看
以下代码显示了如何使用 intent 处理 Dialogflow intent
名称为 finish_push_setup
,操作名称为 finish.push.setup
:
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();
}
请注意,下面的 JSON 描述了对 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"
}
请注意,下面的 JSON 描述了对 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"
}
]
}
]
}
发送通知
您可以使用 Actions API 向用户发送推送通知。要使用此 API, 您需要在 Google Cloud 项目中激活该 API,然后设置和下载 JSON 服务账号密钥。请参阅此处代码示例说明中的第 8 步。
然后,您可以使用 Google OAuth2 客户端库交换服务账号密钥 获取访问令牌,然后使用该令牌对向 Actions API 发出的请求进行身份验证。
获取服务账号密钥
- 转到此网址(将“example-project-1”)并在末尾添加您的项目 ID 在 Actions 控制台中执行以下操作: https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
- 如果您看到启用按钮,请点击该按钮。否则,请继续执行第 3 步。
- 转到此网址(将“example-project-1”)并在末尾添加您的项目 ID 在 Actions 控制台中执行以下操作: https://console.developers.google.com/apis/credentials?project=example-project-1
- 点击创建凭据 >服务账号密钥。
- 点击服务账号下的选择框,然后点击新服务 账号。
- 为服务账号命名(例如“通知”)以及以下角色的 Role: Project Owner。
- 选择 JSON 密钥类型,然后点击创建。JSON 服务账号密钥是 下载到本地计算机
用密钥交换访问令牌并发送通知
要通过 Actions API 发送通知,您需要 访问令牌的服务账号密钥。我们建议使用 Google API 客户端 库。在随后的一系列代码段中,我们将使用 Google API Node.js 客户端库。
- 安装 Google API 客户端库并请求:
npm install googleapis request --save
- 使用以下代码从服务账号密钥获取访问令牌 并发送推送通知:
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);
}