티스토리 뷰

시작하기 전에...
Tizen 공부를 시작하며 에도 썼듯이 혼자 공부하며 서술합니다.
실제 사실과 다를 수도 있고, 보이는 대로 사견을 서술할 예정입니다.
잘못되었다 싶은 부분은 댓글이나, 메일로 알려주세요.
Tizen 2.4 Native 기준으로 포스팅 합니다.


Tizen Push에 대해 포스팅 해보겠습니다.

Push는 단순 API 사용으로만 보면 매우 간단하면서도,
심도있게 Service를 설계하다 보면 굉장히 까다롭고 고려 사항이 많아지는 어려운 기능입니다.

따라서 포스팅을 나누어서 해보겠습니다.

1. 시작하기 (UI App에서 단순 Push 수신)
2. 설계하기 (서버 Flow & App Flow)
3. 구현하기 (제대로 설계 되었지만 그래도 내용은 간단한 Sample)

본 Post는 1. 시작하기 (UI App에서 단순 Push 수신) 입니다.

※서론에 적었듯이 사견을 서술할 것이며, Push는 어려우므로 제가 떠드는 게 100% 사실이 아닐 수도 있습니다.
(보시다가 의견이나 조언을 주셔도 좋습니다.)


Push란...
이름 자체에서도 감이 오듯이, App이 특별히 서버를 Watching 하지 않아도,
심지어 App이 종료된 상태에서도 메시지가 밀려 들어오고 App이 실행되는 등을 할 수 있습니다.

물론 아랫 단으로 내려가고 내려가다 보면 Network Layer에서는 Push가 될 수가 없습니다.
어딘가에서는 주기적으로 연결을 유지하고 있겠지요.
그렇지만 Push의 장점은 Application 관점에서 항상 떠 있지 않아도 필요할 때 Launch될 수 있다는 데에 있습니다.

모바일 단말은 메모리도, 배터리도 비교적 제약적이기 때문에 Desktop 처럼 Process가 상주하면서
동작을 수행하기 보다는 필요할 때만 Activate되어 잠깐 잠깐 수행해주는 Design이 일반적으로 요구되기 때문입니다.


Tizen Push Service를 사용하기 위해서는 Server App ID와 App Secret이 필요합니다.

일반적으로, Open API를 제공하는 Server들은 대부분 이 두 값을 별도로 개발자에게 발급합니다.
서버를 사용하기 위한 ID, Password 라고 생각하시면 됩니다.
그냥 Open 해놓을 경우 무분별한 접근으로 Server에 부하가 걸릴 수 있으므로,
미리 사용처와 사용 빈도 등을 확인하고 승인 후 App ID, App Secret을 발급함으로써
Capacity를 유지하기 위함으로 생각됩니다.

대부분은 웹사이트에서 입력 Form을 채우고 바로 발급 받거나 하는 자동화 설계가 되어있는 반면,
Tizen은 아쉽게도 구식(?) 입니다.
Push API Tutorial 을 참고하면 push.tizen@samsung.com 으로 입력 form에 맞춰 메일을 보내라고 되어 있습니다.
"
Table: Request form details"라고 적혀있는 표를 복사해 입력 란을 채워 메일로 보내면 됩니다.

※ 최근(2019년) 확인 결과 사이트에 입력 창이 별도로 생겼네요.
https://developer.tizen.org/webform/request-permission-tizen-push-service
에서 직접 입력 후 바로 Submit 할 수 있습니다.


1. Push App ID, App Secret 발급 신청하기


e-mail에서 Field를 채워 push.tizen@samsung.com으로 보냅니다.

창 하단 Submit 버튼 클릭


3일만에 답신이 왔습니다. 주말에 보낸거니, 2 working day만에 온 셈인데요.
기대(?)보다 빨리 회신이 와서 놀랐습니다.


2. Push 수신 App 만들기

Tizen SDK에서 Mobile로 UI Basic Application을 한개 생성합니다.

 1) Manifest에 "http://tizen.org/privilege/push" privilege가 선언되어 있어야 합니다.


 2) src/<소스파일>.c 에서 push-service.h를 include 시킵니다.

추가로, Push App ID를 define으로 넣고, app_data_s structure에 push handle도 넣겠습니다.

#include <push-service.h> #define PUSH_APP_ID "input_your_app_id" typedef struct appdata { Evas_Object *win; Evas_Object *conform; Evas_Object *label; push_service_connection_h push_conn; // push handle } appdata_s;


3) app_create() 에서 push_service_connect()를 호출합니다.

static bool
app_create(void *data)
{
	appdata_s *ad = data;
	create_base_gui(ad);

	int ret = push_service_connect(PUSH_APP_ID, _state_cb, _noti_cb, ad, &ad->push_conn);
	if (ret)
		LOGE("push connect error(%d) : %s", ret, get_error_message(ret));

	return true;
}

push_service_connect()는 Tizen Platform의 Push daemon과 단순히 IPC로 연결되는 과정입니다.

_state_cb는 단말의 Push 서버 등록 여부를 확인할 수 있습니다.

_noti_cb는 push 알림이 전달되는 Callback입니다. _state_cb이 registered로 온 다음 부터 메시지를 수신할 수 있습니다.

LOGE 등의 사용 법은 Dlog 사용법 을 참고하시기 바랍니다.


4) state callback을 작성합니다.

static void
_state_cb(push_service_state_e state, const char *err, void *user_data)
{
	appdata_s *ad = user_data;

	switch (state) {
	case PUSH_SERVICE_STATE_UNREGISTERED:
		LOGI("unregistered state, try register");
		push_service_register(ad->push_conn, _result_cb, ad);
		break;

	case PUSH_SERVICE_STATE_REGISTERED:
		LOGI("registered");
		char *reg_id = NULL;
		push_service_get_registration_id(ad->push_conn, &(reg_id));
		LOGD("reg ID : %s", reg_id);
		free(reg_id);
		push_service_request_unread_notification(ad->push_conn);
		break;

	case PUSH_SERVICE_STATE_ERROR:
		LOGE("state error");
		break;

	default:
		LOGW("state unknown");
		break;
	}
}

Push State 는 3종류로 볼 수 있습니다.

1. PUSH_SERVICE_STATE_UNREGISTERED
   -> 단말에서 App 수행이 처음일 때.
   -> App이 오랫동안 수행되지 않았거나 하는 등의 이유로 서버 정책에 의해 알아서 UNREGISTERED가 되었을 때 입니다.
   => 이 때는 push_service_register()를 호출 해 Registration을 해줘야 합니다.

2. PUSH_SERVICE_STATE_REGISTERED
   -> 단말이 Push 서버에 등록된 상태일 때 입니다.
   -> 이 때는 push_service_get_registration_id로 registration ID를 가져올 수 있습니다.
   => registeration ID는 단말에 Push를 보낼 수 있는 중요한 Key 값으로 함부로 Log를 찍으면 안되지만, 이건 예제이므로 Log로 확인하도록 하겠습니다.

3. PUSH_SERVICE_STATE_ERROR
   -> 그 외 Connection을 유지할 수 없는 상황이 생겼을 때 입니다.
   -> 예를 들어 동일 App ID를 사용해서 다른 App이 Push Connect 시도 시, 기존 연결된 App은 Error State로 전환됩니다.


5) push_service_register()를 위한 result callback을 작성합니다.

static void _result_cb(push_service_result_e result, const char *msg, void *user_data)
{
	LOGI("register result callback (%d) : %s", (int)result, msg);
}

특별한 내용은 실제 서비스 구현 시 Error 핸들링에서 필요합니다.
이건 예제이므로 Log만 찍고 넘어가겠습니다.
register가 Success 되면 result도 PUSH_SERVICE_RESULT_SUCCESS가 넘어 오지만,
직후에 state callback으로도 registered 상태가 전달됩니다.


6) notification callback을 작성합니다.

static void _noti_cb(push_service_notification_h noti, void *user_data)
{
	char *data = NULL;
	char *msg = NULL;

	push_service_get_notification_data(noti, &data);
	push_service_get_n한otification_message(noti, &msg);

	LOGI("noti data : %s", data);
	LOGI("noti msg  : %s", msg);

	appdata_s *ad = user_data;
	char buf[4096] = {0, };
	snprintf(buf, 4096, "<align=center>Noti Data : %s</br> \
		Noti Msg : %s</align>", data, msg);
	elm_object_text_set(ad->label, buf);

	free(data);
	free(msg);
}

Push Notification은 push_service_notification_h 형태로 들어 옵니다.
Push API를 써서 Notification field에 있는 data를 꺼내야합니다.

본 예제에서는 message와 data를 꺼내서 화면의 Label에 표시하도록 해보겠습니다..
Service 개발자가 자유롭게 이용할 수 있는 Field는 data Field입니다.


3. 간단한 Push 메시지 발신 Test

Chrome 브라우져의 App 중에서 DHC라는 Rest API 사용하기 편하게 해주는 App을 이용해 보겠습니다.
(※다음 포스팅에서 Curl로 직접 하는 법도 소개하겠습니다.)


1) Chrome Browser에서 DHC 설치

Chrome의 좌측 상단에 Apps를 클릭 합니다.

Web Store로 이동

DHC를 검색해 설치합니다.
(무료이나, 하루 Request 횟수 제한이 있습니다. 간단한 Test를 하기에는 좋습니다.)


2) 아까 작성한 App을 실행해 Registration ID 확인

위에서 정의했던 예제 소스를 그대로 따라하면 이런 Log를 확인할 수 있습니다.

매우 긴 Registration ID를 획득할 수 있는데요,
실제 배포될 App에서는 이런 값을 Log 등 누군가에 노출하는 행위는 지양해야 합니다.
여기서는 Test를 위해 출력했습니다.

해당 값을 복사해 놓습니다.
그리고 값의 첫 두글자 숫자를 확인한 후 Push Server Tutorial
Table: RQM servers 표에서 서버 URL을 확인 합니다.
지역 별 Push 서버를 전달해줄 서버가 다르기 때문입니다.


3) DHC에서 Push 메시지 발신

URL을 HTTPS / POST로 지정 후 2)에서 확인한 RQM 서버 URL을 넣습니다.

HEADERS에 + 버튼을 눌러 App ID와 App Secret을 넣습니다.
※이 때, appID, appSecret 이 두 Key Name이 틀리거나 대소문자가 틀리면 안됩니다.

Json으로 Push Server Tutorial 에 나오는 여러 key / value들을 추가할 수 있습니다.
우선 registration ID와 몇몇 Field만 추가하겠습니다.
※여기서도 Key 값들의 대소문자에 유의하세요

{
   "regID": "input_your_reg_id",
   "requestID": "001",
   "message": "action=LAUNCH",
   "appData": "Hi push app"
}

Send 버튼을 누른 후 하단 Result 창이 200 OK 인지 우선 확인하시고,
그 옆에 BODY 부분에 return 받은 json result에도 특별히 Error라고 적힌 메시지가 없으면 성공입니다.

※message Field의 "action=LAUNCH"는 protocol에 정의된 옵션입니다. (푸시 도착 시 App을 실행시킨다는 의미 입니다.)


4) App의 결과 확인

에뮬레이터에서 정상 수신됨을 확인할 수 있습니다.

※간혹 메시지 발신은 성공인데, App에 오지 않는 경우
단말 또는 Emulator를 구동하는 PC가 방화벽에 의해 특정 Port를 막고있지는 않은 지 확인하시기 바랍니다.

※본 Push API 예제는 Tizen 2.4 Mobile 및 Tizen 2.3.1 Wearable에서 거의 동일하게
사용 가능합니다.


본 Posting은 간단한 Push API의 사용법을 보여드리기 위해,
Push를 사용하기 위한 중요한 설계 Point들을 모두 무시하고 만들었습니다.

다음 번 Posting에서는 App 및 Server 설계를 어떻게 해야 하는지 알아보겠습니다.



오늘 구현한 Application의 간단한 동작 구조 입니다.


마지막으로 위에서 소개한 예제 코드의 Full Source입니다.

#include "push-receiver.h" #include <push-service.h> #define PUSH_APP_ID "input_your_app_id" typedef struct appdata { Evas_Object *win; Evas_Object *conform; Evas_Object *label; push_service_connection_h push_conn; } appdata_s; //////////////////////////////////////////// // 기본 자동생성 Code 생략 //////////////////////////////////////////// static void _result_cb(push_service_result_e result, const char *msg, void *user_data) { LOGI("register result callback (%d) : %s", (int)result, msg); } static void _state_cb(push_service_state_e state, const char *err, void *user_data) { appdata_s *ad = user_data; switch (state) { case PUSH_SERVICE_STATE_UNREGISTERED: LOGI("unregistered state, try register"); push_service_register(ad->push_conn, _result_cb, ad); break; case PUSH_SERVICE_STATE_REGISTERED: LOGI("registered"); char *reg_id = NULL; push_service_get_registration_id(ad->push_conn, &reg_id); LOGD("reg ID : %s", reg_id); free(reg_id); push_service_request_unread_notification(ad->push_conn); //push_service_deregister(ad->push_conn, _result_cb, ad); break; case PUSH_SERVICE_STATE_ERROR: LOGE("state error"); break; default: LOGW("state unknown"); break; } } static void _noti_cb(push_service_notification_h noti, void *user_data) { char *data = NULL; char *msg = NULL; push_service_get_notification_data(noti, &data); push_service_get_notification_message(noti, &msg); LOGI("noti data : %s", data); LOGI("noti msg : %s", msg); appdata_s *ad = user_data; char buf[4096] = {0, }; snprintf(buf, 4096, "<align=center>Noti Data : %s</br> \ Noti Msg : %s</align>", data, msg); elm_object_text_set(ad->label, buf); free(data); free(msg); } static bool app_create(void *data) { appdata_s *ad = data; create_base_gui(ad); int ret = push_service_connect(PUSH_APP_ID, _state_cb, _noti_cb, ad, &ad->push_conn); if (ret) LOGE("push connect error(%d) : %s", ret, get_error_message(ret)); return true; } // 나머지 생략


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함