Home Broad Cast Receiver
Post
Cancel

Broad Cast Receiver

Broadcast

안드로이드에서 브로드캐스팅 (BroadCasting)이란 메시지를 여러 객체에 전달하는 것을 말한다.

예를 들어 카카오톡에서 여러 사람에게 메시지를 전달할 때 그룹 채팅방을 만들어

메시지를 전달하는것을 생각해보자. 마찬가지로 안드로이드도 여러 앱 구성 요소에

메시지를 전달할 때 브로드 캐스팅을 사용한다.

우리가 만든 앱에서 브로드캐스팅 메시지를 받고 싶다면 브로드캐스트 수신자를

만들어 앱에 등록하면 된다.

브로드캐스트도 앱의 구성 요소이기 때문에 수신자를 만들면 새로 등록해야 시스템이 알 수 있다

Mainfest 파일에 등록하는 Service와는 달리,

Broadcast Recevier는 소스코드에서 registerReceiver 메서드를 사용해 시스템에 등록할 수 있다.

브로드 캐스트 수신자 동작 방식 2

출처 : Do it 안드로이드 프로그래밍


브로드 캐스트 수신자 등록 예시

브로드 캐스트 수신자에는 onReceive 메서드를 정의해야 한다.

이 메서드는 원하는 브로드캐스트 메시지가 도착하면 자동으로 호출된다.

시스템의 모든 메시지를 받을 수 없기 때문에 원하는 메시지만 받으려면

인텐트 필터를 사용해 시스템에 등록하면 된다.

1

위 사진같이 브로드캐스트 클래스를 만들어주자 Class Name은 SmsReceiver로 한다.

이렇게 하면 Manifest.xml 파일에 reciver태그가 자동으로 추가 되는데,

브로드캐스트 수신자를 등록하기 위해 아래 처럼 수정하자.

AndroidManifest.xml

1
2
3
4
5
6
7
8
 <receiver
            android:name=".SmsReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECIVED"/>
            </intent-filter>
        </receiver>

위의 intent-filter 태그는 어떤 인텐트를 받을 것인지 지정해 주고,

action 태그의 android.provider.Telephony.SMS_RECIVED는 메시지가 들어간 인텐트를

구분하기 위한 액션 정보이다. 즉, 단말에서 SMS를 수신했을 때 이 action 정보가 들어간

인텐트를 전달 하므로 이 값을 넣어주면 SMS를 받아 볼 수 있다.

인제 아래와 같이 SmsReceiver.java 파일을 수정해주자

SmsReceiver.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class SmsReceiver extends BroadcastReceiver {
    public static final String TAG = "SmsReceiver";
    
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive() 메서드 호출됨.");

        Bundle bundle = intent.getExtras(); // 인텐트에서 Bundle 객체 가져오기
        SmsMessage[] messages = parseSmsMessage(bundle);
        
        if(messages != null && messages.length > 0){
			// getOriginatingAddress() 발신자 번호 확인하는 메서드
            String sender = messages[0].getOriginatingAddress();
            Log.i(TAG, "SMS sender : " + sender);
            
            // 문자 내용을 확인하려면 getMessageBody().toString() 
            String contents = messages[0].getMessageBody();
            Log.i(TAG, "SMS contents : " + contents);
            
            Date receivedDate = new Date(messages[0].getTimestampMillis());
            Log.i(TAG, "SMS received date : " + receivedDate.toString());
        }
        throw new UnsupportedOperationException("Not yet implemented");
    }
    
    private SmsMessage[] parseSmsMessage(Bundle bundle){
        Object[] objs = (Object[]) bundle.get("pdus");
        SmsMessage[] messages = new SmsMessage[objs.length];
        
        int smsCount = objs.length;
        for(int i=0; i<smsCount; i++){
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                String format = bundle.getString("format");
                messages[i] = SmsMessage.createFromPdu((byte[]) objs[i], format);
            }else
                messages[i] = SmsMessage.createFromPdu((byte[]) objs[i]); 
        }
        return messages;
    }
}

위의 parseSmsMessage 메서드는 한 번 만들어 놓으면 다른 앱을 만들 때도 재사용할 수 있다.

왜냐하면 SMS 데이터를 확인할 수 있도록 안드로이드 API에 정해둔 코드이기 때문이다.

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)에서,

Build.VERSION_CODE에는 안드로이드 OS 버전별로 상수가 정의되어 있다.

M은 마시멜로 버전과 같거나 그 이후 버전일 때 중괄호 안의 코드를 실행하겠다는 뜻이다.

인제 SMS를 수신하려면 RECEIVE_SMS 권한이 있어야 한다.

아래와 같이 코드를 수정하자.

AndroidManifest.xml

1
2
3
4
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.techtown.recevier">

    <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>>

build.gradle(Module: SampleReceiver.app)

1
2
3
4
dependencies {
	...
    implementation 'com.yanzhenjie:permission:2.0.3'
}

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MainActivity extends AppCompatActivity {

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

        AndPermission.with(this)// 모든 위험 권한을 자동으로 부여하는 메서드 호출
                .runtime()
                .permission(Permission.RECEIVE_SMS)
                .onGranted(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> permissions) {
                        showToast("허용된 권한 갯수 : " + permissions.size());
                    }
                })
                .onDenied(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> permissions) {
                        showToast("거부된 권한 갯수 : " + permissions.size());
                    }
                })
                .start();

    }

    public void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }

}

인제 앱을 실행했을 때 메인 액티비티가 화면에 보이면 권한을 요청하는 대화상자가 나타난다.

2

Allow 버튼을 누르고 권한이 승인되고 SMS 받을 준비가 완료된다.

3

위 사진 처럼 메시지를 작성하고 SendMessage를 누르면 Logcat창에서,

onReceive 메서드가 호출되었다는 것을 알 수 있다.

SMS 내용 액티비티에 나타내기

app 폴더에서 New Activity -> Empty

4

만들어진 activity_main은 위 처럼 꾸미고 SmsActivity.java 파일을 아래와 같이 수정.

SmsActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class SmsActivity extends AppCompatActivity {
    EditText editText;
    EditText editText2;
    EditText editText3;

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

        editText = findViewById(R.id.editText);
        editText2 = findViewById(R.id.editText2);
        editText3 = findViewById(R.id.editText3);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish(); // 화면을 닫는다.
            }
        });
		
		// 전달 받은 인텐트를 처리 하는 processIntent 호출
        Intent passedIntent = getIntent();
        processIntent(passedIntent);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        processIntent(intent);

        super.onNewIntent(intent);
    }

    private void processIntent(Intent intent) {
			// Intent가 null이 아니면 그 안에 있는 부가 데이터를 화면에 보여주기
        if (intent != null) {
            String sender = intent.getStringExtra("sender");
            String contents = intent.getStringExtra("contents");
            String receivedDate = intent.getStringExtra("receivedDate");

            editText.setText(sender);
            editText2.setText(contents);
            editText3.setText(receivedDate);
        }
    }

}

수신한 SMS를 보여줄 화면까지 만들었으므로 SmsReceiver.java 파일을 열어

SmsActivity 인텐트를 전달하는 코드를 추가한다.

SmsReceiver.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class SmsReceiver extends BroadcastReceiver {
    private static final String TAG = "SmsReceiver";

    public SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive() 메서드 호출됨.");

        Bundle bundle = intent.getExtras();
        SmsMessage[] messages = parseSmsMessage(bundle);
        if (messages != null && messages.length > 0) {
            String sender = messages[0].getOriginatingAddress();
            Log.i(TAG, "SMS sender : " + sender);

            String contents = messages[0].getMessageBody();
            Log.i(TAG, "SMS contents : " + contents);

            Date receivedDate = new Date(messages[0].getTimestampMillis());
            Log.i(TAG, "SMS received date : " + receivedDate.toString());

            sendToActivity(context, sender, contents, receivedDate);
        }
    }

    private SmsMessage[] parseSmsMessage(Bundle bundle) {
        Object[] objs = (Object[]) bundle.get("pdus");

        SmsMessage[] messages = new SmsMessage[objs.length];
        int smsCount = objs.length;
        for (int i = 0; i < smsCount; i++) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                String format = bundle.getString("format");
                messages[i] = SmsMessage.createFromPdu((byte[]) objs[i], format);
            } else {
                messages[i] = SmsMessage.createFromPdu((byte[]) objs[i]);
            }
        }

        return messages;
    }

		/* SmsActivity로 인텐트를 보내기 위한 메서드 */
    private void sendToActivity(Context context, String sender, String contents, Date receivedDate) {
        Intent myIntent = new Intent(context, SmsActivity.class);
        myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_CLEAR_TOP);
        myIntent.putExtra("sender", sender);
        myIntent.putExtra("contents", contents);
        myIntent.putExtra("receivedDate", format.format(receivedDate));
        context.startActivity(myIntent);
    }

}
This post is licensed under CC BY 4.0 by the author.