Notifikasi push (Dialogflow)

Jelajahi di Dialogflow

Klik Continue untuk mengimpor contoh Notifications di Dialogflow. Kemudian, ikuti langkah-langkah di bawah ini untuk men-deploy dan menguji contoh:

  1. Masukkan nama agen dan buat agen Dialogflow baru untuk contoh.
  2. Setelah agen selesai diimpor, klik Go to agent.
  3. Dari menu navigasi utama, buka Fulfillment.
  4. Aktifkan Inline Editor, lalu klik Deploy. Editor berisi contoh tersebut pada kode sumber.
  5. Dari menu navigasi utama, buka Integrations, lalu klik Google Asisten.
  6. Di jendela modal yang muncul, aktifkan Pratinjau perubahan secara otomatis, lalu klik Uji untuk membuka simulator Actions.
  7. Dalam simulator, masukkan Talk to my test app untuk menguji sampel.
Lanjutkan

Action Anda dapat mengirimkan notifikasi kepada pengguna jika relevan, seperti mengirim pengingat ketika tenggat waktu untuk sebuah tugas sudah dekat.

Dalam panduan ini, kami menggunakan contoh tips Actions on Google sebagai referensi untuk menunjukkan cara menyiapkan notifikasi push untuk Action Anda. Saat pengguna memanggil Action ini, aplikasi akan menanyakan apakah mereka ingin mendengar tips atau tidak mengembangkan Action mereka sendiri. Pengguna dapat memilih kategori yang spesifik atau dipilih secara acak untuk tips, atau mereka dapat memilih untuk mendengar kiat terbaru.

Platform yang didukung

Notifikasi push tersedia di perangkat Android dan iOS (perangkat iOS harus menginstal aplikasi Asisten untuk menerima notifikasi push). Tidak saat ini didukung di speaker, layar smart, atau platform lainnya yang diaktifkan dengan suara.

Prasyarat

Setidaknya satu Action dalam project Action Anda harus dikonfigurasi sebagai intent pemicu yang akan dipanggil saat pengguna mengetuk notifikasi yang diterima dari Asisten.

Action Anda tidak dapat dikonfigurasi untuk memicu Intent Selamat Datang Default dari notifikasi push.

Penyiapan konsol

Guna menambahkan dukungan untuk notifikasi push ke Action Anda:

  1. Buka Konsol Actions dan buka ke Build > Tindakan.

  2. Klik Tindakan yang cocok dengan intent pemicu tambahan yang ingin Anda mengaktifkan notifikasi push.

    Untuk contoh tips Actions on Google, pilih "tell_latest_tip".

  3. Scroll ke bawah ke bagian Engagement pengguna, lalu aktifkan Apakah Anda ingin mengirim notifikasi push.

  4. Masukkan Judul konten.

    Untuk contoh tips Actions on Google, judulnya dapat berupa "Tips baru ditambahkan".

  5. Klik Simpan.

Impor

Untuk tujuan bagian berikutnya, dalam kode penyelesaian, Anda akan harus mendeklarasikan impor berikut:

Dialogflow
const {
  dialogflow,
  UpdatePermission,
  Suggestions,
} = require('actions-on-google');
SDK Actions
const {
  actionssdk,
  UpdatePermission,
  Suggestions,
} = require('actions-on-google');

Mengikutsertakan pengguna

Sebelum dapat mengirimkan notifikasi push kepada pengguna, Anda harus meminta mereka untuk ikut serta. Anda dapat melakukannya dengan menampilkan chip saran untuk meminta izin mereka. Saat mereka memberikan izin, Anda akan menerima ID pengguna update untuk dikirim notifikasi push kepada pengguna tersebut.

Tampilkan chip saran untuk keikutsertaan

Sebelum pengguna dapat menerima notifikasi push dari Action, Anda harus menampilkan chip saran untuk mengundang mereka agar memilih notifikasi push.

Cuplikan kode berikut mengirim 'Beri tahu saya tentang tips baru' kepada pengguna saran chip di samping respons teks.

Node.js Dialogflow
conv.ask('I can send you push notifications. Would you like that?');
conv.ask(new Suggestions('Send notifications'));
Node.js Actions SDK
conv.ask(' I can send you push notifications. Would you like that?');
conv.ask(new Suggestions('Send notifications'));
Java Dialogflow
responseBuilder
    .add("I can send you push notifications. Would you like that?")
    .addSuggestions(new String[] {
        "Send notifications"
    });
Java Actions SDK
responseBuilder
    .add("I can send you push notifications. Would you like that?")
    .addSuggestions(new String[] {
        "Send notifications"
    });
JSON Dialogflow

Perlu diperhatikan bahwa JSON di bawah mendeskripsikan respons 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 Actions SDK

Perlu diperhatikan bahwa JSON di bawah mendeskripsikan respons 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"
            }
          ]
        }
      }
    }
  ]
}

Setelah mereka mengetuk chip, Anda harus meminta izin UPDATE. Kode berikut menunjukkan cara melakukannya dengan askForUpdatePermission library klien Node.js.

Node.js Dialogflow
  1. Buka agen Anda di konsol Dialogflow dan pilih intent yang Anda konfigurasi untuk update.
  2. Scroll ke bawah ke Response lalu buka tab Asisten Google.
  3. Klik Tambahkan konten pesan, lalu pilih Chip saran.
  4. Setel teks chip ke sesuatu yang mengundang pengguna untuk memilih ikut serta. Di kolom Contoh tips Actions on Google kami menetapkan chip ke Beri tahu saya tentang tips baru.
  5. Tambahkan intent Dialogflow lain, yang disebut misalnya setup_push, dan menetapkan tindakan yang sesuai, misalnya setup.push. Ekspresi pengguna intent ini harus cocok dengan teks chip keikutsertaan, pada contoh kami Beri tahu saya tentang tips baru.
Cuplikan berikut menunjukkan cara meminta izin menggunakan Tindakan di library klien Google untuk Node.js:
app.intent('Subscribe to Notifications', (conv) => {
  conv.ask(new UpdatePermission({
    intent: 'Notification',
  }));
});
Node.js Actions SDK

Anda harus mengkonfigurasi solusi NLU Anda untuk memicu fungsi yang meminta izin jika ekspresi pengguna cocok dengan nilai notifikasi push dialog keikutsertaan. Berikut adalah contoh yang sangat dasar berdasarkan pencocokan string:

conv.ask(new UpdatePermission({
  intent: 'Notification',
}));
Java Dialogflow
  1. Buka agen Anda di konsol Dialogflow dan pilih intent yang Anda konfigurasi untuk update.
  2. Scroll ke bawah ke Response lalu buka tab Asisten Google.
  3. Klik Tambahkan konten pesan, lalu pilih Chip saran.
  4. Setel teks chip ke sesuatu yang mengundang pengguna untuk memilih ikut serta. Di kolom Contoh tips Actions on Google kami menetapkan chip ke Beri tahu saya tentang tips baru.
  5. Tambahkan intent Dialogflow lain, yang disebut misalnya setup_push, dan menetapkan tindakan yang sesuai, misalnya setup.push. Ekspresi pengguna intent ini harus cocok dengan teks chip keikutsertaan, pada contoh kami Beri tahu saya tentang tips baru.
Cuplikan berikut menunjukkan cara meminta izin menggunakan Tindakan tentang library klien Java/Kotlin Google:
@ForIntent("Subscribe to Notifications")
public ActionResponse subscribeToNotifications(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.add(new UpdatePermission().setIntent("Notification"));
  return responseBuilder.build();
}
Java Actions SDK

Anda harus mengkonfigurasi solusi NLU Anda untuk memicu fungsi yang meminta izin jika ekspresi pengguna cocok dengan nilai notifikasi push dialog keikutsertaan. Berikut adalah contoh yang sangat dasar berdasarkan pencocokan string:

ResponseBuilder responseBuilder = getResponseBuilder(request);
responseBuilder.add(new UpdatePermission().setIntent("Notification"));
return responseBuilder.build();
JSON Dialogflow

Perhatikan bahwa JSON di bawah ini menjelaskan respons webhook menggunakan 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

Perlu diperhatikan bahwa JSON di bawah ini menjelaskan respons webhook menggunakan 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"
            }
          }
        }
      ]
    }
  ]
}

Menyelesaikan langganan

Untuk menyelesaikan langganan dari webhook Node.js, Anda harus menyimpan ID notifikasi pengguna dan intent yang dipilihnya. Keduanya diteruskan sebagai argumen jika pengguna memberikan izin.

Jika Action Anda dibuat dengan Dialogflow, Anda harus:

  • Tambahkan intent yang menangani actions_intent_PERMISSION.
  • Tentukan nama Action intent ke sesuatu yang dapat webhook Anda untuk nanti.

Kode berikut menunjukkan cara menangani intent Dialogflow dengan intent bernama finish_push_setup dengan nama Tindakan finish.push.setup:

Node.js Dialogflow
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.`);
  }
});
Node.js Actions SDK
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.`);
  }
});
Java Dialogflow
@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();
}
Java Actions SDK
@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 Dialogflow

Perlu diperhatikan bahwa JSON di bawah ini menjelaskan permintaan ke 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 Actions SDK

Perlu diperhatikan bahwa JSON di bawah ini menjelaskan permintaan ke 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"
        }
      ]
    }
  ]
}

Kirim notifikasi

Anda dapat mengirim notifikasi push kepada pengguna menggunakan Actions API. Untuk menggunakan API ini, Anda perlu mengaktifkan API di project Google Cloud, lalu menyiapkan dan mendownload Kunci akun layanan JSON. Lihat langkah #8 dalam petunjuk dalam contoh kode di sini.

Kemudian, Anda dapat menggunakan library klien Google OAuth2 untuk menukar kunci akun layanan untuk mendapatkan token akses dan menggunakan token tersebut untuk mengautentikasi permintaan Anda ke Actions API.

Dapatkan kunci akun layanan

  1. Buka URL ini, dengan mengganti "example-project-1" di bagian akhir dengan project ID di konsol Actions: https://console.developers.google.com/apis/api/actions.googleapis.com/overview?project=example-project-1
  2. Jika Anda melihat tombol Enable, klik tombol tersebut. Jika tidak, lanjutkan ke langkah 3.
  3. Buka URL ini, dengan mengganti "example-project-1" di bagian akhir dengan project ID di konsol Actions: https://console.developers.google.com/apis/credentials?project=example-project-1
  4. Klik Create credentials > Kunci Akun Layanan.
  5. Klik kotak Pilih di bagian Akun Layanan dan klik Layanan Baru Anda.
  6. Beri nama Akun Layanan seperti "notifikasi" dan Peran dari Pemilik Project.
  7. Pilih jenis kunci JSON dan klik Create. Kunci akun layanan JSON adalah diunduh ke komputer lokal Anda.

Tukar kunci dengan token akses dan kirim notifikasi

Untuk mengirim notifikasi melalui Actions API, Anda harus bertukar kunci akun layanan untuk token akses. Sebaiknya gunakan klien Google API {i>library<i} untuk ini. Dalam rangkaian cuplikan kode berikutnya, kita menggunakan Library klien Node.js Google API.

  1. Instal library dan permintaan klien Google API: npm install googleapis request --save
  2. Gunakan kode berikut untuk mendapatkan token akses dari kunci akun layanan dan mengirim notifikasi push:
Node.js Dialogflow
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}`);
    });
  }
});
Node.js Actions SDK
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}`);
    });
  }
});
Java Dialogflow
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);
}
Java Actions SDK
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);
}