Unity/정보

[Unity] 로컬 알림 기능 (Android)

달시_Dalsi 2024. 11. 10. 03:44

로컬 알림이란?

로컬 알림은 네트워크 요청 없이 기기 내부에서 직접 생성되는 알림입니다. 주로 아래와 같은 목적으로 사용됩니다:

  • 앱 리마인더
  • 특정 시간에 알림 표시
  • 사용자 액션 트리거

 

Unity Package 설치

 

고려 사항

 (1) Android 13 이상에서 알림 권한 요청

 if (Application.platform == RuntimePlatform.Android &&
     33 <= apiLevel &&
     !UnityEngine.Android.Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
 {
     Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
 }

 

 

 (2) API 레벨 26 이상에서 알림 채널 설정

 if (apiLevel >= 26)
 {
     var channel = new AndroidNotificationChannel()
     {
         Id = "default_channel",
         Name = "pubSdk",
         Importance = Importance.High,
         Description = "for test",
     };
     AndroidNotificationCenter.RegisterNotificationChannel(channel);
 }

채널은 알림의 그룹화를 도와 사용자 경험을 개선합니다.

알림 채널은 Id, Name, Importance, Description을 포함하여 구성됩니다.

  • Id: 고유 식별자.
  • Name: 채널 이름(사용자에게 표시됨).
  • Importance: 알림의 중요도(높음, 낮음 등 설정 가능).
  • Description: 알림 채널의 설명.

 

구현 예제 코드

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Notifications.Android;
using UnityEngine;
using UnityEngine.Android;

public class PushManager : MonoBehaviour
{
    private int maxEnergy = 100; // 최대 에너지
    private int rechargeRate = 10; // 충전 단위
    private int currentEnergy; // 현재 에너지
    private float rechargeTimeInMinutes = 1f; // 한 단위 충전에 걸리는 시간(분 단위)

    private const string lastEnergyUpdateKey = "LastEnergyUpdate";
    private const string currentEnergyKey = "CurrentEnergy";

    void Start()
    {
        // 알림 권한 요청 및 채널 설정
        SetupNotificationChannel();

        // 이전 에너지 상태 복원
        RestoreEnergyState();
    }

    void Update()
    {
        // 에너지가 모두 충전되면 알림 예약 취소
        if (currentEnergy >= maxEnergy)
        {
            AndroidNotificationCenter.CancelAllNotifications();
        }
    }

    void OnApplicationQuit()
    {
        // 앱 종료 시 현재 상태 저장
        SaveEnergyState();

        // 알림 예약
        ScheduleEnergyNotificationIfNeeded();
    }

    void RestoreEnergyState()
    {
        // 마지막 업데이트 시각 로드
        string lastUpdateString = PlayerPrefs.GetString(lastEnergyUpdateKey, DateTime.Now.ToString());
        DateTime lastUpdateTime = DateTime.Parse(lastUpdateString);

        // 현재 에너지 로드
        currentEnergy = PlayerPrefs.GetInt(currentEnergyKey, maxEnergy);

        // 경과 시간에 따라 충전 계산
        TimeSpan elapsedTime = DateTime.Now - lastUpdateTime;
        int energyRecovered = (int)(elapsedTime.TotalMinutes / rechargeTimeInMinutes) * rechargeRate;
        currentEnergy = Mathf.Clamp(currentEnergy + energyRecovered, 0, maxEnergy);

        Debug.Log($"Restored energy: {currentEnergy}, recovered: {energyRecovered} since last update.");
    }

    void SaveEnergyState()
    {
        // 현재 상태 저장
        PlayerPrefs.SetString(lastEnergyUpdateKey, DateTime.Now.ToString());
        PlayerPrefs.SetInt(currentEnergyKey, currentEnergy);
        PlayerPrefs.Save();
    }

    void ScheduleEnergyNotificationIfNeeded()
    {
        if (currentEnergy < maxEnergy)
        {
            int energyNeeded = maxEnergy - currentEnergy;
            float minutesUntilFull = energyNeeded / (float)rechargeRate * rechargeTimeInMinutes;

            var notification = new AndroidNotification
            {
                Title = "에너지가 충전되었습니다!",
                Text = "모든 에너지가 충전되었습니다. 게임을 다시 시작하세요!",
                FireTime = DateTime.Now.AddMinutes(minutesUntilFull)
            };

            AndroidNotificationCenter.SendNotification(notification, "default_channel");
            Debug.Log($"Notification scheduled to fire in {minutesUntilFull} minutes.");
        }
    }

    void SetupNotificationChannel()
    {
        string androidInfo = SystemInfo.operatingSystem;
        int apiLevel = int.Parse(androidInfo.Substring(androidInfo.IndexOf("-") + 1, 3), System.Globalization.CultureInfo.InvariantCulture);

        // Android 13 이상에서 알림 권한 요청
        if (Application.platform == RuntimePlatform.Android &&
            33 <= apiLevel &&
            !UnityEngine.Android.Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
        {
            UnityEngine.Android.Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
        }

        // Android 8.0 이상에서 알림 채널 설정
        if (apiLevel >= 26)
        {
            var channel = new AndroidNotificationChannel()
            {
                Id = "default_channel",
                Name = "Energy Notifications",
                Importance = Importance.High,
                Description = "Notifications for energy recharge",
            };
            AndroidNotificationCenter.RegisterNotificationChannel(channel);
        }
    }
}

 

RestoreEnergyState()

게임 재시작 시 저장된 에너지 상태를 복원합니다.
마지막 업데이트 시각과 경과 시간을 바탕으로 충전된 에너지를 계산합니다.

 

SaveEnergyState()

게임 종료 시 현재 에너지와 마지막 업데이트 시각을 저장합니다.
PlayerPrefs를 활용해 간단히 데이터를 관리했지만 사용하는 저장방식으로 변경하여 사용을 추천합니다.

 

ScheduleEnergyNotificationIfNeeded()

남은 에너지를 확인하여 충전 완료 시점을 계산하여 푸시 알림을 예약합니다.
어플 실행 중 에너지가 모두 충전되었다면 예약된 알림을 취소합니다.

 

SetupNotificationChannel()

Android의 apiLevel에 따라 13이상에선 알림 권한을 요청하고 26이상에선 알림 채널을 설정하여 알림을 관리해야합니다.

 

 

테스트 결과

 

 

AndroidNotification 클래스 주요 속성

var notification = new AndroidNotification
            {
                Title = "에너지가 충전되었습니다!",
                Text = "모든 에너지가 충전되었습니다. 게임을 다시 시작하세요!",
                FireTime = DateTime.Now.AddMinutes(minutesUntilFull)
            };

            AndroidNotificationCenter.SendNotification(notification, "default_channel");

위 코드에 사용되는 항목들입니다.

- Title: 알림의 제목
- Text: 알림의 본문
- FireTime: 알림이 발생할 시간
- SmallIcon: 알림에 표시될 작은 아이콘
- LargeIcon: 알림에 표시될 큰 아이콘 (Android 5.0 이상)
- RepeatInterval: 반복 알림 간격
- Grou`: 알림 그룹화 문자열

 

결론

Unity의 로컬 알림 기능을 구현하면 사용자와의 소통을 강화하고 앱의 유용성을 높일 수 있습니다. 이 글에서 다룬 Unity Push를 활용해 기존의 다른 게임들에서 볼 수 있는 알림을 만들 수 있습니다.