인앱 알림 #

인앱 알림을 사용하면 한 명 이상의 사용자에게 메시지를 쉽게 브로드캐스트할 수 있습니다. 알림, 경보 또는 게임 내 보상 및 선물 통지를 보내는 데 유용합니다.

알림은 다음에 앱을 열 때 읽을 때까지 저장되거나 연결된 사용자만 볼 수 있도록 푸시될 수 있습니다. 알림을 사용하여 게임 내에서 사용자 지정 작업을 트리거하고 클라이언트 동작을 변경할 수도 있습니다.

이러한 알림은 앱 내에서 볼 수 있으므로 앱 외부에서 볼 수 있도록 알림을 푸시하는 훌륭한 보조 수단이 됩니다.

알림 보내기 #

서버 측 코드를 사용하여 한 명 이상의 사용자에게 알림을 보낼 수 있습니다. 게임 내 모든 사용자에게 보낼 수 있으며 친구가 없어도 메시지를 교환할 수 있습니다. 또한 특정 이벤트에 대해 서버에서 암시적으로 여러 알림을 보냅니다.

각 알림에는 분류에 사용되는 코드가 있습니다. 알림에 대해 선택한 코드는 0에서 시작하고 위로 증가해야 합니다. 예약된 메시지 코드는 아래를 참조하세요.

알림에는 JSON으로 인코딩될 컨텐츠 객체가 있습니다.

알림을 보낼 때 지속적으로 표시할 수 있습니다. 비지속 메시지는 현재 서버에 연결된 클라이언트(즉, 온라인 상태인 사용자)만 수신합니다. 알림이 읽기 전에 소실되지 않도록 하려면 전송 시 알림을 지속적으로 표시해야 합니다.

Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
local nk = require("nakama")

local user_id = "user id to send to"
local sender_id = nil -- "nil" for server sent.
local content = {
  item_id = "192308394345345",
  item_icon = "storm_bringer_sword.png"
}
local subject = "You earned a secret item!"
local code = 1
local persistent = true

nk.notification_send(user_id, subject, content, code, sender_id, persistent)
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
subject := "You earned a secret item!"
content := map[string]interface{}{
    "item_id": "192308394345345",
    "item_icon": "storm_bringer_sword.png"
}
userID := "user id to send to"
senderID := "" // Empty string for server sent.
code := 1
persistent := true

nk.NotificationSend(ctx, userID, subject, content, code, senderID, persistent)
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let receiverId = '4c2ae592-b2a7-445e-98ec-697694478b1c';
let subject = "You've unlocked level 100!";
let content = {
  rewardCoins: 1000,
}
let code = 101;
let senderId = 'dcb891ea-a311-4681-9213-6741351c9994' // who the message if from
let persistent = true;

nk.notificationSend(receiverId, subject, content, code, senderId, persistent);

알림 받기 #

클라이언트 연결 시 수신되는 알림에 대해 콜백을 등록할 수 있습니다. 핸들러는 클라이언트 소켓이 연결된 상태를 유지하는 한 알림이 수신될 때마다 호출됩니다. 여러 메시지가 반환되면(성능을 위해 일괄 처리됨) 핸들러는 각 알림에 대해 한 번만 호출됩니다.

Client
1
2
3
4
socket.onnotification = (notification) => {
  console.log("Received %o", notification);
  console.log("Notification content %s", notification.content);
}
Client
1
2
3
4
5
socket.ReceivedNotification += notification =>
{
    Console.WriteLine("Received: {0}", notification);
    Console.WriteLine("Notification content: '{0}'", notification.Content);
};
Client
1
2
3
4
5
6
7
rtListener->setNotificationsCallback([](const NNotificationList& notifications)
{
    for (auto& notification : notifications.notifications)
    {
        std::cout << "Notification content " << notification.content << std::cout;
    }
});
Client
1
2
3
4
5
6
7
8
9
SocketListener listener = new AbstractSocketListener() {
    @Override
    public void onNotifications(final NotificationList notifications) {
        System.out.println("Received notifications");
        for (Notification notification : notifications.getNotificationsList()) {
            System.out.format("Notification content: %s", notification.getContent());
        }
    }
};
Client
1
2
3
4
5
6
7
func _ready():
    # First, setup the socket as explained in the authentication section.
    socket.connect("received_notification", self, "_on_notification")

func _on_notification(p_notification : NakamaAPI.ApiNotification):
    print(p_notification)
    print(p_notification.content)
Client
1
2
3
4
5
local group_id = "<group id>"
socket.on_notification(function(message)
  print("Received notification!")
  pprint(message)
end)

Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.

알림 나열 #

사용자가 오프라인일 때 받은 알림을 나열할 수 있습니다. 이러한 알림은 전송될 때 “지속적"으로 표시된 알림입니다. 정확한 로직은 게임이나 앱에 따라 다르지만 클라이언트가 다시 연결된 후 알림을 검색하는 것이 좋습니다. 그런 다음 목록과 함께 게임이나 앱 내에서 UI를 표시할 수 있습니다.

Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/notification?limit=10" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
const result = await client.listNotifications(session, 10);
result.notifications.forEach(notification => {
  console.info("Notification code %o and subject %o.", notification.code, notification.subject);
});
console.info("Fetch more results with cursor:", result.cacheable_cursor);
Client
1
2
3
4
5
var result = await client.ListNotificationsAsync(session, 10);
foreach (var n in result.Notifications)
{
    Console.WriteLine("Subject '{0}' content '{1}'", n.Subject, n.Content);
}
Client
1
2
3
4
5
6
7
8
9
auto successCallback = [](NNotificationListPtr list)
{
    for (auto& notification : list->notifications)
    {
        std::cout << "Notification content " << notification.content << std::endl;
    }
};

client->listNotifications(session, 10, opt::nullopt, successCallback);
Client
1
2
3
4
NotificationList notifications = client.listNotifications(session, 10).get();
for (Notification notification : notifications.getNotificationsList()) {
    System.out.format("Notification content: %s", notification.getContent());
}
Client
1
2
3
4
5
6
var result : NakamaAPI.ApiNotificationList = yield(client.list_notifications_async(session, 10), "completed")
if result.is_exception():
    print("An error occurred: %s" % result)
    return
for n in result.notifications:
    print("Subject '%s' content '%s'" % [n.subject, n.content])
Client
1
2
3
4
5
GET /v2/notification?limit=10
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
Client
1
2
3
4
5
6
7
8
local result = client.list_notifications(10)
if result.error then
  print(result.message)
  return
end
for _,notification in ipairs(result.notifications) do
  pprint(notification)
end

알림 목록은 한 번에 최대 100개까지 일괄적으로 검색할 수 있습니다. 모든 메시지를 검색하려면 캐시 가능한 커서로 메시지를 누적해야 합니다. 이 커서를 클라이언트에 유지하고 사용자가 오프라인 동안 놓쳤을 수 있는 알림을 확인하기 위해 다시 연결할 때 사용할 수 있습니다.

일반적으로 한 번에 100개의 알림만 나열하게 됩니다. 그렇지 않으면 사용자가 피로해질 수 있습니다. 좋은 해결책은 사용자가 UI 패널의 맨 아래로 스크롤할 때 UI에서 다음 100개의 알림을 가져오도록 만드는 것입니다.

Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/notification?limit=100&cursor=<cacheableCursor>" \
  -H 'Authorization: Bearer <session token>'
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var allNotifications = [];

var accumulateNotifications = (cursor) => {
  var result = await client.listNotifications(session, 100, cursor);
  if (result.notifications.length == 0) {
    return;
  }
  allNotifications.concat(result.notifications.notifications);
  accumulateNotifications(result.cacheable_cursor);
}
accumulateNotifications("");
Client
1
2
3
4
5
6
7
8
9
var result = await client.ListNotificationsAsync(session, 100);
if (!string.IsNullOrEmpty(result.CacheableCursor))
{
    result = await client.ListNotificationsAsync(session, 100, result.CacheableCursor);
    foreach (var n in result.Notifications)
    {
        Console.WriteLine("Subject '{0}' content '{1}'", n.Subject, n.Content);
    }
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// add to your class: std::vector<NNotification> allNotifications;

void YourClass::accumulateNotifications(const string& cursor)
{
    auto successCallback = [this](NNotificationListPtr list)
    {
        allNotifications.insert(allNotifications.end(), list->notifications.begin(), list->notifications.end());

        if (!list->cacheableCursor.empty())
        {
            accumulateNotifications(list->cacheableCursor);
        }
    };

    client->listNotifications(session, 100, cursor, successCallback);
}

accumulateNotifications("");
Client
1
2
3
4
5
6
7
NotificationList notifications = client.listNotifications(session, 10).get();
if (notifications.getCacheableCursor() != null) {
    notifications = client.listNotifications(session, 10, notifications.getCacheableCursor()).get();
    for (Notification notification : notifications.getNotificationsList()) {
        System.out.format("Notification content: %s", notification.getContent());
    }
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var result : NakamaAPI.ApiNotificationList = yield(client.list_notifications_async(session, 1), "completed")
if result.is_exception():
    print("An error occurred: %s" % result)
    return
for n in result.notifications:
    print("Subject '%s' content '%s'" % [n.subject, n.content])
while result.cacheable_cursor and result.notifications:
    result = yield(client.list_notifications_async(session, 10, result.cacheable_cursor), "completed")
    if result.is_exception():
          print("An error occurred: %s" % result)
          return
    for n in result.notifications:
          print("Subject '%s' content '%s'" % [n.subject, n.content])
print("Done")
Client
1
2
3
4
5
GET /v2/notification?limit=100&cursor=<cacheableCursor>
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
local cursor = nil
repeat
  local result = client.list_notifications(10, cursor)
  if result.error then
      print(result.message)
      break
  end

  cursor = result.cursor
  for _,notification in ipairs(result.notifications) do
      pprint(notification)
  end
until not cursor

클라이언트가 목록을 마지막으로 검색한 이후에 추가된 알림만 검색하는 것이 좋을 수 있습니다. 이는 각 목록 메시지와 함께 반환된 캐시 가능한 커서로 수행할 수 있습니다. 새 목록 작업을 통해 커서를 보내면 표시된 알림보다 더 최신인 알림만 검색합니다.

캐시 가능한 커서는 검색된 가장 최근 알림의 위치를 표시합니다. 캐시 가능한 커서를 장치 저장소에 저장하고 클라이언트가 최근 알림에 대한 다음 요청을 실시할 때 사용하는 것이 좋습니다.

Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/notification?limit=10&cursor=<cacheableCursor>" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
const cacheableCursor = "<cacheableCursor>";
const result = await client.listNotifications(session, 10, cacheableCursor);
result.notifications.forEach(notification => {
  console.info("Notification code %o and subject %o.", notification.code, notification.subject);
});
Client
1
2
3
4
5
6
const string cacheableCursor = "<cacheableCursor>";
var result = await client.ListNotificationsAsync(session, 10, cacheableCursor);
foreach (var n in result.Notifications)
{
    Console.WriteLine("Subject '{0}' content '{1}'", n.Subject, n.Content);
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
auto successCallback = [](NNotificationListPtr list)
{
    for (auto& notification : list->notifications)
    {
        std::cout << "Notification content " << notification.content << std::endl;
    }
};

string cacheableCursor = "<cacheableCursor>";
client->listNotifications(session, 10, cacheableCursor, successCallback);
Client
1
2
3
4
5
String cacheableCursor = "<cacheableCursor>";
NotificationList notifications = client.listNotifications(session, 10, cacheableCursor).get();
for (Notification notification : notifications.getNotificationsList()) {
    System.out.format("Notification content: %s", notification.getContent());
}
Client
1
2
3
4
5
6
7
var cursor = "<cacheable-cursor>";
var result : NakamaAPI.ApiNotificationList = yield(client.list_notifications_async(session, 10, cursor), "completed")
if result.is_exception():
    print("An error occurred: %s" % result)
    return
for n in result.notifications:
    print("Subject '%s' content '%s'" % [n.subject, n.content])
Client
1
2
3
4
5
GET /v2/notification?limit=10&cursor=<cacheableCursor>
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
local cursor = "<cacheable-cursor>"
local result = client.list_notifications(10, cursor)
if result.error then
  print(result.message)
  return
end

for _,notification in ipairs(result.notifications) do
  pprint(notification)
end

알림 삭제 #

클라이언트에서 하나 이상의 알림을 삭제할 수 있습니다. 따라서 사용자가 읽거나 확인한 알림을 제거하고 오래된 메시지가 쌓이지 않도록 할 수 있습니다. 알림이 삭제되면 관련된 모든 기록이 시스템에서 제거되며 복원할 수 없습니다.

Client
1
2
curl -X DELETE "http://127.0.0.1:7350/v2/notification?ids=<notificationId>&ids=<notificationId>" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
const notificationIds = ["<notificationId>"];
await client.deleteNotifications(session, notificationIds);
Client
1
2
var notificationIds = new[] {"<notificationId>"};
await client.DeleteNotificationsAsync(session, notificationIds);
Client
1
client->deleteNotifications(session, { "<notificationId>" });
Client
1
2
String[] notificationIds = new String[] {"<notificationId>"};
client.deleteNotifications(session, notificationIds).get();
Client
1
2
3
4
5
6
var notification_ids = ["<notification-id>"]
var delete : NakamaAsyncResult = yield(client.delete_notifications_async(session, notification_ids), "completed")
if delete.is_exception():
    print("An error occurred: %s" % delete)
    return
print("Deleted")
Client
1
2
3
4
5
DELETE /v2/notification?ids=<notificationId>&ids=<notificationId>
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
Client
1
2
3
4
5
6
local ids = { "<notification-id>" }
local result = client.delete_notifications(ids)
if result.error then
  print(result.message)
  return
end

알림 코드 #

서버는 특정 이벤트에 대해 암시적으로 전송된 메시지에 대해 0보다 작거나 같은 모든 코드를 예약합니다. 단순히 0보다 큰 값을 사용하여 고유한 알림 코드를 정의할 수 있습니다.

이 코드로 UI에 알림을 표시하는 방법을 결정할 수 있습니다.

코드목적
0예약됨
-1오프라인 상태이거나 채널에 있지 않은 상태에서 사용자 X가 보낸 메시지.
-2사용자 X가 귀하를 친구로 추가하려고 합니다.
-3사용자 X가 귀하의 친구 초대를 수락했습니다.
-4X 그룹에서 귀하를 수락했습니다.
-5사용자 X가 귀하의 그룹에 가입하려고 합니다.
-6귀하의 친구 X가 방금 게임에 가입했습니다.
-7[single_socket 구성]을 통한 닫힌 소켓에 대한 최종 알림(../../getting-started/configuration/#session).