본문 바로가기
Android/Java

Android 백그라운드 서비스 제한 notification 없이 service 실행하기!!

by DnaJ 2019. 11. 30.
반응형

 

백그라운드 서비스 제한 notification없이 service 실행하기!!

background service를 사용하려면 사용자에게 알리도록 되어있다.

Oreo이후 startForegroundService를 호출후 5초 이내에 service안에서 startForeground호출하지 않으면 crash가 발생하게 된다.

crash가 발생하지 않게 하려면 startForeground를 호출하면 된다. 

startForground를 호출하게 되면 상단에 백그라운드 서비스가 사용중 이라는 notification이 발생하게 된다.

 

targetsdk 28 이전에는 notification channel을 등록하지 않고 notification을 생성 후 startForeground에 넣어주게 되면 상단에 notification이 생성되지 않고 service가 실행되게 된다. 

 

android target sdk 28으로 올리면서 notificastion channel을 등록하지 않는 꼼수가 통하지 않게 되었다...

 

 

backroudService를 사용해야 하는데 notification이 방해를 한다.

notification없이 backgroundService를 이용하기 위해서두가지 방법이 있다.

https://smartstore.naver.com/happysiso

 

해피시소마켓 : 네이버쇼핑 스마트스토어

SISO

smartstore.naver.com

 

 

1. Service내 onCreate() 에서 stopForeground 호출

@Override

public void onCreate() {

    super.onCreate();

    startForeground(ForegroundService.instance);

    startForeground(this);

    stopForeground(true);

}

 

2. onStartCommand 에서 startService 호출

간혹 앱에서 startForeground를 호출을 했지만 5초 이내에 호출이 안됐다면서 crash report를 받아 봤을것이다.

참여중인 프로젝트 에서도 startForeground를 호출하지 못해서 crash가 많이 발생했다.

근본적으로 해결할 수 있는 방법을 찾지 못한채 앱이 계속 업데이트가 되었다.

 

 

Oreo 이상부터 startForegroundService로 실행 하라고 보통 이렇게 가이드를 한다.

 

if (Build.VERSION.SDK_INT >= 26) {
	context.startForegroundService(intent)
} else {
	context.startService(intent)
}

 

startForegroundService는 background, fourground구분없이 사용해도 된다. 하지만 startForground를 반드시 호출해줘야 한다.

 

하지만 이번 sdk28을 대응하면서 잘못 생각하고 있었던 부분이 있었다는 것을 알았다.

백그라운드 서비스 제한이지 서비스 제한이 아니였다는 것이다.

 

그렇기 때문에 ActivityLifecycleCallbacks을 사용하여 backgroud인지 foreground인지 구분을 했다.

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
}

앱이 background 상태일 경우 startForegroundService를 사용하여 실행하였고

foreground 상태일경우 startService를 사용해서 Service 를 실행했다.

 

foreground일경우 startService를 사용해도 crash가 발생하지 않는다.

여기서 약간의 문제가 발생을 했다. ActivityLifecycleCallbacks으로 앱의 상태를 판단할때 앱이 시작하는 시점은

foreground로 나왔다.

create시점이기 때문에 callback이 오는 것보다 service가 실행하는 것이 먼저였기 때문에 crash가 발생 했다.

하지만 특정 화면에서 실행이 될때는 crash가 발생하지 않아 확인을 해보았다.

 

확인 결과 startForegroundService 실행 후 startService를 실행하면 crash가 발생하지 않는다.

 

그렇기 때문에 약간의 꼼수를 사용했다.

startForgroundService를 실행 후 onCreate에서 startForground를 호출하지 않고

onStartCommand 에서 startService를 다시 호출하여 crash를 방지했다.

하지만 onStartCommand에서 startService를 실행하게 되면 무한 루프가 발생한다.

 

그렇기 때문에 startForegroundService에 넣는 Intent에 background에서 실행했다는 정보를 넣고

해당 상태일 경우만 startService를 호출했다.

 

onStartCommand에서 startService를 실행 시킨 이유는 onStartService에서 Intent객체를 받아올 수 있기 때문에

이전에 실행시킨 intent로 다시 전달을 할수 있기 때문이다.

 

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
	boolean startBackground = intent.getBooleanArrayExtra("startBackground");

	if (startBackground) {
    		intent.putExtra("startBackground", false);
    		startService(intent);
    	}
    
	return super.onStartCommand(Intent intent, int flags, int startId);
    // return 값은 필요한 값으로.....
}


 

문제점

위에처럼 startForground를 실행하지 않고 startService를 호출하게 되면  background에서 startService를 실행해서 crash가 발생했다는 로그간혹 올라온다. (특정한 재현 case가 있을듯 싶다)

앱을 나가기전 테스트를했을 때는 발생하지 않던 문제였다. 역시 꼼수는 꼼수인가보다... 완벽하지 않다.

 

하지만 startForground를 호출하지 않았다고 올라왔던 로그에 비해 확실히 crash빈도가 줄어들었다.

또한, notification을 띄우지 않고 백그라운드에서 service를 사용할수 있다는 장점도 있다.

 

 

 

그러나!!! 위의 방법도 다 꼼수다!! 꼼수!!!

 

가장 추천하는 방법은 WorkerManager를 사용하는 것이다!!!!!

만약 계속 실행되어야 하지 않아도 상관이 없는 service를 사용할 경우

WorkerManager를 사용을 하는것이 좋다고 한다. 

 

 

반응형

'Android > Java' 카테고리의 다른 글

Android WeakReference  (0) 2019.01.31

댓글