Merge pull request '[✨] APNS(.p12) 개발' (#6) from seonkyu.kim/AcaMate_API:main into debug
All checks were successful
Back/pipeline/head This commit looks good
All checks were successful
Back/pipeline/head This commit looks good
Reviewed-on: https://git.ipstein.myds.me/AcaMate/AcaMate_API/pulls/6
This commit is contained in:
commit
cf63383b04
|
@ -12,7 +12,7 @@ public class Status
|
||||||
public string message { get; set; }
|
public string message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ErrorResponse
|
public static class DefaultResponse
|
||||||
{
|
{
|
||||||
// private static readonly Lazy<ErrorResponse> _instance = new Lazy<ErrorResponse>();
|
// private static readonly Lazy<ErrorResponse> _instance = new Lazy<ErrorResponse>();
|
||||||
// public static ErrorResponse Instace => _instance.Value;
|
// public static ErrorResponse Instace => _instance.Value;
|
||||||
|
@ -22,6 +22,15 @@ public static class ErrorResponse
|
||||||
// // 외부 초기화 방지
|
// // 외부 초기화 방지
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
public static readonly APIResponseStatus<string> Success = new APIResponseStatus<string>
|
||||||
|
{
|
||||||
|
status = new Status()
|
||||||
|
{
|
||||||
|
code = "000",
|
||||||
|
message = "정상"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static readonly APIResponseStatus<string> InvalidInputError = new APIResponseStatus<string>
|
public static readonly APIResponseStatus<string> InvalidInputError = new APIResponseStatus<string>
|
||||||
{
|
{
|
||||||
status = new Status()
|
status = new Status()
|
||||||
|
|
|
@ -8,7 +8,7 @@ using Version = AcaMate.V1.Models.Version;
|
||||||
namespace AcaMate.V1.Controllers;
|
namespace AcaMate.V1.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/v1/in/app")]
|
[Route("/api/v1/in/app")]
|
||||||
[ApiExplorerSettings(GroupName = "공통")]
|
[ApiExplorerSettings(GroupName = "공통")]
|
||||||
public class AppController : ControllerBase
|
public class AppController : ControllerBase
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ public class AppController : ControllerBase
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(type))
|
if (string.IsNullOrEmpty(type))
|
||||||
{
|
{
|
||||||
return BadRequest(ErrorResponse.InvalidInputError);
|
return BadRequest(DefaultResponse.InvalidInputError);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -34,7 +34,7 @@ public class AppController : ControllerBase
|
||||||
|
|
||||||
if (version == null)
|
if (version == null)
|
||||||
{
|
{
|
||||||
return NotFound(ErrorResponse.NotFoundError);
|
return NotFound(DefaultResponse.NotFoundError);
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = new APIResponseStatus<Version>
|
var response = new APIResponseStatus<Version>
|
||||||
|
@ -60,7 +60,7 @@ public class AppController : ControllerBase
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return StatusCode(500, ErrorResponse.UnknownError);
|
return StatusCode(500, DefaultResponse.UnknownError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ namespace AcaMate.V1.Controllers;
|
||||||
|
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("error")]
|
[Route("/api/error")]
|
||||||
public class ErrorController: ControllerBase
|
public class ErrorController: ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
|
|
@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
namespace AcaMate.V1.Controllers;
|
namespace AcaMate.V1.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("v1/in/member")]
|
[Route("/api/v1/in/member")]
|
||||||
[ApiExplorerSettings(GroupName = "사업자 정보")]
|
[ApiExplorerSettings(GroupName = "사업자 정보")]
|
||||||
public class MemberController: ControllerBase
|
public class MemberController: ControllerBase
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,24 +1,59 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Swashbuckle.AspNetCore.Annotations;
|
|
||||||
|
using AcaMate.V1.Services;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace AcaMate.V1.Controllers;
|
namespace AcaMate.V1.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("v1/in/push")]
|
[Route("/api/v1/in/push")]
|
||||||
[ApiExplorerSettings(GroupName = "공통")]
|
[ApiExplorerSettings(GroupName = "공통")]
|
||||||
public class PushController: ControllerBase
|
public class PushController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private readonly IWebHostEnvironment _env;
|
||||||
|
|
||||||
|
public PushController(IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
_env = env;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet()]
|
[HttpGet()]
|
||||||
[CustomOperation("푸시 확인","저장된 양식을 확인 할 수 있다..", "푸시")]
|
[CustomOperation("푸시 확인", "저장된 양식을 확인 할 수 있다..", "푸시")]
|
||||||
public IActionResult GetPushData()
|
public IActionResult GetPushData()
|
||||||
{
|
{
|
||||||
return Ok("SEND");
|
return Ok("SEND");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("send")]
|
[HttpPost("send")]
|
||||||
[CustomOperation("푸시전송","저장된 양식으로, 사용자에게 푸시를 전송한다.", "푸시")]
|
[CustomOperation("푸시전송", "저장된 양식으로, 사용자에게 푸시를 전송한다.", "푸시")]
|
||||||
public IActionResult SendPush()
|
public async Task<IActionResult> SendPush(string deviceToken, string title, string body, int badge)
|
||||||
{
|
{
|
||||||
return Ok("SEND");
|
var keysFilePath = "private/appleKeys.json";
|
||||||
|
var uri = "";
|
||||||
|
var p12FilePath = "";
|
||||||
|
|
||||||
|
if (_env.IsDevelopment())
|
||||||
|
{
|
||||||
|
uri = "https://api.sandbox.push.apple.com";
|
||||||
|
p12FilePath = "private/AM_Push_Sandbox.p12";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uri = "https://api.push.apple.com";
|
||||||
|
p12FilePath = "private/AM_Push.p12";
|
||||||
|
}
|
||||||
|
var apnsTopic = "me.myds.ipstien.acamate.AcaMate";
|
||||||
|
|
||||||
|
|
||||||
|
var pushService = new PushServiceWithP12(keysFilePath, p12FilePath, apnsTopic);
|
||||||
|
|
||||||
|
// 푸시 알림 전송
|
||||||
|
await pushService.SendPushAsync(uri, deviceToken, title, body, badge);
|
||||||
|
|
||||||
|
return Ok("Push notification sent.");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ namespace AcaMate.V1.Controllers;
|
||||||
|
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/v1/in/user")]
|
[Route("/api/v1/in/user")]
|
||||||
[ApiExplorerSettings(GroupName = "사용자")]
|
[ApiExplorerSettings(GroupName = "사용자")]
|
||||||
public class UserController: ControllerBase
|
public class UserController: ControllerBase
|
||||||
{
|
{
|
||||||
|
|
35
Program/V1/Models/PushPayload.cs
Normal file
35
Program/V1/Models/PushPayload.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
|
namespace AcaMate.V1.Models;
|
||||||
|
|
||||||
|
public class Payload
|
||||||
|
{
|
||||||
|
public Aps aps { get; set; }
|
||||||
|
// public string customKey { get; set; } 이런식으로 추가도 가능
|
||||||
|
|
||||||
|
public string ToJson()
|
||||||
|
{
|
||||||
|
return System.Text.Json.JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Aps
|
||||||
|
{
|
||||||
|
public Aps()
|
||||||
|
{
|
||||||
|
sound = "default";
|
||||||
|
content_available = 1;
|
||||||
|
}
|
||||||
|
public Alert alert { get; set; }
|
||||||
|
public int badge { get; set; } // 앱 아이콘 표시 배지 숫자 설정
|
||||||
|
public string sound { get; set; } // 사운드 파일 이름 default = "default"
|
||||||
|
public int content_available { get; set; } // 백그라운드 알림 활성화: 필수 (1)
|
||||||
|
public string? category { get; set; } // 알림에 대한 특정 액션을 정의
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Alert
|
||||||
|
{
|
||||||
|
public string title { get; set; } // 제목
|
||||||
|
public string body { get; set; } // 내용
|
||||||
|
public string? subtitle { get; set; } // 부제목 (선택)
|
||||||
|
}
|
74
Program/V1/Services/PushService.cs
Normal file
74
Program/V1/Services/PushService.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace AcaMate.V1.Services;
|
||||||
|
using AcaMate.V1.Models;
|
||||||
|
|
||||||
|
public class PushServiceWithP12
|
||||||
|
{
|
||||||
|
private readonly string p12Path;
|
||||||
|
private readonly string p12Password;
|
||||||
|
private readonly string apnsTopic;
|
||||||
|
|
||||||
|
public PushServiceWithP12(string keysFilePath, string p12Path, string apnsTopic)
|
||||||
|
{
|
||||||
|
var keys = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(keysFilePath));
|
||||||
|
this.p12Password = keys["Password"];
|
||||||
|
this.p12Path = p12Path;
|
||||||
|
this.apnsTopic = apnsTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendPushAsync(string uri,string deviceToken, string title, string body, int badge)
|
||||||
|
{
|
||||||
|
var payload = new Payload()
|
||||||
|
{
|
||||||
|
aps = new Aps()
|
||||||
|
{
|
||||||
|
alert = new Alert()
|
||||||
|
{
|
||||||
|
title = title,
|
||||||
|
body = body
|
||||||
|
},
|
||||||
|
badge = badge
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||||
|
|
||||||
|
var certificate = new X509Certificate2(p12Path, p12Password);
|
||||||
|
|
||||||
|
var handler = new HttpClientHandler();
|
||||||
|
handler.ClientCertificates.Add(certificate);
|
||||||
|
|
||||||
|
using var client = new HttpClient(handler)
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri($"{uri}")
|
||||||
|
};
|
||||||
|
|
||||||
|
client.DefaultRequestHeaders.Add("apns-topic", apnsTopic);
|
||||||
|
client.DefaultRequestHeaders.Add("apns-priority", "10");
|
||||||
|
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await client.PostAsync($"/3/device/{deviceToken}", content);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Push notification sent successfully.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var errorContent = await response.Content.ReadAsStringAsync();
|
||||||
|
Console.WriteLine($"Failed to send push notification. Status Code: {response.StatusCode}, Error: {errorContent}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"An error occurred while sending the push notification: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user