티스토리 뷰

단말앱 동기화

 앱서버는 등록한 단말앱 아이디을 관리해야 한다. 가장 기본적인 관리방법이 단말앱이 단말앱 등록 API와 단말앱 등록해제 API 호출 후 그 결과를 앱서버에 전달함으로써 앱서버가 유효한 단말앱 아이디를 동기화하는 것이다. 그러나 사용자가 단말앱 삭제를 하는 경우 앱서버는 삭제된 단말앱 아이디를 알기가 어렵다. 이를 해결하기 위해 래셔널아울은 두 가지 방법의 단말앱 동기화 방안을 제공한다. 단말앱 삭제에 대해 동기화를 진행하지 않은채로 서비스를 운영하면 유효한 단말앱 현황을 파악하기가 불가능할 뿐 아니라 사용자가 삭제하여 존재하지 않는 단말앱에 불필요한 메시지를 발신하게 된다.

 

1) 자동 동기화 방식

  • 시스템푸시 허용 설정으로 래셔널아울이 사용자 삭제 단말앱을 포함한 동기화 작업 자동 수행
  • 앱서버에서는 단말앱 동기화 API 호출을 통해 래셔널아울로부터 유효한 단말앱 아이디 목록 동기화

2) 수동 동기화 방식

 

  • 앱서버에서 사일런트 푸시 발신을 통한 삭제한 단말앱을 포함한 동기화 작업 직접 수행
  • unregisterDevices API 호출로 래셔널아울에 삭제된 단말앱 아이디 정보 제공

시스템푸시 '허용'을 통한 자동 동기화 방식

 래셔널아울 웹 관리자 화면에서 '단말앱 현황' > '단말앱 시스템푸시 설정'에서 시스템푸시를 '허용'으로 설정하면 해당 시점부터 래셔널아울은 사용자가 삭제한 단말앱에 대해서도 동기화 작업을 진행한다. 단말앱 시스템푸시는 기본 '불허'로 설정되어 있다.

단말앱 시스템푸시 설정

 시스템 푸시는 래셔널아울 서비스 차원에서 단말앱에 발신하는 사일런트 푸시이다. 시스템푸시를 허용으로 설정하면 해당 서비스 내 모든 단말앱에 하루 2번 시스템푸시를 발신하고 모든 단말앱들의 시스템 푸시 수신 여부를 트래킹한다. 참고로 시스템푸시는 발신목록에서 확인은 가능하지만 통계에서는 메시지 발신건수에 포함되지 않고 별도 메시지 비용도 발생하지 않는다.

 

자동 동기화 방식에서 단말앱 삭제 판단 기준

 자동 동기화 방식에서 래셔널아울이 단말앱 삭제 판단 기준은 아래 두 가지 조건을 모두 만족하는 경우이다.

  • 단말앱이 10일 이상 시스템푸시를 수신하지 않음
  • 단말앱이 10일 이상 실행되지 않음

단말앱 삭제 판단 기준일 10일은 '구축형 베이직' 과 '구축형 클러스터' 의 경우 고객사가 설정 가능하나 클라우드 형의 경우 설정 변경을 지원하지 않는다. 따라서 클라우드형 서비스를 이용하는 고객사 중 서비스 성격에 따라 단말앱 삭제 판단 기준일을 3일로 짧게 혹은 한달로 길게 잡고자 할 경우 본 글의 마지막 '수동 동기화 방식'을 통해 앱서버에서 직접 단말앱 동기화를 진행하면 된다.

단말앱 개발시 시스템푸시 대응 템플릿 코드 반영

 래셔널아울 웹 관리자 화면에서 '단말앱 시스템푸시'를 '허용'으로 설정하면 기본 하루에 두 번씩 시스템 푸시를 모든 단말앱에 발신한다. 단말앱이 시스템 푸시를 수신하면 이를 무시하는 루틴을 추가하면 된다. 이는 안드로이드 및 IOS 단말앱 샘플앱 가이드에서 확인할 수 있다. 시스템푸시 허용 여부에 관계없이 단말앱 개발시 아래 템플릿 코드를 따르는 것이 중요하다. 왜냐면 실제 서비스 운영시 시스템푸시를 이용하던지 아니던지 단말앱 재빌드가 필요없이 모든 경우에 대응이 가능하기 때문이다.

 

안드로이드

 

안드로이드 샘플앱 가이드의  개발환경을 그대로 다운받아 아래 코드 부분을 검색해서 확인 할 수 있다.

 

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Logger.debug(TAG, "onMessageReceived enter");
        Map<String, String> data = remoteMessage.getData();

        // set notification  delivery tracking
        MinervaManager minMgr = MinervaManager.getInstance();
        minMgr.enableNotificationTracking(data);

        // silent push received.
        if(data.containsKey("silent")) {
		
            // system push is sent by RationalOwl for device app lifecycle check.
            // system push is also silent push.
            // if system push has received, just return.
            if(data.containsKey("SystemPush")) {
                Logger.debug(TAG, "System push received!");
                return;
            }
            // normal silent push which are sent by your app server.
            // do your logic
            else {
                Logger.debug(TAG, "your app server sent silent push");
                // do your logic
            }
        }
        // it is normal custom push not silent push.
        // do your logic here
        else {
            // make your custom notification UI
            showCustomNotification(data);
        }

    }

즉, FCM 푸시 수신 콜백인 onMessageReceived 콜백내에서 위의 코드 템플릿을 추가하면 된다. 

 

사일런트 푸시 체크

  • 래셔널아울 사일런트 푸시 수신시 "silent": 1 필드가 존재하게 된다.
  • 시스템푸시는 사일런트 푸시 형태로 전달된다.
  • 위 코드 템플릿의 if(data.containsKey("silent")) 부분이 사일런트 푸시 수신 체크 부분이다.

시스템 푸시 체크

  • 래셔널아울 시스템 푸시 수신시 "SystemPush":1 필드가 존재하게 된다.
  • 위 코드 템플릿의 if(data.containsKey("SystemPush")) 부분이 시스템 푸시 수신 체크 부분이다.
  • 시스템 푸시일 경우 return 문을 호출해 줘야 한다.

IOS

 

IOS Swift 샘플앱 가이드의  개발환경을 그대로 다운받아 아래 코드 부분을 검색해서 확인 할 수 있다.

Objective-C로 개발하는 경우 IOS Objective-C 샘플앱 가이드를 참조하면 된다. 본 문서는 Swift 샘플앱 기준으로 설명한다.

 

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {

        if let aps = userInfo["aps"] as? NSDictionary {

            // silent push recieved
            if(aps["content-available"] != nil) {
                // enable notification delivery tracking
                let minMgr: MinervaManager = MinervaManager.getInstance();
                minMgr.enableNotificationTracking(userInfo, appGroup: "group.com.rationalowl.sample");
                // system push is sent by RationalOwl for device app lifecycle check.
                // system push is also silent push.
                // if system push has received, just return.
                if(userInfo["SystemPush"] != nil) {
                    print("system push received!!");
                    return;
                }
                // normal silent push which are sent by your app server.
                // do your logic
                else {
                    print("silent push received!");
                    // do your logic
                }
            }
        }
    }

AppDelegate.swift 의 didReceiveRemoteNotification 콜백내에서 위의 코드 템플릿을 추가하면 된다. 

 

사일런트 푸시 체크

  • IOS 사일런트 푸시 수신시 "content-available": 1 필드가 존재하게 된다.
  • 시스템푸시는 사일런트 푸시 형태로 전달된다.
  • 위 코드 템플릿의 if(aps["content-available"] != nil) 부분이 사일런트 푸시 수신 체크 부분이다.

시스템 푸시 체크

  • 래셔널아울 시스템 푸시 수신시 "SystemPush":1 필드가 존재하게 된다.
  • 위 코드 템플릿의 if(userInfo["SystemPush"] != nil) 부분이 시스템 푸시 수신 체크 부분이다.
  • 시스템 푸시일 경우 return 문을 호출해 줘야 한다.

앱서버 동기화 방법 (JAVA SDK 기준)

 자동 동기화를 통해 래셔널아울 시스템에서는 삭제한 단말앱에 대한 동기화가 진행되지만 앱서버에서는 단말앱 동기화 API를 통해 주기적으로 유효한 단말앱 아이디 목록을 동기화해야 한다.

 REST API를 이용하는 앱서버의 경우 REST API 개발가이드 의 '단말앱 동기화' 부분을 참고하기 바란다.

 

단말앱 동기화 리스너 등록

 

단말앱 동기화 API 결과 콜백을 수행할 리스너를 등록한다.

AppServerManager serverMgr = AppServerManager.getInstance(); 
serverMgr.setDeviceSyncListener(new SimpleDeviceSyncListener());

유효한 단말앱 아이디 목록 조회

 

시스템푸시를 허용으로 단말앱 자동 동기화 방식을 이용하는 경우 래셔널아울은 삭제된 단말앱까지 동기화하게 된다. 앱서버는 주기적으로 getDeviceIds API를 호출하여 서비스 내 모든 유효한 단말앱 목록을 동기화해야 한다. 한번의 API호출로 최대 20,000개 단말앱 아이디를 조회할 수 있다. 따라서 100만개 단말앱이 있는 서비스의 경우 해당 API를 50회 호출해야 한다.

 

유효한 단말앱 아이디 목록 조회 API

 

/**
* 서비스 내 유효한 단말앱 아이디 목록을 요청한다. 
* 결과는 setDeviceSyncListener로 등록한 DeviceSyncListener의 onDeviceIdResult 콜백을 통해  확인한다.
*     
* @param startIndex
*            전체 단말앱 중 fetch 시작 index
* @param fetchSize
*            전체 단말앱 목록 startIndex부터 fetch할 단말앱 아이디 목록 수.
*            최대 20,000
* @return request id
*/
public String getDeviceIds(int startIndex, int fetchSize) {
}

API 사용 예

AppServerManager serverMgr = AppServerManager.getInstance();
serverMgr.getDeviceIds(0, 20000);

유효한 단말앱 아이디 목록 조회 결과 콜백

 

onDeviceIdResult 콜백에서 결과를 알 수 있다.

/**
* AppServerManager의 getDeviceIds()API 호출결과 콜백이다.
* 
* @param resultCode
*            Result클래스에 정의된 결과값 상수
* @param resultMsg
*            resultCode의 값에 대한 의미    
* @param totalDeviceSize
*            서비스 내 유효한 단말앱 총 수
* @param startIndex
*            유효한 전체 단말앱 아이디 목록 중 fetch해올 목록의 첫 인덱스
* @param fetchDeviceSize
*            totalDeviceSize 중 startIndex부터 fetchDeviceSize 만큼의 단말앱 아이디를 deviceIds에 fetch 해 온다.
* @param deviceIds
*            fetch 해 온 단말앱 아이디 목록            
*                      
* @param requestId
*            본 콜백 결과를 야기한 getDeviceIds() API 반환값
*/
public void onDeviceIdResult(int resultCode, String resultMsg, int totalDeviceSize, int startIndex, int fetchDeviceSize, ArrayList<String> deviceIds, String requestId) {

}

단말그룹 내 단말앱 아이디 목록 조회

 

 자동 동기화 방식을 이용하는 경우 앱서버는 주기적으로 getSynchronizedGroupDeviceIds API를 호출하여 단말그룹 내 모든 유효한 단말앱 목록을 동기화해야 한다. 한번의 API호출로 최대 20,000개 단말앱 아이디를 조회할 수 있다. 따라서 100만개 단말앱이 있는 단말그룹의 경우 해당 API를 50회 호출해야 한다.

 

단말그룹 내 단말앱 아이디 목록 조회 API

/**
* 본 API가 호출되면 단말 그룹 내 동기화 작업이 수행되고 단말그룹내 내 유효한 단말앱 아이디 목록이 콜백으로 전달된다. 
* 결과는 setDeviceSyncListener로 등록한 DeviceSyncListener의 onGroupDeviceIdResult 콜백을 통해  확인한다.
* 
* @param deviceGroupId
*            대상 단말그룹 아이디 
* @param startIndex
*            전체 단말앱 중 fetch 시작 index
* @param fetchSize
*            전체 단말앱 목록 startIndex부터 fetch할 단말앱 아이디 목록 수
*            최대 20,000            
* @return request id
*/
public String getSynchronizedGroupDeviceIds(String deviceGroupId, int startIndex, int fetchSize) {
}

 

단말그룹 내 단말앱 아이디 목록 조회 결과 콜백

 

onGroupDeviceIdResult 콜백에서 결과를 알 수 있다.

/**
* AppServerManager의 getDeviceIdsInDeviceGroup()API 호출결과 콜백이다.
* 
* @param resultCode
*            Result클래스에 정의된 결과값 상수
* @param resultMsg
*            resultCode의 값에 대한 의미    
* @param deviceGroupId
*            대상 단말 그룹 아이디       
* @param totalDeviceSize
*            단말그룹 내 유효한 단말앱 총 수
* @param startIndex
*            단말그룹의 전체 단말앱 아이디 목록 중 fetch해올  첫 번째 인덱스
* @param fetchDeviceSize
*            totalDeviceSize 중 startIndex부터 fetchDeviceSize 만큼의 단말앱 아이디를 deviceIds에 fetch 해 온다.
* @param deviceIds
*            fetch 해 온 단말앱 아이디 목록            
*                      
* @param requestId
*            본 콜백 결과를 야기한 getDeviceIdsInDeviceGroup() API 반환값
*/
public void onGroupDeviceIdResult(int resultCode, String resultMsg, String deviceGroupId, int totalDeviceSize, int startIndex, int fetchDeviceSize, ArrayList<String> deviceIds, String requestId) {
}

수동 동기화 방식

 클라우드형 서비스를 이용하는 고객사 중 서비스 성격에 따라 단말앱 삭제 판단 기준일을 3일로 짧게 혹은 한달로 길게 잡고자 할 경우 앱서버에서 직접 단말앱 동기화를 할 수 가 있다. 아래는 수동 동기화 방식의 핵심 내용이다. 커스텀푸시 및 메시지 트래킹의 사용법은 본 블로그에서 별도의 주제로 다루고 있어서 해당 글을 참조하거나 앱서버 개발가이드를 참조하기 바란다.

 

1) 매일 하루 한번 이상 모든 단말앱 대상 사일런트 커스텀 푸시 발신

 간단하게 브로드캐스트 API로 모든 단말앱 대상 발신하는 것이 가장 효과적이다.

  • sendBroadcastCustomPush(Map<String, Object> data, boolean isSilent) API 이용

2) 메시지 트래킹 API 혹은 자동 메시지 트래킹 모드로 모든 단말앱 대상 알림 전달 여부 체크 

 

 - 메시지 트래킹 자동콜백 이용시

  • onAutoMsgTracked 결과 콜백에서 대상 단말앱 별 알림전달/수신확인 여부 확인

- 단말앱 상세정보를 트래킹할 수 있는 msgDeviceDetailTracking API를 통해 확인

  • msgDeviceDetailTracking API 결과콜백 onMsgDeviceDetailTrackingResult에서 알림전달/수신확인 여부 확인

3) 단말앱 삭제 판단 기준일 초과 한번도 푸시 수신을 하지 않은 단말앱에 대해 앱서버 내에서 단말앱 아이디 삭제 처리

 

4) 시스템푸시를 '불허'로 하면 래셔널아울 시스템에서 삭제한 단말앱에 대한 트래킹 및 동기화를 진행하지 않아 앱서버는 삭제된 단말앱 아이디 목록을 unregisterDevices API호출을 통해 래셔널아울 시스템에 알려줘야 한다.

AppServerManager serverMgr = AppServerManager.getInstance();
ArrayList<String> devices = new ArrayList<String>();
devices.add("app id 1");
devices.add("app id 2");
serverMgr.unregisterDevices(devices);
댓글