Edit
알림 허브
애저가 한국에서 많은 사람들이 사용하는 인기있는 서비스가 아니라, 뭔가 하나 하려면 생각보다 많은 공을 들여야 했다. 일단 내가 삽질을 헀으니, 다음 사람은 삽질하질 않길 바라는 마음으로 자주 Azure(애저)
와 관련된 글을 올리려 한다. MS
를 좋아하지 않았지만, 최근 행보와 서비스가 참 마음에 들었다. 특히 아마존 그 언저리되는 수준의 애저 서비스는 상당히 인상 깊었다. 그래서 최근 내가 운영하는 스타트업 Haffle
은 슈퍼레디
라는 서비스를 만들며 이 애저를 이용하기로 했다. 슈퍼레디
특성상 꼭 필요했던 서비스가 바로 푸시 알림이다. 이것을 구현하기는 어렵지 않겠지만, 다수의 사용자가 어떻게 알림을 구독하는지를 제어하고 이를 한 사용자의 다수의 각기 다른 디바이스에 알림을 골고루 뿌리는 일이 꽤 번거롭게 생각됐다. 아니, 본질인 서비스를 만드는 것 보다 오히려 여기에 상당한 시간을 들여야 한다 생각이 들었다.
그러다 알게된 서비스가 바로 애저의 알림허브
다. 알림 허브는 다양한 플랫폼에서 지원되는 푸시 알림 인프라 서비스로, tag
를 이용해 마치 검색하듯 알림을 손쉽게 보낼 수 있다. 빠르고 저렴하며, 우리가 제작하는 것 보다 안정적이라는 점이 상당히 마음에 들었다. 애저를 이용해 알림 인프라를 구축하는 비용보다 저렴하면서도 필요한 모든 기능이 제공됐다.
어찌됐든 쓰기로하고 나서 막상 개발하려니 막막했는데, 문서화가 잘 되어있지 않은 점 때문이었다. 당연하게도 C#쪽 문서는 완벽했지만 nodejs쪽은 불친절한 API 문서 외에는 거의 뭐 설명서가 제대로 없었다. 공식 사이트에선 찾을 수 없어서 이리저리 뒤져봤는데 원하는 만큼의 딱 들어맞는 예시는 찾을 수 없었다. 생각보다 구글에서 영어로 찾아도 잘 안찾아지는? 그래서 내가 쓴다.
뭔가 멋지게 설명하고 싶은데, 어차피 예제 코드만 볼 것 같아, 코드만 쫙 보여주는 식으로 쓰겠다. 안드로이드와 아이폰만 우리가 필요해서 두개의 코드만 있는데, 원래는 엄청 다양한 플랫폼을 지원한다.
먼저,
당연히 애저에 가입하고, 관리 포털을 접속하여 알림허브 서비스를 구성해야한다. 서비스 버스
메뉴에서 알림허브를 만들 수 있다.
그리고 나면 npm
으로 azure
패키지를 설치한다.
sudo npm install azure
이후, 서브라임 텍스트 같은 편집기를 켜서 작업을 시작한다. 첫 줄에 먼저 모듈을 로드한다.
var azure = require('azure');
그리고 알림 허브와 연결을 하고, 명령을 처리해줄 객체를 만들어야한다.
var notificationHubService = azure.createNotificationHubService('hubname','connectionstring');
저기서 파라매터로 들어가는 hubname
과 connectionstring
은 Azure 관리 포털에서 알 수 있다.
hubname
은 서비스 허브
에서 구성할 때 입력한 이름이고, connectionstring
은 알림 허브 대시보드 어딘가에 보이는 연결 문자열 보기
를 클릭하면 알 수 있다. 그 긴 연결 문자열
을 복붙하면 된다.
태그란?
잠깐 알아야할 게 있다. 애저는 태그를 사용해 푸시 알림의 스코프를 관리한다. 모든 사용자에게 브로드캐스트 할 수도 있지만, 어떨 때는 딱 한 명한태만 하고 싶을 때도 있다. 예를들어 나는 아이폰과 아이패드, 그리고 안드로이드 폰 세개를 쓰는데, 내게 와야할 알림이 아이패드만 오거나 아이폰에만 오면 안되고 3개의 디바이스 모두에 와야하지 않겠는가. 이럴때 tag
를 youngkyu
라고 쓰고, youngkyu
란 태그에 푸시를 쏘면 모든 youngkyu
의 디바이스에 푸시 알림이 도착한다.
서비스 버스 알림 허브에 시그니처와 API 키 등록
알림 허브에 구성
을 클릭하면 APNS와 GCM의 시그니처와 키를 등록하는 곳이 있다. 여기에 해당 파일과 키를 올려줘야 애저에서 처리할 수 있는 환경이 조성된다.
디바이스 등록하기
먼저 디바이스를 등록해야한다. 이때 youngkyu
로 예시를 들었던 tag
도 설정한다. 잘 추상화되어있어서, 푸시알림의 과정을 정확히 이해하지 못해도 원활히 사용할 수 있다. 이 과정에 대한 얘기는 다음에 포스팅하겠다.
아이폰
먼저 아이폰의 deviceToken
이 필요하다. 이건 애저와 관련이 없으므로 여기서 설명하지 않는다.
notificationHubService.apns
.createNativeRegistration(deviceToken,tags,null,function(error){
// To do
});
여기서 파라매터에 deviceToken
은 받아온 토큰을 집어넣고, tags
에는 배열에 담은 태그들을 집어넣는다. 세번째 null
은 option
으로 중요하지 않다. 제대로 설명도 안되있어서 아직 기능이 크게는 없는 듯 하다. 마지막 callback
에 이후 할 작업 함수를 넣는다.
아래는 내가 쓴 코드 일부다.
notificationHubService.gcm
.createNativeRegistration(deviceToken,["user","user."+userId],null,function(error){
if(!error) {
}
});
태그에 ["user","user."+userId]
가 보이는가. 이렇게 적게되면 이후 "user"
라는 태그에 푸시를 때리면 모든 "user"
태그를 가진 디바이스가 받게 된다. 그리고 "user.12"
라고 하면 12번 유저 아이디의 사용자만 받게 되는 식이다.
안드로이드
마찬가지로 deviceToken
인 gcmRegistrationId
가 먼저 필요하다.
notificationHubService.gcm
.createNativeRegistration(gcmRegistrationId,tags,null,function(error){
// To do
});
위와 똑같다. gcm
만 빼고.
푸시 보내기
등록이 끝나고 나면, 아래 코드를 실행해본다.
var payload = {
alert : "hello noti!",
sound : "default"
}
notificationHubService.apns.send(null,payload,function(error){});
띵똥. 푸시가 왔는가? payload
에 sound
가 소리를 내는 역할을 하고, alert
이 글을 표현한다. 그리고 send()
의 첫번째 인자는 tag
인데, null
이면 브로드캐스트다. 모든 등록된 아이폰/IOS 디바이스에 전송한다. 따라서 받게 되는 것이다.
var payload = {
alert : "hello users!",
sound : "default"
}
notificationHubService.apns.send("user",payload,function(error){});
위와 같이 보내면 user
태그를 가진 디바이스만 받게 된다. 만약 태그를 여러개 지정하고 싶다면, 아래와 같은 규칙을 쓰면 된다.
- 여러 태그들에 : “user.12||user.23||user.24”
- 두 태그 다 가지고 있는 : “user||post.15”
간단하다.
%23%20nodejs%uB85C%20Azure%28%uC560%uC800%29%20%uD074%uB77C%uC6B0%uB4DC%20%uC54C%uB9BC%20%uD5C8%uBE0C%20%uD478%uC2DC%uC54C%uB9BC%20%uBCF4%uB0B4%uAE30%0A%0A@%28%uD0DC%uADF8%29%5B%uC560%uC800%7CAzure%7C%uD478%uC2DC%uC54C%uB9BC%7C%uC54C%uB9BC%uD5C8%uBE0C%7Cnodejs%7C%uD2F0%uC2A4%uD1A0%uB9AC%5D%0A%0A%23%23%20%uC54C%uB9BC%20%uD5C8%uBE0C%0A%0A%uC560%uC800%uAC00%20%uD55C%uAD6D%uC5D0%uC11C%20%uB9CE%uC740%20%uC0AC%uB78C%uB4E4%uC774%20%uC0AC%uC6A9%uD558%uB294%20%uC778%uAE30%uC788%uB294%20%uC11C%uBE44%uC2A4%uAC00%20%uC544%uB2C8%uB77C%2C%20%uBB54%uAC00%20%uD558%uB098%20%uD558%uB824%uBA74%20%uC0DD%uAC01%uBCF4%uB2E4%20%uB9CE%uC740%20%uACF5%uC744%20%uB4E4%uC5EC%uC57C%20%uD588%uB2E4.%20%uC77C%uB2E8%20%uB0B4%uAC00%20%uC0BD%uC9C8%uC744%20%uD5C0%uC73C%uB2C8%2C%20%uB2E4%uC74C%20%uC0AC%uB78C%uC740%20%uC0BD%uC9C8%uD558%uC9C8%20%uC54A%uAE38%20%uBC14%uB77C%uB294%20%uB9C8%uC74C%uC73C%uB85C%20%uC790%uC8FC%20%60Azure%28%uC560%uC800%29%60%uC640%20%uAD00%uB828%uB41C%20%uAE00%uC744%20%uC62C%uB9AC%uB824%20%uD55C%uB2E4.%20%60MS%60%uB97C%20%uC88B%uC544%uD558%uC9C0%20%uC54A%uC558%uC9C0%uB9CC%2C%20%uCD5C%uADFC%20%uD589%uBCF4%uC640%20%uC11C%uBE44%uC2A4%uAC00%20%uCC38%20%uB9C8%uC74C%uC5D0%20%uB4E4%uC5C8%uB2E4.%20%uD2B9%uD788%20%uC544%uB9C8%uC874%20%uADF8%20%uC5B8%uC800%uB9AC%uB418%uB294%20%uC218%uC900%uC758%20%uC560%uC800%20%uC11C%uBE44%uC2A4%uB294%20%uC0C1%uB2F9%uD788%20%uC778%uC0C1%20%uAE4A%uC5C8%uB2E4.%20%uADF8%uB798%uC11C%20%uCD5C%uADFC%20%uB0B4%uAC00%20%uC6B4%uC601%uD558%uB294%20%uC2A4%uD0C0%uD2B8%uC5C5%20%60Haffle%60%uC740%20%60%uC288%uD37C%uB808%uB514%60%uB77C%uB294%20%uC11C%uBE44%uC2A4%uB97C%20%uB9CC%uB4E4%uBA70%20%uC774%20%uC560%uC800%uB97C%20%uC774%uC6A9%uD558%uAE30%uB85C%20%uD588%uB2E4.%20%60%uC288%uD37C%uB808%uB514%60%20%uD2B9%uC131%uC0C1%20%uAF2D%20%uD544%uC694%uD588%uB358%20%uC11C%uBE44%uC2A4%uAC00%20%uBC14%uB85C%20%uD478%uC2DC%20%uC54C%uB9BC%uC774%uB2E4.%20%uC774%uAC83%uC744%20%uAD6C%uD604%uD558%uAE30%uB294%20%uC5B4%uB835%uC9C0%20%uC54A%uACA0%uC9C0%uB9CC%2C%20%uB2E4%uC218%uC758%20%uC0AC%uC6A9%uC790%uAC00%20%uC5B4%uB5BB%uAC8C%20%uC54C%uB9BC%uC744%20%uAD6C%uB3C5%uD558%uB294%uC9C0%uB97C%20%uC81C%uC5B4%uD558%uACE0%20%uC774%uB97C%20%uD55C%20%uC0AC%uC6A9%uC790%uC758%20%uB2E4%uC218%uC758%20%uAC01%uAE30%20%uB2E4%uB978%20%uB514%uBC14%uC774%uC2A4%uC5D0%20%uC54C%uB9BC%uC744%20%uACE8%uACE0%uB8E8%20%uBFCC%uB9AC%uB294%20%uC77C%uC774%20%uAF64%20%uBC88%uAC70%uB86D%uAC8C%20%uC0DD%uAC01%uB410%uB2E4.%20%uC544%uB2C8%2C%20%uBCF8%uC9C8%uC778%20%uC11C%uBE44%uC2A4%uB97C%20%uB9CC%uB4DC%uB294%20%uAC83%20%uBCF4%uB2E4%20%uC624%uD788%uB824%20%uC5EC%uAE30%uC5D0%20%uC0C1%uB2F9%uD55C%20%uC2DC%uAC04%uC744%20%uB4E4%uC5EC%uC57C%20%uD55C%uB2E4%20%uC0DD%uAC01%uC774%20%uB4E4%uC5C8%uB2E4.%0A%0A%uADF8%uB7EC%uB2E4%20%uC54C%uAC8C%uB41C%20%uC11C%uBE44%uC2A4%uAC00%20%uBC14%uB85C%20%uC560%uC800%uC758%20%60%uC54C%uB9BC%uD5C8%uBE0C%60%uB2E4.%20%uC54C%uB9BC%20%uD5C8%uBE0C%uB294%20%uB2E4%uC591%uD55C%20%uD50C%uB7AB%uD3FC%uC5D0%uC11C%20%uC9C0%uC6D0%uB418%uB294%20%uD478%uC2DC%20%uC54C%uB9BC%20%uC778%uD504%uB77C%20%uC11C%uBE44%uC2A4%uB85C%2C%20%20%60tag%60%uB97C%20%uC774%uC6A9%uD574%20%uB9C8%uCE58%20%uAC80%uC0C9%uD558%uB4EF%20%uC54C%uB9BC%uC744%20%uC190%uC27D%uAC8C%20%uBCF4%uB0BC%20%uC218%20%uC788%uB2E4.%20%uBE60%uB974%uACE0%20%uC800%uB834%uD558%uBA70%2C%20%uC6B0%uB9AC%uAC00%20%uC81C%uC791%uD558%uB294%20%uAC83%20%uBCF4%uB2E4%20%uC548%uC815%uC801%uC774%uB77C%uB294%20%uC810%uC774%20%uC0C1%uB2F9%uD788%20%uB9C8%uC74C%uC5D0%20%uB4E4%uC5C8%uB2E4.%20%20%uC560%uC800%uB97C%20%uC774%uC6A9%uD574%20%uC54C%uB9BC%20%uC778%uD504%uB77C%uB97C%20%uAD6C%uCD95%uD558%uB294%20%uBE44%uC6A9%uBCF4%uB2E4%20%uC800%uB834%uD558%uBA74%uC11C%uB3C4%20%uD544%uC694%uD55C%20%uBAA8%uB4E0%20%uAE30%uB2A5%uC774%20%uC81C%uACF5%uB410%uB2E4.%0A%0A%uC5B4%uCC0C%uB410%uB4E0%20%uC4F0%uAE30%uB85C%uD558%uACE0%20%uB098%uC11C%20%uB9C9%uC0C1%20%uAC1C%uBC1C%uD558%uB824%uB2C8%20%uB9C9%uB9C9%uD588%uB294%uB370%2C%20%uBB38%uC11C%uD654%uAC00%20%uC798%20%uB418%uC5B4%uC788%uC9C0%20%uC54A%uC740%20%uC810%20%uB54C%uBB38%uC774%uC5C8%uB2E4.%20%uB2F9%uC5F0%uD558%uAC8C%uB3C4%20C%23%uCABD%20%uBB38%uC11C%uB294%20%uC644%uBCBD%uD588%uC9C0%uB9CC%20nodejs%uCABD%uC740%20%uBD88%uCE5C%uC808%uD55C%20API%20%uBB38%uC11C%20%uC678%uC5D0%uB294%20%uAC70%uC758%20%uBB50%20%uC124%uBA85%uC11C%uAC00%20%uC81C%uB300%uB85C%20%uC5C6%uC5C8%uB2E4.%20%uACF5%uC2DD%20%uC0AC%uC774%uD2B8%uC5D0%uC120%20%uCC3E%uC744%20%uC218%20%uC5C6%uC5B4%uC11C%20%uC774%uB9AC%uC800%uB9AC%20%uB4A4%uC838%uBD24%uB294%uB370%20%uC6D0%uD558%uB294%20%uB9CC%uD07C%uC758%20%uB531%20%uB4E4%uC5B4%uB9DE%uB294%20%uC608%uC2DC%uB294%20%uCC3E%uC744%20%uC218%20%uC5C6%uC5C8%uB2E4.%20%uC0DD%uAC01%uBCF4%uB2E4%20%uAD6C%uAE00%uC5D0%uC11C%20%uC601%uC5B4%uB85C%20%uCC3E%uC544%uB3C4%20%uC798%20%uC548%uCC3E%uC544%uC9C0%uB294%3F%20%uADF8%uB798%uC11C%20%uB0B4%uAC00%20%uC4F4%uB2E4.%0A%0A%uBB54%uAC00%20%uBA4B%uC9C0%uAC8C%20%uC124%uBA85%uD558%uACE0%20%uC2F6%uC740%uB370%2C%20%uC5B4%uCC28%uD53C%20%uC608%uC81C%20%uCF54%uB4DC%uB9CC%20%uBCFC%20%uAC83%20%uAC19%uC544%2C%20%uCF54%uB4DC%uB9CC%20%uCAD9%20%uBCF4%uC5EC%uC8FC%uB294%20%uC2DD%uC73C%uB85C%20%uC4F0%uACA0%uB2E4.%20%uC548%uB4DC%uB85C%uC774%uB4DC%uC640%20%uC544%uC774%uD3F0%uB9CC%20%uC6B0%uB9AC%uAC00%20%uD544%uC694%uD574%uC11C%20%uB450%uAC1C%uC758%20%uCF54%uB4DC%uB9CC%20%uC788%uB294%uB370%2C%20%uC6D0%uB798%uB294%20%uC5C4%uCCAD%20%uB2E4%uC591%uD55C%20%uD50C%uB7AB%uD3FC%uC744%20%uC9C0%uC6D0%uD55C%uB2E4.%0A%0A%23%23%20%uBA3C%uC800%2C%0A%0A%uB2F9%uC5F0%uD788%20%uC560%uC800%uC5D0%20%uAC00%uC785%uD558%uACE0%2C%20%uAD00%uB9AC%20%uD3EC%uD138%uC744%20%uC811%uC18D%uD558%uC5EC%20%uC54C%uB9BC%uD5C8%uBE0C%20%uC11C%uBE44%uC2A4%uB97C%20%uAD6C%uC131%uD574%uC57C%uD55C%uB2E4.%20%60%uC11C%uBE44%uC2A4%20%uBC84%uC2A4%60%20%uBA54%uB274%uC5D0%uC11C%20%uC54C%uB9BC%uD5C8%uBE0C%uB97C%20%uB9CC%uB4E4%20%uC218%20%uC788%uB2E4.%0A%0A%uADF8%uB9AC%uACE0%20%uB098%uBA74%20%60npm%60%uC73C%uB85C%20%60azure%60%20%uD328%uD0A4%uC9C0%uB97C%20%uC124%uCE58%uD55C%uB2E4.%0A%0A%09sudo%20npm%20install%20azure%0A%0A%uC774%uD6C4%2C%20%20%uC11C%uBE0C%uB77C%uC784%20%uD14D%uC2A4%uD2B8%20%uAC19%uC740%20%uD3B8%uC9D1%uAE30%uB97C%20%uCF1C%uC11C%20%uC791%uC5C5%uC744%20%uC2DC%uC791%uD55C%uB2E4.%20%uCCAB%20%uC904%uC5D0%20%uBA3C%uC800%20%uBAA8%uB4C8%uC744%20%uB85C%uB4DC%uD55C%uB2E4.%0A%0A%09var%20azure%20%3D%20require%28%27azure%27%29%3B%0A%0A%uADF8%uB9AC%uACE0%20%uC54C%uB9BC%20%uD5C8%uBE0C%uC640%20%uC5F0%uACB0%uC744%20%uD558%uACE0%2C%20%uBA85%uB839%uC744%20%uCC98%uB9AC%uD574%uC904%20%uAC1D%uCCB4%uB97C%20%uB9CC%uB4E4%uC5B4%uC57C%uD55C%uB2E4.%0A%0A%09var%20notificationHubService%20%3D%20azure.createNotificationHubService%28%27hubname%27%2C%27connectionstring%27%29%3B%0A%0A%uC800%uAE30%uC11C%20%uD30C%uB77C%uB9E4%uD130%uB85C%20%uB4E4%uC5B4%uAC00%uB294%20%60hubname%60%uACFC%20%60connectionstring%60%uC740%20%20Azure%20%uAD00%uB9AC%20%uD3EC%uD138%uC5D0%uC11C%20%uC54C%20%uC218%20%uC788%uB2E4.%0A%60hubname%60%uC740%20%60%uC11C%uBE44%uC2A4%20%uD5C8%uBE0C%60%uC5D0%uC11C%20%uAD6C%uC131%uD560%20%uB54C%20%uC785%uB825%uD55C%20%uC774%uB984%uC774%uACE0%2C%20%60connectionstring%60%uC740%20%uC54C%uB9BC%20%uD5C8%uBE0C%20%uB300%uC2DC%uBCF4%uB4DC%20%uC5B4%uB518%uAC00%uC5D0%20%uBCF4%uC774%uB294%20%60%uC5F0%uACB0%20%uBB38%uC790%uC5F4%20%uBCF4%uAE30%60%uB97C%20%uD074%uB9AD%uD558%uBA74%20%uC54C%20%uC218%20%uC788%uB2E4.%20%uADF8%20%uAE34%20%60%uC5F0%uACB0%20%uBB38%uC790%uC5F4%60%uC744%20%uBCF5%uBD99%uD558%uBA74%20%uB41C%uB2E4.%0A%0A%23%23%20%uD0DC%uADF8%uB780%3F%0A%0A%uC7A0%uAE50%20%uC54C%uC544%uC57C%uD560%20%uAC8C%20%uC788%uB2E4.%20%uC560%uC800%uB294%20%uD0DC%uADF8%uB97C%20%uC0AC%uC6A9%uD574%20%uD478%uC2DC%20%uC54C%uB9BC%uC758%20%uC2A4%uCF54%uD504%uB97C%20%uAD00%uB9AC%uD55C%uB2E4.%20%uBAA8%uB4E0%20%uC0AC%uC6A9%uC790%uC5D0%uAC8C%20%uBE0C%uB85C%uB4DC%uCE90%uC2A4%uD2B8%20%uD560%20%uC218%uB3C4%20%uC788%uC9C0%uB9CC%2C%20%uC5B4%uB5A8%20%uB54C%uB294%20%uB531%20%uD55C%20%uBA85%uD55C%uD0DC%uB9CC%20%uD558%uACE0%20%uC2F6%uC744%20%uB54C%uB3C4%20%uC788%uB2E4.%20%uC608%uB97C%uB4E4%uC5B4%20%uB098%uB294%20%uC544%uC774%uD3F0%uACFC%20%uC544%uC774%uD328%uB4DC%2C%20%uADF8%uB9AC%uACE0%20%uC548%uB4DC%uB85C%uC774%uB4DC%20%uD3F0%20%uC138%uAC1C%uB97C%20%uC4F0%uB294%uB370%2C%20%uB0B4%uAC8C%20%uC640%uC57C%uD560%20%uC54C%uB9BC%uC774%20%uC544%uC774%uD328%uB4DC%uB9CC%20%uC624%uAC70%uB098%20%uC544%uC774%uD3F0%uC5D0%uB9CC%20%uC624%uBA74%20%uC548%uB418%uACE0%203%uAC1C%uC758%20%uB514%uBC14%uC774%uC2A4%20%uBAA8%uB450%uC5D0%20%uC640%uC57C%uD558%uC9C0%20%uC54A%uACA0%uB294%uAC00.%20%uC774%uB7F4%uB54C%20%60tag%60%uB97C%20%60youngkyu%60%uB77C%uACE0%20%uC4F0%uACE0%2C%20%60youngkyu%60%uB780%20%uD0DC%uADF8%uC5D0%20%uD478%uC2DC%uB97C%20%uC3D8%uBA74%20%uBAA8%uB4E0%20%60youngkyu%60%uC758%20%uB514%uBC14%uC774%uC2A4%uC5D0%20%uD478%uC2DC%20%uC54C%uB9BC%uC774%20%uB3C4%uCC29%uD55C%uB2E4.%0A%0A%23%23%20%uC11C%uBE44%uC2A4%20%uBC84%uC2A4%20%uC54C%uB9BC%20%uD5C8%uBE0C%uC5D0%20%uC2DC%uADF8%uB2C8%uCC98%uC640%20API%20%uD0A4%20%uB4F1%uB85D%0A%0A%uC54C%uB9BC%20%uD5C8%uBE0C%uC5D0%20%60%uAD6C%uC131%60%uC744%20%uD074%uB9AD%uD558%uBA74%20APNS%uC640%20GCM%uC758%20%uC2DC%uADF8%uB2C8%uCC98%uC640%20%uD0A4%uB97C%20%uB4F1%uB85D%uD558%uB294%20%uACF3%uC774%20%uC788%uB2E4.%20%uC5EC%uAE30%uC5D0%20%uD574%uB2F9%20%uD30C%uC77C%uACFC%20%uD0A4%uB97C%20%uC62C%uB824%uC918%uC57C%20%uC560%uC800%uC5D0%uC11C%20%uCC98%uB9AC%uD560%20%uC218%20%uC788%uB294%20%uD658%uACBD%uC774%20%uC870%uC131%uB41C%uB2E4.%0A%0A%23%23%20%uB514%uBC14%uC774%uC2A4%20%uB4F1%uB85D%uD558%uAE30%0A%0A%uBA3C%uC800%20%uB514%uBC14%uC774%uC2A4%uB97C%20%uB4F1%uB85D%uD574%uC57C%uD55C%uB2E4.%20%uC774%uB54C%20%60youngkyu%60%uB85C%20%uC608%uC2DC%uB97C%20%uB4E4%uC5C8%uB358%20%60tag%60%uB3C4%20%uC124%uC815%uD55C%uB2E4.%20%uC798%20%uCD94%uC0C1%uD654%uB418%uC5B4%uC788%uC5B4%uC11C%2C%20%uD478%uC2DC%uC54C%uB9BC%uC758%20%uACFC%uC815%uC744%20%uC815%uD655%uD788%20%uC774%uD574%uD558%uC9C0%20%uBABB%uD574%uB3C4%20%uC6D0%uD65C%uD788%20%uC0AC%uC6A9%uD560%20%uC218%20%uC788%uB2E4.%20%uC774%20%uACFC%uC815%uC5D0%20%uB300%uD55C%20%uC598%uAE30%uB294%20%uB2E4%uC74C%uC5D0%20%uD3EC%uC2A4%uD305%uD558%uACA0%uB2E4.%0A%0A%23%23%23%20%uC544%uC774%uD3F0%0A%0A%uBA3C%uC800%20%uC544%uC774%uD3F0%uC758%20%60deviceToken%60%uC774%20%uD544%uC694%uD558%uB2E4.%20%uC774%uAC74%20%uC560%uC800%uC640%20%uAD00%uB828%uC774%20%uC5C6%uC73C%uBBC0%uB85C%20%uC5EC%uAE30%uC11C%20%uC124%uBA85%uD558%uC9C0%20%uC54A%uB294%uB2E4.%0A%0A%20%20%20%20notificationHubService.apns%0A%09%09.createNativeRegistration%28deviceToken%2Ctags%2Cnull%2Cfunction%28error%29%7B%0A%09%09//%20To%20do%0A%09%7D%29%3B%0A%0A%uC5EC%uAE30%uC11C%20%uD30C%uB77C%uB9E4%uD130%uC5D0%20%60deviceToken%60%uC740%20%uBC1B%uC544%uC628%20%uD1A0%uD070%uC744%20%uC9D1%uC5B4%uB123%uACE0%2C%20%60tags%60%uC5D0%uB294%20%uBC30%uC5F4%uC5D0%20%uB2F4%uC740%20%uD0DC%uADF8%uB4E4%uC744%20%uC9D1%uC5B4%uB123%uB294%uB2E4.%20%uC138%uBC88%uC9F8%20%60null%60%uC740%20%60option%60%uC73C%uB85C%20%uC911%uC694%uD558%uC9C0%20%uC54A%uB2E4.%20%uC81C%uB300%uB85C%20%uC124%uBA85%uB3C4%20%uC548%uB418%uC788%uC5B4%uC11C%20%uC544%uC9C1%20%uAE30%uB2A5%uC774%20%uD06C%uAC8C%uB294%20%uC5C6%uB294%20%uB4EF%20%uD558%uB2E4.%20%uB9C8%uC9C0%uB9C9%20%60callback%60%uC5D0%20%uC774%uD6C4%20%uD560%20%uC791%uC5C5%20%uD568%uC218%uB97C%20%uB123%uB294%uB2E4.%0A%0A%uC544%uB798%uB294%20%uB0B4%uAC00%20%uC4F4%20%uCF54%uB4DC%20%uC77C%uBD80%uB2E4.%0A%0A%09notificationHubService.gcm%0A%09%09.createNativeRegistration%28deviceToken%2C%5B%22user%22%2C%22user.%22+userId%5D%2Cnull%2Cfunction%28error%29%7B%0A%09%20%20%20%20if%28%21error%29%20%7B%0A%20%20%20%20%0A%09%20%20%20%20%7D%0A%09%7D%29%3B%0A%0A%uD0DC%uADF8%uC5D0%20%60%5B%22user%22%2C%22user.%22+userId%5D%60%uAC00%20%uBCF4%uC774%uB294%uAC00.%20%uC774%uB807%uAC8C%20%uC801%uAC8C%uB418%uBA74%20%uC774%uD6C4%20%60%22user%22%60%uB77C%uB294%20%uD0DC%uADF8%uC5D0%20%uD478%uC2DC%uB97C%20%uB54C%uB9AC%uBA74%20%uBAA8%uB4E0%20%60%22user%22%60%uD0DC%uADF8%uB97C%20%uAC00%uC9C4%20%uB514%uBC14%uC774%uC2A4%uAC00%20%09%uBC1B%uAC8C%20%uB41C%uB2E4.%20%uADF8%uB9AC%uACE0%20%60%22user.12%22%60%uB77C%uACE0%20%uD558%uBA74%2012%uBC88%20%uC720%uC800%20%uC544%uC774%uB514%uC758%20%uC0AC%uC6A9%uC790%uB9CC%20%uBC1B%uAC8C%20%uB418%uB294%20%uC2DD%uC774%uB2E4.%0A%0A%23%23%23%20%uC548%uB4DC%uB85C%uC774%uB4DC%0A%0A%uB9C8%uCC2C%uAC00%uC9C0%uB85C%20%60deviceToken%60%uC778%20%60gcmRegistrationId%60%uAC00%20%uBA3C%uC800%20%uD544%uC694%uD558%uB2E4.%0A%0A%09notificationHubService.gcm%0A%09%09.createNativeRegistration%28gcmRegistrationId%2Ctags%2Cnull%2Cfunction%28error%29%7B%0A%09%09//%20To%20do%0A%09%7D%29%3B%0A%0A%uC704%uC640%20%uB611%uAC19%uB2E4.%20%60gcm%60%uB9CC%20%uBE7C%uACE0.%0A%0A%23%23%20%uD478%uC2DC%20%uBCF4%uB0B4%uAE30%0A%0A%uB4F1%uB85D%uC774%20%uB05D%uB098%uACE0%20%uB098%uBA74%2C%20%uC544%uB798%20%uCF54%uB4DC%uB97C%20%uC2E4%uD589%uD574%uBCF8%uB2E4.%0A%0A%09var%20payload%20%3D%20%7B%0A%09%20%20%20%20alert%20%3A%20%22hello%20noti%21%22%2C%0A%09%20%20%20%20sound%20%3A%20%22default%22%0A%09%7D%0A%09notificationHubService.apns.send%28null%2Cpayload%2Cfunction%28error%29%7B%7D%29%3B%0A%0A%uB775%uB625.%20%uD478%uC2DC%uAC00%20%uC654%uB294%uAC00%3F%20%60payload%60%uC5D0%20%60sound%60%uAC00%20%uC18C%uB9AC%uB97C%20%uB0B4%uB294%20%uC5ED%uD560%uC744%20%uD558%uACE0%2C%20%60alert%60%uC774%20%uAE00%uC744%20%uD45C%uD604%uD55C%uB2E4.%20%uADF8%uB9AC%uACE0%20%60send%28%29%60%uC758%20%uCCAB%uBC88%uC9F8%20%uC778%uC790%uB294%20%60tag%60%uC778%uB370%2C%20%60null%60%uC774%uBA74%20%uBE0C%uB85C%uB4DC%uCE90%uC2A4%uD2B8%uB2E4.%20%uBAA8%uB4E0%20%uB4F1%uB85D%uB41C%20%uC544%uC774%uD3F0/IOS%20%uB514%uBC14%uC774%uC2A4%uC5D0%20%uC804%uC1A1%uD55C%uB2E4.%20%uB530%uB77C%uC11C%20%uBC1B%uAC8C%20%uB418%uB294%20%uAC83%uC774%uB2E4.%0A%0A%09var%20payload%20%3D%20%7B%0A%09%20%20%20%20alert%20%3A%20%22hello%20users%21%22%2C%0A%09%20%20%20%20sound%20%3A%20%22default%22%0A%09%7D%0A%09notificationHubService.apns.send%28%22user%22%2Cpayload%2Cfunction%28error%29%7B%7D%29%3B%0A%0A%uC704%uC640%20%uAC19%uC774%20%uBCF4%uB0B4%uBA74%20%60user%60%uD0DC%uADF8%uB97C%20%uAC00%uC9C4%20%uB514%uBC14%uC774%uC2A4%uB9CC%20%uBC1B%uAC8C%20%uB41C%uB2E4.%20%uB9CC%uC57D%20%uD0DC%uADF8%uB97C%20%uC5EC%uB7EC%uAC1C%20%uC9C0%uC815%uD558%uACE0%20%uC2F6%uB2E4%uBA74%2C%20%uC544%uB798%uC640%20%uAC19%uC740%20%uADDC%uCE59%uC744%20%uC4F0%uBA74%20%uB41C%uB2E4.%0A%0A-%20%uC5EC%uB7EC%20%uD0DC%uADF8%uB4E4%uC5D0%20%3A%20%22user.12%7C%7Cuser.23%7C%7Cuser.24%22%0A-%20%uB450%20%uD0DC%uADF8%20%uB2E4%20%uAC00%uC9C0%uACE0%20%uC788%uB294%20%3A%20%22user%7C%7Cpost.15%22%0A%0A%uAC04%uB2E8%uD558%uB2E4.%0A%0A%23%23%20%uB05D%21%0A%0A%uC544%uC8FC%20%uAC04%uB2E8%uD558%uC9C0%uB9CC%20%uB9CE%uC774%20%uB2F9%uD669%uC2A4%uB7EC%uC6E0%uB2E4.%20%uC12C%uC138%uD788%20%uC54C%uB824%uC8FC%uB294%20%uD29C%uD1A0%uB9AC%uC5BC%20%uD558%uB098%20%uC5C6%uC774%20%uACE0%uC791%20API%uBB38%uC11C%20%uB538%uB791%20%uD558%uB098%uBCF4%uACE0%20%uC2DC%uC791%uD588%uC73C%uB2C8.%20%uC5B4%uCA0C%uB4E0%20%uC27D%uB2E4.%20%uADF8%uB9AC%uACE0%20%uB9E4%uC6B0%20%uAC15%uB825%uD558%uB2E4.%20%uD478%uC2DC%20%uC2DC%uC2A4%uD15C%uC744%20%uC9C1%uC811%20%uB9CC%uB4E4%uBA74%20%uB354%20%uC800%uB834%uD588%uC744%uC9C0%20%uBAA8%uB974%uC9C0%uB9CC%20%28%uC2E4%uC740%20%uADF8%uB807%uC9C0%uB3C4%20%uC54A%uC744%20%uAC70%uB2E4%29%20%uAE30%uD68C%20%uBE44%uC6A9%uC774%20%uC0C1%uB2F9%uD788%20%uB192%uAC8C%uB41C%uB2E4.%20%uC11C%uBE44%uC2A4%uB97C%20%uB9CC%uB4DC%uB294%20%uD68C%uC0AC%uB2C8%20%uC11C%uBE44%uC2A4%uC5D0%20%uC9D1%uC911%uD574%uC57C%uD558%uB294%uB370%20%uB9D0%uC774%uB2E4.%20API%20%uBB38%uC11C%uB294%20%uC544%uB798%20%uC8FC%uC18C%uB97C%20%uB20C%uB7EC%20%uBCFC%20%uC218%20%uC788%uB2E4.%20%uB2E4%uC74C%20%uD3EC%uC2A4%uD2B8%uC5D0%uC11C%uB294%20%uCD08%uAE30%uC5D0%20%uC124%uC815%uD55C%20%60tag%60%uC774%uC678%uC758%20%60tag%60%uB4E4%uC744%20%uCD94%uAC00%uD574%uBCF4%uC790.%0A%0Ahttp%3A//dl.windowsazure.com/nodedocs/NotificationHubService.html