APNS 따라하기 시리즈 (프로바이더 구성하기)

프로바이더에서의 개발 개요

두번째 시리즈인 프로바이더에서 개발 방법에 대해서 알아보겠습니다.
이미 인증서 만들기에서 제작한 apns.pem 인증서 파일을 FTP 프로그램을 이용해 임의의 경로로 업로드 합니다.
보통 웹루트내에 파일을 올리면 주소나 파일명만 알면 바로 다운로드 받아갈 수 있기때문에 가급적 웹루트가 아닌 곳에 올려주시기 바랍니다.

이 인증서로 APNS 서버와의 통신을 통해 인증을 받고 인증을 받은 상태에서 Payload에 애플이 요구하는 텍스트를 채워 json데이터를 APNS서버로 전송해주기만 하면 됩니다. 이런 부분을 손쉽게 접근할 수 있도록 도와주는 친구들을 아래에서 몇 명 소개시켜드리겠습니다.

그래도 어떤 원리인지는 간단하게 알고 넘어가야겠죠?

 

Payload 작성 양식

다음의 애플문서를 보면 아주아주 자세하게 나와있습니다. 영어가 되시는 분은 애플에서 제공하는 원문을 보시는게 더 좋을 것 같네요!
기본적으로 Payload는 JSON 형식으로 전달되며 형식은 다음과 같습니다.

여기서 aps 키값은 Dictionary 형태로 만들어지며 각각의 키들은 다음과 같은 역할을 합니다.

  • alert : 스트링 혹은 딕셔너리 형태로 값이 들어갈 수 있으며 스트링으로 할 경우 보내고자하는 메시지를 적어 넣어주시면 됩니다.
    • body : 전달할 내용을 입력합니다.
    • action-loc-key : LocalizedString의 키값을 참조해 AlertView의 View Detail이라는 버튼을 언어에 맞게 변경시켜줍니다.
    • loc-key : LocalizedString의 키값을 참조해 내용을 채워줍니다.
  • badge : 배지의 숫자를 입력합니다.
  • acme1 or acme2 : 커스터마이징 변수값으로 임의의 문자열로 키와 값을 만들어 스트링 혹은 배열의 형태로 전달 할 수 있습니다.

PHP 테스트 코드:

아래는 EasyAPNS가 아닌 막코딩으로 전송테스트를 해보았습니다.
상단에 deviceToken정보만 제대로 입력해주면 해당 디바이스로 메시지가 잘 전송되는 것을 확인했습니다.

 

개발에 사용할 오픈소스

위와 같이 Github 및 검색을 해보시면 아시겠지만 다양한 개발자들이 만들어 놓은 오픈소스가 많이 있습니다.
가장 최근에 등록된 PHP_APN의 경우 API를 기능별로 세분화시켜놓아 관리기능을 별도로 제작할때 좋지 않을까 싶습니다.
하지만 저는 PHP로 개발코자 EasyAPNS를 이용해서 개발을 시작하다가 일이 커져 지금은

별도로 개발해 안드로이드까지 통합발송이 되도록 만들어 사용하고 있습니다.
GCM(Google Cloud Message)에 대한 정보는 다음에 시간날때 게재하도록 하겠습니다.

 

관련 참고 자료:

Why was my device token rejected by Apple?

Local and Push Notification Programming Guide

How to build an Apple Push Notification provider server (tutorial)

 

Published by

안반장

Web과 App 개발을 하고 있으며 최근 워드프레스에 관심이 많아져 네이버 카페 워드프레스 홈페이지의 TF팀으로 활동 중 입니다.개인적으로는 안반장의 개발 노트라는 블로그를 운영하면서 개발의 즐거움과 고충들을 차곡차곡 담아가고 있습니다.

  • holyreign

    이전 따라하기에는 apns.pem 로 만드셨던데 파일명 바꾼건가요?
    php 코드 상에 이전에 만들었더 pem 비밀번호 같은건 없어도 되나요?

    • 파일명은 맘대로 변경하셔도 되요… 다만 php에서 인증서 경로 설정할때 변경하신 이름으로 동일하게 설정만 하시면 됩니다. ^^
      그리고 해당 비밀번호는 PHP단에서는 필요없습니다.

  • Guest

    GCM 처럼 api키 형식이 아니라 인증서 로드 식인가요?

    짧은 지식으로 사용을 편하게 하기 위하여 클래스화 하였습니다.

    pem_path = $path;

    if($mode == 1) {

    $this->mode = ‘real’;

    $this->server_url = $this->real_server_url;

    }

    else {

    $this->mode = ‘test’;

    $this->server_url = $this->test_server_url;

    }

    }

    # 발송처리

    public function send($token, $message=”, $badge=1, $sound=”) {

    $pem_path = $this->pem_path;

    $server_url = $this->server_url;

    if(!$pem_path) die(‘서버 인증서가 지정되지 않았습니다.’);

    if(!is_file($pem_path)) die(‘지정된 인증서 파일이 존재하지 않습니다.’);

    if(!$token) die(‘토큰값이 지정되지 않았습니다.’);

    if(!$message) die(‘메시지 내용이 없습니다.’);

    # 전달값 조합

    $body = array();

    $body[‘aps’] = array(‘alert’=>$message);

    # 사용자 지정 뱃지나 사운드가 있을 경우 설정

    if($badge) $body[‘aps’][‘badge’] = $badge;

    if($sound) $body[‘aps’][‘sound’] = $sound;

    # 애플 APNS서버와 인증서를 이용해 소켓 통신

    $ctx = stream_context_create();

    stream_context_set_option($ctx, ‘ssl’, ‘local_cert’, $pem_path);

    $fp = stream_socket_client($server_url, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);

    if(!$fp) {

    return “Failed to connect $err $errstrn”;

    }

    else {

    echo “Connection OKn”;

    }

    // 배열을 json으로 변경

    $payload = json_encode($body);

    $msg = chr(0) . pack(“n”,32) . pack(‘H*’, str_replace(‘ ‘, ”, $deviceToken)) . pack(“n”,strlen($payload)) . $payload;

    print “Sending message :” . $payload . “n”;

    fwrite($fp, $msg);

    fclose($fp);

    }

    # 테스트

    public function test() {

    $output = array();

    $output[‘mode’] = $this->mode;

    $output[‘pem_path’] = $this->pem_path;

    $output[‘server_url’] = $this->server_url;

    return $output;

    }

    }

  • Terrorboy

    gcm 처럼 api방식이 아니라 인증서 방식인가 보내요^^
    좋은 정보 감사합니다.

    사용상 편의를 위하여 다음처럼 작업 하여 사용 하겠습니다 ^^

    pem_path = $path;

    if($mode == 1) {

    $this->mode = ‘real’;

    $this->server_url = $this->real_server_url;

    }

    else {

    $this->mode = ‘test’;

    $this->server_url = $this->test_server_url;

    }

    }

    # 발송처리

    public function send($token, $message=”, $badge=1, $sound=”) {

    $pem_path = $this->pem_path;

    $server_url = $this->server_url;

    if(!$pem_path) die(‘서버 인증서가 지정되지 않았습니다.’);

    if(!is_file($pem_path)) die(‘지정된 인증서 파일이 존재하지 않습니다.’);

    if(!$token) die(‘토큰값이 지정되지 않았습니다.’);

    if(!$message) die(‘메시지 내용이 없습니다.’);

    # 전달값 조합

    $body = array();

    $body[‘aps’] = array(‘alert’=>$message);

    # 사용자 지정 뱃지나 사운드가 있을 경우 설정

    if($badge) $body[‘aps’][‘badge’] = $badge;

    if($sound) $body[‘aps’][‘sound’] = $sound;

    # 애플 APNS서버와 인증서를 이용해 소켓 통신

    $ctx = stream_context_create();

    stream_context_set_option($ctx, ‘ssl’, ‘local_cert’, $pem_path);

    $fp = stream_socket_client($server_url, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);

    if(!$fp) {

    return “Failed to connect $err $errstrn”;

    }

    else {

    echo “Connection OKn”;

    }

    // 배열을 json으로 변경

    $payload = json_encode($body);

    $msg = chr(0) . pack(“n”,32) . pack(‘H*’, str_replace(‘ ‘, ”, $deviceToken)) . pack(“n”,strlen($payload)) . $payload;

    print “Sending message :” . $payload . “n”;

    fwrite($fp, $msg);

    fclose($fp);

    }

    # 테스트

    public function test() {

    $output = array();

    $output[‘mode’] = $this->mode;

    $output[‘pem_path’] = $this->pem_path;

    $output[‘server_url’] = $this->server_url;

    return $output;

    }

    }

    • Terrorboy

      소스가 붙여 넣어도 정상으로 안들어 가네요 ㅠ.ㅠ;