국비교육(22-23)

84일차(2)/Android App(48) : Notification(1)

서리/Seori 2023. 2. 9. 00:22

84일차(2)/Android App(48) : Notification(1)

 

새 모듈 생성- empty activity

step21notification

 

 

activity_main.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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="메세지 입력..."
        android:id="@+id/inputMsg"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="자동 취소 되는 알림"
        android:id="@+id/notiBtn"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="수동 취소 되는 알림"
        android:id="@+id/notiBtn2"/>

</LinearLayout>

 

MainActivity

package com.example.step21notification;

import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

public class MainActivity extends AppCompatActivity {
    //알림 체널의 이름 정하기
    public static final String CHANNEL_NAME = "com.example.step21notification.MY_CHANNEL";
    //필요한 필드
    EditText inputMsg;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        inputMsg = findViewById(R.id.inputMsg);
        //Auto Cancel 버튼을 눌렀을때 동작
        Button notiBtn = findViewById(R.id.notiBtn);
        notiBtn.setOnClickListener(v -> {
            makeAutoCancelNoti();
        });
    }
    public void makeAutoCancelNoti(){
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
            //권한이 필요한 목록을 배열에 담는다.
            String[] permissions={Manifest.permission.POST_NOTIFICATIONS};
            //배열을 전달해서 해당 권한을 부여하도록 요청한다.
            ActivityCompat.requestPermissions(this,
                    permissions,
                    0); //요청의 아이디
            return;
        }
        //입력한 문자열을 읽어온다.
        String msg = inputMsg.getText().toString();
        createNotificationChannel();
        //알림을 클릭했을때 활성화시킬 액티비티 정보를 담고 있는 Intent 객체
        Intent intent = new Intent(this, DetailActivity.class);
        //액티비티를 실행하는데 새로운 태스크에서 실행되도록 한다(기존에 onStop() 에 머물러 있다면 제거하고 새로 시작)
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
        //intent에 msg라는 키값으로 String type을 담는다. 새로 시작된 액티비티에서 읽어낼 수 있다.
        intent.putExtra("msg", msg);

        //알림의 아이디 얻어내기 (값이 겹치지않게)
        int currentId = (int) (System.currentTimeMillis() / 1000);

        //인텐트 전달자 객체
        PendingIntent pendingIntent = PendingIntent.getActivity(this, currentId, intent, PendingIntent.FLAG_MUTABLE);

        //띄울 알림을 구성하기
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_NAME)
                .setSmallIcon(android.R.drawable.ic_btn_speak_now) //알림의 아이콘
                .setContentTitle("얘들아 나야~") //알림의 내용
                .setContentText(msg) //알림의 내용
                .setPriority(NotificationCompat.PRIORITY_DEFAULT) //알림의 우선순위
                .setContentIntent(pendingIntent) //인텐트 전달
                .setAutoCancel(true); //자동 취소되는 알림인지 여부

        //알림 만들기
        Notification noti=builder.build();

        //알림 매니저를 이용해서 알림을 띄운다.
        NotificationManagerCompat.from(this).notify(currentId, noti);
    }


    //앱의 사용자가 알림을 직접 관리 할수 있도록 알림 채널을 만들어야한다.
    public void createNotificationChannel(){
        //알림 채널을 지원하는 기기인지 확인해서
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //알림 채널을 만들기

            //셈플 데이터
            String name="삼성카드";
            String text="테스트!";
            //알림 채널 객체를 얻어내서
            NotificationChannel channel=
                    new NotificationChannel(CHANNEL_NAME, name, NotificationManager.IMPORTANCE_DEFAULT);
            //채널의 설명을 적고
            channel.setDescription(text);
            //알림 매니저 객체를 얻어내서
            NotificationManager notiManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            //알림 채널을 만든다.
            notiManager.createNotificationChannel(channel);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case 0:
                //권한을 부여 했다면
                if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    //자동 취소 알림 띄우기
                    makeAutoCancelNoti();
                }else{//권한을 부여 하지 않았다면
                    Toast.makeText(this, "알림을 띄울 권한이 필요합니다.",
                            Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
}

 

- 폰에 알림 띄우기!

- 자동 취소되는 알림 / 수동 취소되는 알림 띄우는 방법

 

 

- static final 상수로 "패키지명+채널명" 을 정의해준다.

- 패키지명은 모듈이 만들어진 패키지를 정확히 / 채널명은 마음대로 정하면 된다.

 

- 알림 채널을 지원하는 기기인지 확인해서 알림 채널을 만들어주기

 (if문 부분의 Build.version을 확인하는 코드)

 

 

- inputText 안에 msg라는 키값으로 들어온 값을 intent에 전달한다!

 

- 알림을 클릭했을 때 활성화시킬 액티비티 정보를 담고 있는 Intent 객체

 

 

- 이렇게 여러번 호출해서 쓸 수 있는 것은 리턴타입이 this이기 때문이다!

- NotificationCompat.Builder 객체를 사용한다.

 

- 클릭시 자동으로 사라지는 알림                                                                                                                 

- 권한 체크 요청(requestPermission) 을 하고, 승인되면

 

 

- 아래에서 이 메소드를 다시 호출하도록 한다.

 

 

- 그러면 inputMsg의 문자열을 읽어내고, 알림채널을 만들고 intent 객체로 전달한다.

- 지금은 MainActivity로 이동하도록 했는데 나중엔 다른 액티비티로 이동하도록 해볼 것!

 

- intent에 플래그 옵션을 지정해준 것이다.

 

- putExtra로 키값을 담으면 MainActivity에서 읽어낼 수 있다. (getStringExtra로)

 

 

- 알림의 아이디는 왜 필요할까?

→ 나중에 수동으로 취소하려면 알림별로 아이디를 지정해주어야 한다.

→ 그래서 값이 겹치면 안되어서 겹치지 않는 숫자를 임의로 얻어냈다(큰 정수값을 얻어내도록 함)

 

 

- PendingIntent 인텐트 전달자 객체에 intent를 담아서

 NotificationCompat.Builder 에 넣어준다.

 

 

- 주석으로 builder의 인자들 설명!

- setAutoCancel(true) 로 설정하면 알림을 읽는 순간(터치하면) 알림이 자동으로 사라진다.

 

Notification noti=builder.build();
NotificationManagerCompat.from(this).notify(currentId, noti);

- 이 builder.build() 가 notificaton 타입이다. 조금 풀어서 쓰면 이런 코드가 된다.

 

 

- 메시지를 보내면 기기에 알림을 보낼 수 있는지 승인을 요청하는 창이 뜬다.

 

 

 

- 위쪽 알림 바에 뭔가 생겨난 것을 볼 수 있다.

 

 

- 이렇게 알림이 뜬다. 알림을 클릭하면 다시 MainActifvity가 나타난다.

 

 

- 알림을 표시하려면 이렇게 permission이 설정되어 있어야 한다.

 

 

- 알림에 가보면 이렇게 알림 채널이 있다.

 

 

- 알림 채널 안에 들어가면 이렇게 알림채널에 대한 세부적인 설정을 할 수 있다.

 

 

- 여기서 알림채널의 이름을 설정한 것이다.

 

 

 

- 이름(name), 설명(text) 부분을 이렇게 수정하면 여기에 뜬다.

 

- 이렇게 NotificationChannel 객체를 따로 생성하지 않으면 알림이 오지 않는다!

 


 

- 액티비티 추가

 

DetailActivity

package com.example.step21notification;

import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class DetailActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        //전달된 intent 객체
        Intent intent = getIntent();
        //intent 객체에 "msg"라는 키값으로 전달된 문자열 얻어내기
        String msg=intent.getStringExtra("msg");
        //TextView에 출력해보기
        TextView textView=findViewById(R.id.textView);
        textView.setText(msg);
    }
}

 

activity_detail.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"
    tools:context="com.example.step21notification.DetailActivity"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:id="@+id/textView"/>
</LinearLayout>

 

 

- 이 intent를 detail Activity로 전달하기

- MainActivity에서 위와 같이 Intent 객체를 생성해서 값을 넣어주고,

  DetailActivity에서 .getIntent() 하면 된다.

 

 

 

- 입력받은 메시지(msg)가 DetailActivity에 출력된다!