내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-09 07:39

제목

[Android] FCM(Firebase)을 이용한 Push처리 시 앱 Background처리 대응


FCM(Firebase)을 이용해서 Push처리시 해당 어플이 실행중 일때 즉 Foreground상태에서는 정상적으로 FirebaseMessagingService클래스를 상속받아 구현한 onMessageReceived메서드가 호출되어 같이 넘긴 Data를 받아 처리 할 수 있다.

하지만 어플이 Background상태일 경우(앱 자체가 시작되지 않았거나, 메모리에서 내려간 경우) SDK에서 전달받은 데이터에 키를 찾아서

'Notification'키가 있는 경우는 SDK내에서 처리해서 onMessageReceived메서드를 호출 할 수 없게 된다.

이를 해결하려면 'Notification'키 내에 Intent필터를 걸어줄 수 있는 액션을 함께 설정해서 push를 전송해야 한다.

AndroidManifest.xml

<activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
 
        <!--앱이 백그라운드 상태일때 푸시 알림바 클릭시 열리는 엑티비티 및 데이터 받는 필터 설정-->
        <category android:name="android.intent.category.DEFAULT" />
 
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
 
<activity
        android:name=".NoteActivity"
        android:theme="@style/AppTheme.NoActionBar">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity" />
</activity>
 
<activity
        android:name=".ScheduleActivity"
        android:theme="@style/AppTheme.NoActionBar">
    <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".MainActivity" />
</activity>
cs

위 코드에서 MainActivity에 Intent필터를 설정한 부분을 보면

<action android:name="android.intent.action.MAIN"/>
<!--앱이 백그라운드 상태일때 푸시 알림바 클릭시 열리는 엑티비티 및 데이터 받는 필터 설정-->
<category android:name="android.intent.category.DEFAULT" />
cs

action과 category속성을 설정한 것을 볼 수 있다.
action name이 FCM에서 push발송시 알림 클릭시 표시되는 Activity를 지정할 name이다.

FCM Push발송에 대한 JSON은 다음과 같다.

[push 알림 전송 서버의 node.js 코드중 FCM Push발송 JSON데이터]

var options = {
        method: 'POST',
        url: url,
        headers: {
            'Content-Type''application/json',
            'Authorization': `key=${apikey}`
        },
        body: JSON.stringify({
            to: "/topics/ShareNotes",
            priority: 'high',
            notification: {
                body: body,
                title: title,
                click_action: "android.intent.action.MAIN"
            },
            data: {
                title: title,
                body: body,
            },
 
            // App 패키지 이름
            restricted_package_name: "com.tyeom.sharenotes",
            // App에게 전달할 데이터가 있는 경우 여기에 설정해서 전송
            data: {
                categoryId: categoryId,
                noteId: noteId,
                noteType: noteType
            }
        })
};
cs


전달 받은 데이터는 Intent 필터를 설정한 Activity에서 다음과 같이 처리 할 수 있다.

위 코드에서는 push알림 클릭 후 해당 앱 진입시 android.intent.action.MAIN Activity를 표시 하기에 MainActivity에서 데이터를 받는다.

MainActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    // https://stackoverflow.com/questions/20853128/connect-to-sql-server-through-android
    // StrictMode설정을 해야 MSSQL Connection시 오류가 나지 않는다..
    // 이유는 모르겠음..ㅠ
    val policy = StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(this.toolbar)
 
    // 스와이프 새로고침 이벤트 리스너 등록
    this.swipeRefreshLayout.setOnRefreshListener(this);
 
    // 푸시 알림 클릭으로 MainIntent실행시
    val categoryId = intent.getLongExtra("categoryId"-1L);
    val noteId = intent.getLongExtra("noteId"-1L);
    val noteType = intent.getStringExtra("noteType");
    // 앱 포크라운드에서 푸시 알림 클릭시
    if(categoryId > 0 && noteId > 0) {
        if(noteType == "ScheduleType") {
            startActivity<ScheduleActivity>("noteId" to noteId, "categoryId" to categoryId, "categoryText" to "");
        }
        else {
            startActivity<NoteActivity>("noteId" to noteId, "categoryId" to categoryId, "categoryText" to "");
        }
    }
    // 앱 백그라운드에서 푸시 알림 클릭시
    else {
        val bundle: Bundle? = intent.extras;
        if(bundle != null) {
            val categoryId = bundle.get("categoryId")?.toString()?.toLongOrNull();
            val noteId = bundle.get("noteId")?.toString()?.toLongOrNull();
            val noteType = bundle.get("noteType")?.toString() ?: "";
 
            if(categoryId != null && categoryId > 0 && noteId != null && noteId > 0) {
                if(noteType == "ScheduleType") {
                    startActivity<ScheduleActivity>("noteId" to noteId, "categoryId" to categoryId, "categoryText" to "");
                }
                else {
                    startActivity<NoteActivity>("noteId" to noteId, "categoryId" to categoryId, "categoryText" to "");
                }
            }
        }
    }
....
}
cs

위 처럼 Bundle클래스를 통해 FCM SDK가 전달한 데이터를 받아서 처리 할 수 있다.

출처1

출처2