Dialogflow에서 살펴보기
계속을 클릭하여 Dialogflow의 알림 샘플을 가져옵니다. 그런 다음 다음 단계에 따라 샘플을 배포하고 테스트합니다.
- 에이전트 이름을 입력하고 샘플의 새 Dialogflow 에이전트를 만듭니다.
- 에이전트 가져오기가 완료되면 Go to agent를 클릭합니다.
- 기본 탐색 메뉴에서 fulfillment로 이동합니다.
- 인라인 편집기를 사용 설정한 다음 배포를 클릭합니다. 편집기에 샘플 파일이 포함되어 있고 있습니다.
- 기본 탐색 메뉴에서 Integrations로 이동한 다음 Google을 클릭합니다. 어시스턴트를 탭합니다.
- 모달 창이 나타나면 변경사항 자동 미리보기를 사용 설정하고 테스트를 클릭합니다. 작업 시뮬레이터를 엽니다.
- 시뮬레이터에서
Talk to my test app
를 입력하여 샘플을 테스트합니다.
작업이 관련이 있을 때마다 사용자에게 알림을 푸시할 수 있습니다(예: 할 일의 마감일이 다가오면 알림이 표시됩니다.
이 가이드에서는 Actions on Google 도움말 샘플을 사용합니다. 을 참조하세요. 사용자가 이 작업을 호출할 때 도움말을 들을지 묻습니다. 자신만의 Action을 개발하는 것입니다. 사용자가 할 수 있는 작업 팁에 대해 특정 카테고리 또는 무작위로 선택된 카테고리를 선택하거나 최근 팁을 듣기로 선택합니다
지원되는 노출 영역
푸시 알림은 Android 및 iOS 기기에서 사용할 수 있습니다. iOS 기기의 경우 어시스턴트 앱을 설치해야 푸시 알림을 수신할 수 있음). 그렇지 않습니다. 현재 음성 인식 스피커, 스마트 디스플레이 또는 기타 표면에서 지원됩니다.
기본 요건
작업 프로젝트의 작업 중 하나 이상이 사용자가 알림을 탭할 때 호출될 인텐트를 트리거하는 인텐트 어시스턴트를 탭합니다.
푸시 알림에서 기본 시작 인텐트를 트리거하도록 작업을 구성할 수 없습니다.
콘솔 설정
작업에 푸시 알림 지원을 추가하려면 다음 단계를 따르세요.
Actions 콘솔로 이동하여 이동합니다. 빌드 > 작업.
추가 트리거 인텐트와 일치하는 작업을 클릭합니다. 푸시 알림을 사용 설정합니다
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은 웹훅 응답을 설명합니다.
{ "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은 웹훅 응답을 설명합니다.
{ "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 콘솔에서 에이전트를 열고 업데이트를 구성하려는 인텐트를 선택합니다.
- 응답까지 아래로 스크롤한 다음 Google 어시스턴트 탭을 엽니다.
- 메시지 콘텐츠 추가를 클릭하고 추천 쿼리 칩을 선택합니다.
- 사용자의 참여를 유도하는 것으로 칩 텍스트를 설정합니다. Alert me of new detail(새로운 도움말 알림 받기) 칩을 설정한 Actions on Google 도움말 샘플입니다.
- 예를 들어 setup_push라는 또 다른 Dialogflow 인텐트를 추가합니다. 해당하는 작업(예: setup.push)을 설정해야 합니다. 이 인텐트의 사용자 표현은 수신 동의 칩의 텍스트와 일치해야 합니다. 새로운 도움말 알림 예제를 참조하세요.
app.intent('Subscribe to Notifications', (conv) => { conv.ask(new UpdatePermission({ intent: 'Notification', })); });
다음 질문을 하는 함수를 트리거하도록 NLU 솔루션을 구성해야 합니다. 권한: 사용자 표현이 푸시 알림 값과 일치하는 경우 수신 동의 메시지가 표시됩니다. 다음은 문자열 일치에 기반한 기본적인 예입니다.
conv.ask(new UpdatePermission({ intent: 'Notification', }));
- Dialogflow 콘솔에서 에이전트를 열고 업데이트를 구성하려는 인텐트를 선택합니다.
- 응답까지 아래로 스크롤한 다음 Google 어시스턴트 탭을 엽니다.
- 메시지 콘텐츠 추가를 클릭하고 추천 쿼리 칩을 선택합니다.
- 사용자의 참여를 유도하는 것으로 칩 텍스트를 설정합니다. Alert me of new detail(새로운 도움말 알림 받기) 칩을 설정한 Actions on Google 도움말 샘플입니다.
- 예를 들어 setup_push라는 또 다른 Dialogflow 인텐트를 추가합니다. 해당하는 작업(예: setup.push)을 설정해야 합니다. 이 인텐트의 사용자 표현은 수신 동의 칩의 텍스트와 일치해야 합니다. 새로운 도움말 알림 예제를 참조하세요.
@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를 사용한 웹훅 응답을 설명합니다.
{ "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 웹훅에서 구독을 완료하려면 사용자의 알림 ID와 사용자가 선택한 인텐트입니다. 둘 다 인수를 만듭니다.
Dialogflow로 작업을 빌드하는 경우 다음을 수행해야 합니다.
actions_intent_PERMISSION
를 처리하는 인텐트를 추가합니다.- 인텐트의 작업 이름을 웹훅이 만들 수 있는 이름으로 지정합니다. 나중에 볼 수 있습니다.
다음 코드는 인텐트로 Dialogflow 인텐트를 처리하는 방법을 보여줍니다.
이름이 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은 웹훅에 대한 요청을 설명합니다.
{ "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은 웹훅에 대한 요청을 설명합니다.
{ "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'을 대체하여 이 URL로 이동합니다. 프로젝트 ID로 끝남 작업 콘솔에서 다음을 수행합니다. https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
- 사용 설정 버튼이 표시되면 클릭합니다. 그렇지 않은 경우 3단계로 진행합니다.
- 'example-project-1'을 대체하여 이 URL로 이동합니다. 프로젝트 ID로 끝남 작업 콘솔에서 다음을 수행합니다. https://console.developers.google.com/apis/credentials?project=example-project-1
- 사용자 인증 정보 만들기 > 서비스 계정 키를 입력합니다.
- 서비스 계정에서 선택 상자를 클릭하고 새 서비스를 클릭합니다. 계정.
- 서비스 계정에 '알림'과 같은 이름을 지정합니다. 및 역할 프로젝트 소유자
- 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); }