iOS 만 서비스 할때는 그냥 대충 php + cron 으로 push 를 돌렸었는데,
이게 백명 단위만 되어도 delay 문제가 생겨서... async 방식으로 언젠가 도입을 해야지.. 생각만 했었다.
이번에 안드로이드때문에 하게 되었으니.. 겸사겸사...
GCM 으로 iOS 도 사용할 수 있는 방법이 있다는건 봤지만,, 클라를 수정해야 했고..
이미 있는 앱도 같이 적용 + 클라 더 손대기가 귀찮아서 서버쪽을 잘 만들어보기로 했다.
APNS
우선 APNS 는 pyapns 라는 녀석으로 쉽게 asynchronous 한 push 를 구현가능하다.
뭐.. https://github.com/samuraisam/pyapns 여기 들어가면 잘 나와있긴 한데..
$ sudo easy_install pyapns
로 설치한다. 의존성이 걸린 twistd 도 같이 설치된다.
$ twistd -r epoll web --class=pyapns.server.APNSServer --port=7077
로 twistd 서비스를 실행할 수 있다. 잘되는지 확인...
그리고 실행해보고 service_identity 모듈이 없다는 경고가 뜨면 설치해주자.
$ sudo pip install service_identity
pyapns 서버를 구축한 후 python 에서
import pyapns
pem_path = 'path_to_push_pem'
pyapns.configure({'HOST': 'http://localhost:7077/'})
pyapns.provision('com.example.appid', pem_path, 'production') #sandbox
push = {'aps': {'alert':'푸시 테스트', 'sound':'default'}}
pyapns.notify('com.example.appid', '### push token ###', push, async=True)
이렇게 사용하면 된다.
GCM
GCM 은 주로 node.js 로 했던 듯 하나... 난 시스템을 통일시키고 싶었다.
찾아보니, 위 pyapns 처럼 로컬에 서버를 열어두고 request를 보내면 되는 방식의 GoCM 이라는 라이브러리가 있었다.
Golang 으로 짜져 있음.
자.. 우선 Go 가 설치되어 있지 않다면 설치하고... [Mac / Ubuntu] Go (golang) 설치하기
$ go get github.com/Flyclops/GoCM
$ go install github.com/Flyclops/GoCM
을 하면 $GOPATH/bin/ 에 GoCM 이 생성되어 있다.
이걸 ./GoCM --apikey ##### 요렇게 실행하면 됨.
GCM 은 인증서가 필요없고 sandbox / production 구분이 없어서 더 간편하다.
간단히 POST request 만 구현하면 어떻게든 가능하지만, 난 requests 라이브러리 사용을 선호함.
import requests, json
GCM_SEND_ENDPOINT = 'http://localhost:5601/gcm/send'
token = '### token ###'
msg = {'title': '[title]', 'message': 'message'}
requests.post(GCM_SEND_ENDPOINT, data={'tokens': [token], 'payload': json.dumps(msg)})
Daemonize
위 방법대로 하면 이제 APNS / GCM 을 둘다 이용할 수 있게 되지만, 각각 웹서버를 하나 돌려야 해서 귀찮다.
당장은 그냥 쓴다고 해도 재부팅을 한다거나.. 프로세스 유지해주기가 귀찮으니까 데몬으로 만들어버리자.
pyapns 는 python-twistd :: daemon 으로 만들기
GoCM 은 GoCM :: daemon 으로 만들기
글을 각각 참고하면 된다.
Feedback / Report
APNS / GCM 각각 삭제되었거나 더이상 사용되지 않는 token 에 대한 feedback 을 제공해준다.
APNS
pyapns.feedback('com.example.appid') 를 호출하면
[(timestamp, token), ]
형태로 반환해준다.
token 으로 uninstalled 처리를 해주면 됨.
GCM
canonicals / notregistered 두가지 feedback 이 존재한다.
전자는 token 이 변경되었을 경우(인 것 같다. 사실 레퍼런스를 안봐서..), 후자는 앱이 삭제된 경우.
이건 그냥 GoCM README 를 보자.
Fin
드디어 Python 만을 사용하여(Go 는 컴파일 한번 하고 끝이니 논외), 하나의 시스템만으로 Asynchronous APNS / GCM 둘다 사용할 수 있게 되었다.
여기선 다루지 않았지만, 동일한 DB에 os 구분하여 token 을 저장하고, os 를 알아서 구분해서 메세지를 보내도록 하면 좀 더 관리가 쉽다.
분명히 두 OS를 같이 서비스하는 사람/업체가 많은데 내가 못찾는건지 다른 방법이 있는건지...
생각처럼 깔끔하고 쉬운 방법이 눈에 안보이네.. 흑