Notice
Recent Posts
Recent Comments
Link
투케이2K
128. (AndroidStudio/android/java) 포그라운드 서비스 (Foreground Service) 사용해 이모탈 서비스 만들기 - 좀비 서비스 본문
Android
128. (AndroidStudio/android/java) 포그라운드 서비스 (Foreground Service) 사용해 이모탈 서비스 만들기 - 좀비 서비스
투케이2K 2021. 5. 3. 13:23/* =========================== */
[ 개발 환경 설정 ]
개발 툴 : AndroidStudio
개발 언어 : java
/* =========================== */
/* =========================== */
[소스 코드]
[AndroidManifest.xml 파일]
<퍼미션 등록 부분>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<액티비티 등록 부분>
<activity
android:name=".A_ImmotalService"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan"/>
<서비스 등록 부분>
<service
android:name=".A_ImmotalServiceReceiver"
android:enabled="true"
android:exported="true"
android:stopWithTask="false" />
[JAVA 파일 : A_ImmotalService]
package kr.co.two2k.manager;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class A_ImmotalService extends AppCompatActivity {
/**
* [좀비 서비스]
* 1. 앱이 실행되는 동안 주기적 작업을 반복합니다
* 2. 서비스를 실행한 액티비티가 종료되어도 주기적 작업을 반복합니다
* 3. 애플리케이션 killed 상태가 되면 다시 서비스를 재실행합니다
* */
//TODO [클래스 컴포넌트 선언]
Button start_button;
Button stop_button;
//TODO [액티비티 시작 메소드]
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a_immotal_service);
Log.d("---","---");
Log.d("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalService > onCreate() 메소드 : 액티비티 시작 실시]");
Log.d("//===========//","================================================");
Log.d("---","---");
//TODO [컴포넌트 매칭 실시]
start_button = (Button)findViewById(R.id.start_button);
stop_button = (Button)findViewById(R.id.stop_button);
//TODO [화면 접속 시 즉시 서비스 종료]
try {
setServiceStop();
}
catch (Exception e){
e.printStackTrace();
}
//TODO [버튼 클릭 이벤트]
start_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Toast.makeText(getApplication(), "서비스를 시작합니다 ... ",Toast.LENGTH_SHORT).show();
setServiceStart();
}
catch (Exception e){
e.printStackTrace();
}
}
});
//TODO [버튼 클릭 이벤트]
stop_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Toast.makeText(getApplication(), "서비스를 종료합니다 ... ",Toast.LENGTH_SHORT).show();
setServiceStop();
}
catch (Exception e){
e.printStackTrace();
}
}
});
}//TODO 메인 종료
//TODO [서비스 등록 부분]
public void setServiceStart(){
Log.d("---","---");
Log.w("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalService > setServiceStart() 메소드 : 서비스 시작 수행]");
Log.w("//===========//","================================================");
Log.d("---","---");
try {
//TODO [서비스 시작 실시]
startService(new Intent(getApplicationContext(), A_ImmotalServiceReceiver.class));
}
catch (Exception e){
e.printStackTrace();
}
}
//TODO [서비스 해제 부분]
public void setServiceStop(){
Log.d("---","---");
Log.e("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalService > setServiceStop() 메소드 : 서비스 종료 수행]");
Log.e("//===========//","================================================");
Log.d("---","---");
try {
//TODO [서비스 종료 실시]
stopService(new Intent(getApplicationContext(), A_ImmotalServiceReceiver.class));
}
catch (Exception e){
e.printStackTrace();
}
}
//TODO [백버튼 터치시 뒤로 가기]
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 디바이스의 키 이벤트가 발생했는데, 뒤로가기 이벤트일때
if (keyCode == KeyEvent.KEYCODE_BACK) {
Log.d("---","---");
Log.d("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalService > onKeyDown() 메소드 : 백버튼 터치시 뒤로 가기 이벤트 실시]");
Log.d("//===========//","================================================");
Log.d("---","---");
try {
//TODO [액티비티 종료 실시]
finish();
overridePendingTransition(0,0);
}
catch (Exception e){
e.printStackTrace();
}
}
return true;
}
//TODO [액티비티 종료 메소드]
@Override
public void onDestroy(){
super.onDestroy();
Log.d("---","---");
Log.d("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalService > onDestroy() 메소드 : 액티비티 종료 확인]");
Log.d("//===========//","================================================");
Log.d("---","---");
}
}//TODO 클래스 종료
[JAVA 파일 : A_ImmotalServiceReceiver]
//TODO 노티피케이션 알림 표시 부분
NotificationManager notificationManager; //매니저
NotificationChannel notificationChannel; //채널
NotificationCompat.Builder builder; //빌더
String serviceTittle = "Service";
String serviceContent = "Start";
public void setNotificationShow(){
try {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ //TODO 오레오 버전 이상
//오레오 버전 이상부터는 노티피케이션을 사용하기 위해서 채널이 필요하다
int importance = NotificationManager.IMPORTANCE_HIGH; //TODO 알림 우선순위를 최상으로 설정 (타이틀 및 소리)
String Noti_Channel_ID = "DefaultNoti";
String Noti_Channel_Group_ID = "DefaultNoti_Group";
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationChannel = new NotificationChannel(Noti_Channel_ID,Noti_Channel_Group_ID,importance);
//TODO 뱃지 카운트 실시 (디폴트 true)
//notificationChannel.setShowBadge(true);
if(notificationManager.getNotificationChannel(Noti_Channel_ID) != null){ //TODO 채널이 존재할 경우
Log.d("---","---");
Log.w("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalServiceReceiver > setNotificationShow() 메소드 : 채널이 이미 존재합니다]");
Log.w("//===========//","================================================");
Log.d("---","---");
}
else{
Log.d("---","---");
Log.e("//===========//","================================================");
Log.d("","\n"+"[A_ImmotalServiceReceiver > setNotificationShow() 메소드 : 채널이 없어서 만듭니다]");
Log.e("//===========//","================================================");
Log.d("---","---");
notificationManager.createNotificationChannel(notificationChannel);
}
notificationManager.createNotificationChannel(notificationChannel);
builder = new NotificationCompat.Builder(getApplicationContext(),Noti_Channel_ID)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tk_app_icon))
.setSmallIcon(R.drawable.ic_logo_white)
.setColor(ContextCompat.getColor(this, R.color.customColor))
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentTitle(serviceTittle) //TODO 제목
.setChannelId(Noti_Channel_ID)
.setContentText(serviceContent); //TODO 내용
//builder.setContentIntent(pendingIntent); //TODO 개별 인텐트 적용
builder.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; //TODO 노티 알림 삭제 시 자동으로 푸시 뱃지 표시 지움
notificationManager.notify(1,builder.build()); //TODO 노티피케이션이 표시
startForeground(1, builder.build()); //TODO 포그라운드 서비스 실행
}
else {
builder = new NotificationCompat.Builder(getApplicationContext())
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.tk_app_icon))
.setSmallIcon(R.drawable.ic_logo_white)
.setColor(ContextCompat.getColor(this, R.color.customColor))
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_MAX) //TODO Priority와 Vibrator가 있어야 알림바 표시됨
//.setDefaults(Notification.DEFAULT_VIBRATE)
.setContentTitle(serviceTittle) //TODO 제목
.setContentText(serviceContent); //TODO 내용
//builder.setContentIntent(pendingIntent); //TODO 개별 인텐트 적용
builder.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; //TODO 노티 알림 삭제 시 자동으로 푸시 뱃지 표시 지움
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1,builder.build()); //TODO 노티피케이션이 표시
startForeground(1, builder.build()); //TODO 포그라운드 서비스 실행
}
}
catch (Exception e){
e.printStackTrace();
}
}
[XML 파일 : activity_a_immotal_service.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true"
android:id="@+id/parent">
<!-- [editText 사용시 자동으로 포커스활성 방지]-->
<!-- android:focusable="true"-->
<!-- android:focusableInTouchMode="true"-->
<!-- android:id="@+id/parent"-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- ====== [타이틀 레이아웃] ====== -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:background="#343d46"
android:layout_marginBottom="10dp">
<TextView
android:id="@+id/title_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="[ 이모탈 서비스 ]"
android:textColor="#ffffff"
android:textSize="23dp"
android:textStyle="bold"
android:gravity="center"/>
</LinearLayout>
<!-- ====== [카드 레이아웃] ====== -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#343d46"
android:layout_margin="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6.5"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginBottom="0dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/url_icon"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:layout_marginTop="15dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginBottom="20dp">
<Button
android:id="@+id/start_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="서비스 시작"
android:textStyle="bold"
android:textSize="13dp"
android:gravity="center"
android:textColor="#000000"
android:background="@drawable/white_button_bg"
android:layout_marginTop="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="0dp" />
<Button
android:id="@+id/stop_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="서비스 종료"
android:textStyle="bold"
android:textSize="13dp"
android:gravity="center"
android:textColor="#000000"
android:background="@drawable/white_button_bg"
android:layout_marginTop="0dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
/* =========================== */
/* =========================== */
[결과 출력]
/* =========================== */
/* =========================== */
[첨부 파일 - 전체 소스코드]
/* =========================== */
반응형
'Android' 카테고리의 다른 글
Comments