Warning
이 방식은 안드로이드 8.0이상 부터, BACKGROUND SERVICE 제약으로, 더 이상 지원이 불가능하니다. 아래 링크를 참고해서, 새로운 버전으로 적용하시기 바랍니다.
Morpheus Push 는 스마트폰 OS에서 지원하는 PNS(Push Notification Server)를 기반으로 한 메세지 전송 플랫폼이다.
Android Client 에서는 UPMC WAS 에서 제공하는 Push API 를 각각 버전 규격에 맞춰 연동하여 원할하게 Push Service 를 운영하기 위한 라이브러리를 제공한다.
– GCM 서비스 등록을 위한 ID
UPMC 4.0 이상 버전
RegisterService & User => 메시지 수신
Android 용 SDK 파일
MPushLibrary
mcore.mobile.lic
– Push 라이센스 정보가 담긴 Push 라이센스 파일
Manifest.xml
– Push 구동을 위한 설정 파일
SDK 적용 방법
Android Project 의 libs 폴더에 Library 파일에 추가
Android Project의 assets/res 폴더에 라이선스 및 설정 파일 추가
mcore.mobile.lic
#Tue Feb 17 09:53:27 KST 2015
application_id=xxx.xxx.xxxx.xxxx
expiration_date=xxxx-xx-xx
mpsn=hZK................X
sn=AhA....E....
New in version 3.8.1 Library
<?xml version="1.0" encoding="UTF-8"?>
<settings>
<push>
<receiver> <!-- UPMC 설정 정보 -->
<!-- console log -->
<log>y</log>
<!-- file log -->
<file-log>n</file-log>
<!-- key 교환 방식 암호화 : 라이선스 발급시 요청 (hexa코드 16자리) -->
<security-indexes>0x??? 0x??? 0x??? </security-indexes>
<!-- UPMC 서버 버전 4.0/ 5.0 / 5.1 등 -->
<version>4.0</version>
<!-- UPMC 서버 url(필수 설정) -->
<server>http://pushxx.morpheus.co.kr:18080/</server>
<timeout>20000</timeout>
<!-- 푸쉬타입(필수설정)
GCM:구글GCM(Public Push)
UPNS:유라클UPNS(Private Push)
ALL : doze mode 대응 (gcm : dummy data, upns : real data)
-->
<android-push-type>UPNS</android-push-type>
<!-- 서비스 정책 ,
user : one user multidevice,
device : one user one device,
default : user -->
<policy>device</policy>
<!-- stb(셋탑)/mobile(모바일)/mobile_old(디바이스 아이디 이전 버전) -->
<device-type>mobile</device-type>
<!-- upmc 연동시 휴대폰 번호 사용 여부 -->
<use-phone_number>n</use-phone_number>
<!-- 안드로이드 8.0이상 필수, 브로드캐스트 리시버에서 퍼미션 사용 여부를 설정 (Y/N) -->
<use-permission>Y</use-permission>
</receiver>
<upns>
<!-- agent, inapp -->
<agent-service-type>inapp</agent-service-type>
<!-- UPNS RESTART ALARM INTERVAL (초단위) -->
<agent-restart-interval>60</agent-restart-interval>
<!-- auto/manual -->
<agent-receive-confirm>auto</agent-receive-confirm>
<!-- reconnect interval (초단위) - 최소 10초 이상(서버에 대한 부하 고려하여 설정 - 기본값 10초) -->
<reconnect-interval>10</reconnect-interval>
<!-- reconnect interval (초단위) - 최소 10초 이상 (재접속 카운트에 따라 설정, 3회 이후 다시 최초 설정 간격으로 반복)-->
<reconnect-interval>10,20,30</reconnect-interval>
<!-- reallocate interval (v4.1 이상 - 다른 버전 무시) - 최소 10 이상 -->
<!-- 단위: , 1~reallocate-interval 사이의 랜덤한 시간간격으로 호출 요청 (60 이상 권장, 재할당 카운트에 따라 설정, 3회 이후 다시 최초 설정 간격으로 반복) -->
<reallocate-interval>10,30,50</reallocate-interval>
<!-- 사용자 등록 시 재시도 여부 auto / 횟수 (integer) -->
<retry-regist-count>auto</retry-regist-count>
</upns>
</push>
</settings>
Key | Type | Description |
---|---|---|
log | String | Push Service 에 대한 Debugging 로그 출력 여부 ( y / n ) |
version | String | UPMC Version ( 3.0, 3.5, 3.6, 3.7, 3.8, 4.0 ) |
server | String | UPMC WAS 서버 URL |
device-type | String | 서비스 디바이스에 대한 성정 (빈값 : mobile, mobile : mobile용, stb : 셋탑용) |
agent-service-type | String | UPNS 서비스 방식 (inapp : 라이브러리형, agent : 별도의 Agent 앱 구현시) |
agent-restart-interval | String | 앱이 살아 있는지 체크를 위한 시간 설정 (단위 : sec) |
agent-receive-confirm | String | upns 메시지 수신 결과에 대한 ack 전송 방법 (auto : 자동 (default), manual : 수동, 직접 구현) |
reconnect-interval | String | 재연결 요청 간격 (기본값: 10초) : 서버의 부하를 고려하여 설정 (반대로 너무 길 경우 재연결이 오래 걸리므로 주의) |
reallocate-interval | String | 서버 4.1 이상 이용 시 연결 실패에 따른 서버 재할당 간격 (기본값: 600ms) : 서버의 부하를 고려하여 설정 |
retry-regist-count | String | 사용자 등록 시 재시도 여부 auto / 횟수 (integer) |
Note
파일로그 위치 : 스토리지 > Android > data > [package name] > log > pushlog.log
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="[패키지명]"
android:versionCode="1"
android:versionName="1.0">
<!-- 안드로이드 8.0이상 필수, 라이브러리 버전 4.1.0.7 이상부터 추가된 리시버 등록 시 권한 등록위해 선언 (없으면 앱 디폴트 권한) -->
<permission android:name="${applicationId}.permission.MPUSH_PERMISSION" android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.MPUSH_PERMISSION" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
<!-- 5.1.1.x 버전 신규 -->
<service
android:name="m.client.push.library.service.UPNSConnectService"
android:exported="false"/>
<service
android:name="m.client.push.library.service.UPNSJobService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
<receiver android:name="m.client.push.library.receiver.ServiceHandleReceiver">
<intent-filter>
<action android:name="${applicationId}.START_PUSHSERVICE" />
<action android:name="${applicationId}.STOP_PUSHSERVICE" />
<action android:name="${applicationId}.RESTART_PUSHSERVICE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<receiver android:name="com.push.democlient.receiver.MessageArrivedReceiver">
<intent-filter>
<action android:name="${applicationId}.UPNS_MESSAGE_ARRIVED" />
<action android:name="${applicationId}.GCM_MESSAGE_ARRIVED" />
</intent-filter>
</receiver>
<receiver android:name="m.client.push.library.receiver.UpnsActionReceiver">
<intent-filter>
<action android:name="${applicationId}.ACTION_UPNS" />
</intent-filter>
</receiver>
<service
android:name=".service.RealService"
android:enabled="true"
android:exported="true" />
<receiver android:name=".service.AlarmRecever"/>
<receiver
android:name=".service.RebootRecever"
android:enabled="true"
android:exported="false"
android:process=":remote">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</applicationi>
</manifest>
Case #1. Push service 등록
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PushManager.getInstance().registerServiceAndUser(getApplicationContext(), cuid, cname);
...
}
-- Push 플러그인 : http://docs.morpheus.co.kr/client/api/plugin-push.html
Arguments
Arguments
Key | Type | Description |
---|---|---|
PushConstants.KEY_CNAME | String | 사용자 닉네임 |
PushConstants.KEY_STB_ID | String | 셋탑 아이디 |
PushConstants.KEY_DEVICE_ID | String | 디바이스id |
PushConstants.KEY_CUSTOM_RECEIVER_SERVER_URL | String | UPMC url |
PushConstants.KEY_CUSTOM_UPNS_SERVER_URL | String | UPNS url |
- 예시 :
JSONObject params = new JSONObject();
// http://xxx.xxx.x.xx:xxxx 연결할 리시버 서버 url
params.put(PushConstants.KEY_CUSTOM_RECEIVER_SERVER_URL, "http://xxx.xxx.x.xx:xxxx");
// tcp://xxx.xxx.x.xx:xxxx 연결할 UPNS 서버 url
params.put(PushConstants.KEY_CUSTOM_UPNS_SERVER_URL, "tcp://xxx.xxx.x.xx:xxxx");
Arguments
Arguments
Key | Type | Description |
---|---|---|
PushConstants.KEY_DEVICE_ID | String | 디바이스id |
PushConstants.KEY_CUSTOM_RECEIVER_SERVER_URL | String | UPMC url |
PushConstants.KEY_CUSTOM_UPNS_SERVER_URL | String | UPNS url |
- 예시 :
JSONObject params = new JSONObject();
params.put(PushConstants.KEY_STB_ID, "{A73E9E2E-9C6B-11E4-AFAE-C55006B96D3C}");
params.put(PushConstants.KEY_DEVICE_ID, "DEVICE-A73E9E2E9C6B11E4AFAEC55006B96D3C"/*생성하여 추가 요망*/);
params.put(PushConstants.KEY_CNAME, "GUEST-A73E9E2E9C6B11E4AFAEC55006B96D3C");
Arguments
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
Key | Type | Necessary | Description |
---|---|---|---|
PushConstants.KEY_CUID | String | 필수 | Client ID |
PushConstants.KEY_CNAME | String | 필수 | Client Name |
PushConstants.KEY_STB_ID | String | 선택 | STB ID |
PushConstants.KEY_DEVICE_ID | String | 선택 | Device ID |
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
Key | Type | Necessary | Description |
---|---|---|---|
PushConstants.KEY_CUID | String | 필수 | Client ID |
PushConstants.KEY_CNAME | String | 필수 | Client Name |
PushConstants.KEY_STB_ID | String | 선택 | STB ID |
PushConstants.KEY_DEVICE_ID | String | 선택 | Device ID |
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
Key | Type | Necessary | Description |
---|---|---|---|
PushConstants.KEY_EDIT_PUSH_TYPE | String | 필수 | Push Type |
-결과값 : Reciver 를 통해, 처리 결과 통보
- 예시 :
JSONObject params = new JSONObject();
params.put(PushConstants.KEY_EDIT_PUSH_TYPE, PushConstants.STR_UPNS_PUSH_TYPE);
Arguments
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
Key | Type | Necessary | Description |
---|---|---|---|
PushConstants.KEY_CUID | String | 필수 | Client ID |
PushConstants.KEY_CNAME | String | 필수 | Client Name |
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
-결과값 : Reciver 를 통해, 처리 결과 통보
Arguments
Key | Type | Necessary | Description |
---|---|---|---|
PushConstants.KEY_CNAME | String | 선택 | Client Name |
PushConstants.KEY_STB_ID | String | 선택 | STB ID |
PushConstants.KEY_DEVICE_ID | String | 선택 | Device ID |
- 예시 :
JSONObject params = new JSONObject();
params.put(PushConstants.KEY_STB_ID, "{A73E9E2E-9C6B-11E4-AFAE-C55006B96D3C}");
params.put(PushConstants.KEY_DEVICE_ID, "DEVICE-A73E9E2E9C6B11E4AFAEC55006B96D3C");
Arguments
New in version 4.0 UPMC
Arguments
:param int badgeCountType
Key | Type | Description |
---|---|---|
PushConstants.BADGE_TYPE_KEEP | String | 1개 읽음 처리, 다음 메시지 수신시, 동일한 값 유지(Default, -1 후 +1 이 됨) |
PushConstants.BADGE_TYPE_RESET | String | 입력 값으로 초기화, 다음 수신된 값은 입력값 +1로 처리됨 |
PushConstants.BADGE_TYPE_UPDATE | String | 카운트에 따라 업데이트 됨 (읽음여부에 상관없이, push 수신 ++) |
Arguments
Arguments
Arguments
Arguments
Arguments
Arguments
Arguments
Arguments
Key | Description (결과값) |
---|---|
PushConstantsEx.COMPLETE_BUNDLE.REG_USER | 사용자 등록 |
PushConstantsEx.COMPLETE_BUNDLE.UNREG_USER | 사용자 등록 |
PushConstantsEx.COMPLETE_BUNDLE.UPDATE_PUSHSERVICE_DATE | push service 갱신 |
PushConstantsEx.COMPLETE_BUNDLE.REG_PUSHSERVICE | 푸시 서비스 등록 |
PushConstantsEx.COMPLETE_BUNDLE.UNREG_PUSHSERVICE | 푸시 서비스 해제 |
PushConstantsEx.COMPLETE_BUNDLE.READ_CONFIRM | 읽음 ack |
PushConstantsEx.COMPLETE_BUNDLE.RECEIVE_CONFIRM | 수신 ack (gcm only) |
PushConstantsEx.COMPLETE_BUNDLE.IS_REGISTERED_SERVICE | 서비스 등록 여부 (register service 호출 시, 수신 될 수 있음) |
PushConstantsEx.COMPLETE_BUNDLE.INITBADGENO | 뱃지 넘버 초기화 |
PushConstantsEx.COMPLETE_BUNDLE.REG_GROUP | 그룹 등록 |
PushConstantsEx.COMPLETE_BUNDLE.UNREG_GROUP | 그릅 해제 |
Key | Description (결과값) |
---|---|
PushConstants.RESULTCODE_OK | 정상 |
PushConstants.RESULTCODE_HTTP_ERR | 통신 오류 - UPMC서버에 접속할 수 없을때 - connection 관련 error |
PushConstants.RESULTCODE_AUTHKEY_ERR | 인증키 획득 오류 |
PushConstants.RESULTCODE_RESPONSE_ERR | 응답 오류 - 오류코드를 수신한 경우 |
PushConstants.RESULTCODE_INTERNAL_ERR | 정의되지 않은 예기치 못한 오류가 발생한 경우 |
PushConstants.RESULTCODE_AUTHKEY_ERR2 | 인증키 획득 오류 |
Key | Description (결과값) |
---|---|
PushConstants.KEY_RESULT | ACTION_COMPLETED에 Extras용 전체 호출값 |
PushConstants.KEY_BUNDLE | 번들용 KEY |
PushConstants.KEY_ISREGISTER | 서비스 등록 여부에 대한 결과값 |
PushConstants.KEY_RESULT_CODE | 결과 코드 (정상 : 200) |
PushConstants.KEY_RESULT_MSG | upmc 통신 이후, 수신된 메시지 |
private BroadcastReceiver mLoginBroadcastReceiver;
public void registerReceiver() {
if (mMainBroadcastReceiver != null) {
return;
}
// 화면에서 서비스 등록 결과를 받기 위한 리시버 등록 - 패키지명.ACTION_COMPLETED
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MainActivity.this.getPackageName() + PushConstantsEx.ACTION_COMPLETED);
mMainBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 수신된 인텐트(결과값 응답) 의 정상 데이터 여부 체크 (푸시 타입/액션 타입) - 반드시 구현
if(! PushUtils.checkValidationOfCompleted(intent, context)){
return;
}
//push 타입 판단
JSONObject result_obj = null; // 수신된 오브젝트
String result_code = ""; // 결과 코드
String result_msg = ""; // 결과 메세지
try {
result_obj = new JSONObject(intent.getExtras().getString(PushConstants.KEY_RESULT));
result_code = result_obj.getString(PushConstants.KEY_RESULT_CODE);
result_msg = result_obj.getString(PushConstants.KEY_RESULT_MSG);
}
catch (JSONException e) {
e.printStackTrace();
}
// 액션 타입
String bundle = intent.getStringExtra(PushConstantsEx.KEY_BUNDLE);
//액션에 따라 분기 (이미 서비스 등록이 완료된 상태인 경우 다음 process 이동)
if (bundle.equals(PushConstantsEx.COMPLETE_BUNDLE.IS_REGISTERED_SERVICE)) {
//mProgressDialog.dismiss();
Logger.e(result_code);
String resultPushType = intent.getExtras().getString(PushConstants.KEY_PUSH_TYPE);
if (resultPushType.equals(PushHandler.getInstance().getPushConfigInfo(getApplicationContext()).getPushType())) {
if (result_code.equals(PushConstants.RESULTCODE_OK)) {
Intent pageIntent = new Intent(mMainActivity, LoginActivity.class);
startActivity(pageIntent);
finish();
}
}
else {
Toast.makeText(mMainActivity, result_msg, Toast.LENGTH_LONG).show();
}
// 최초 서비스 등록이 완료된 경우 다음 process 이동
} else if (bundle.equals(PushConstantsEx.COMPLETE_BUNDLE.REG_PUSHSERVICE)) {
// 등록 성공
if (result_code.equals(PushConstants.RESULTCODE_OK)) {
Toast.makeText(context, "등록 성공!", Toast.LENGTH_SHORT).show();
Intent pageIntent = new Intent(mMainActivity, LoginActivity.class);
startActivity(pageIntent);
finish();
}
// 통신 에러
else if (result_code.equals(PushConstants.RESULTCODE_HTTP_ERR)) {
Toast.makeText(context, "[MainActivity] error code: " + result_code + " msg: " + result_msg, Toast.LENGTH_SHORT).show();
}
// 인증키 오류
else if (result_code.equals(PushConstants.RESULTCODE_AUTHKEY_ERR)) {
Toast.makeText(context, "[MainActivity] error code: " + result_code + " msg: " + result_msg, Toast.LENGTH_SHORT).show();
}
// 서버 응답 에러
else if (result_code.equals(PushConstants.RESULTCODE_RESPONSE_ERR)) {
Toast.makeText(context, "[MainActivity] error code: " + result_code + " msg: " + result_msg, Toast.LENGTH_SHORT).show();
}
// 라이브러리 에러 - 파싱 에러
else if (result_code.equals(PushConstants.RESULTCODE_INTERNAL_ERR)) {
Toast.makeText(context, "[MainActivity] error code: " + result_code + " msg: " + result_msg, Toast.LENGTH_SHORT).show();
}
// 기타
else {
Toast.makeText(context, "[MainActivity] error code: " + result_code + " msg: " + result_msg, Toast.LENGTH_SHORT).show();
//System.exit(0);
}
}
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMainBroadcastReceiver, intentFilter);
}
public void unregisterReceiver() {
if (mMainBroadcastReceiver != null) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMainBroadcastReceiver);
mMainBroadcastReceiver = null;
}
}
아래 기술된 메시지는 샘플에 대한 예시이며, 프로젝트에서 표현하고자 하는 방식에 따라, Interface 정의서에 의해, 변경이 가능함.
JSONObject key 값에 대한 설명
Key | 활용방법 |
---|---|
MESSAGE | 메시지 타이틀로 이용 |
EXT | 일반 메시지인 경우, 메시지로 이용가능하며, Rich 메시지인 경우, 세부 정보를 추가로 획득하여, 표현 |
SEQNO | Push message의 고유 키값 |
PSID | Push 서비스에 대한 고유 ID( PSID) |
APPID | Push 서비스가 관리되는 앱 ID( Application ID) |
CUID | 사용자 ID( Client ID) |
PUBLIC | Public 망을 이용하는 push 여부 |
SENDERCODE | 발송자 코드 (서버관점) |
SENDDATE | 발송된 시간 (서버관점) |
DB_IN | DB에 저장 여부 (서버 관점) |
BADGENO | 뱃지값 |
{
"BODY":{
"MESSAGE":"일반 알림",
"EXT":"메세지 테스트",
"SEQNO":"304",
"PSID":"9ca385ad63c4cbd5eeda33c2e7a7a024ea83c2d4",
"APPID":"com.uracle.push.test",
"CUID":"test1",
"PUBLIC":"N",
"SENDERCODE":"device-android",
"SENDDATE":"2016041410",
"DB_IN":"Y",
"BADGENO":"9"
}
}
{
"BODY":{
"MESSAGE":"Web 알림",
"EXT":"1|웹페이지|http://lab.morpheus.kr/push/sample/image|http://lab.morpheus.kr/push/sample/webpage",
"SEQNO":"305",
"PSID":"9ca385ad63c4cbd5eeda33c2e7a7a024ea83c2d4",
"APPID":"com.uracle.push.test",
"CUID":"test1",
"PUBLIC":"N",
"SENDERCODE":"device-android",
"SENDDATE":"2016041410",
"DB_IN":"Y",
"BADGENO":"10"
}
}
{
"BODY":{
"MESSAGE":"이미지 알림",
"EXT":"1|웹페이지|http://lab.morpheus.kr/push/sample/image",
"SEQNO":"307",
"PSID":"9ca385ad63c4cbd5eeda33c2e7a7a024ea83c2d4",
"APPID":"com.uracle.push.test",
"CUID":"test1",
"PUBLIC":"N",
"SENDERCODE":"device-android",
"SENDDATE":"2016041410",
"DB_IN":"Y",
"BADGENO":"12"
}
}