* 우선 Broadcast Receiver 만들기!

 

[ 프로젝트이름 왼쪽클릭 -> New -> Other -> Broadcast Receiver 선택 -> 원하는 이름으로 설정]

의 과정을 거치면, AndroidManifest.xml에 자동으로 <receiver></receiver> 태그가 만들어진것을 볼 수 있다.

(해당 글에서는 리시버의 이름이 SmsReceiver.java 이다.)

 

브로드캐스트 리시버의 대표적인 예인 문자메시지 수신과 관련된 기능을 가진 어플을 만들어 볼 것이다.

 

이제, 매니페스트 파일에 리시버 태그안에 <intent-filter> 태그를 추가할 것이다.

해당 태그를 통해 원하는 수많은 브로드캐스팅 인텐트들 중에서 필요한, 원하는 인텐트에 대해서만 알림 받을 것을 시스템에 요청할 수 있다.

<receiver
	android:name=".SmsReceiver"
	android:enabled="true"
	android:exported="true">
	<intent-filter>
		<action android:name="android.provider.Telephony.SMS_RECEIVED" />
	</intent-filter>
</receiver>

위에서와 같이, <intent-filter>태그를 추가하여, SMS_RECEIVED액션, 즉 문자를 수신했을 경우에만

SmsReceiver 라는 이름의 브로드캐스트 리시버에게 알려달라! 라고 설정할 수 있습니다.

 

또한, 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="x.x.x">

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

위와 같이 <uses-permission>태그를 통해 SMS 수신과 관련된 권한을 가질 수 있도록 해줍니다.

또한, 마시멜로우 버전 이후부터는 해당 권한이 위험권한으로 바뀌어 앱 실행시 다시한번 사용자에게 권한요청을 받아야하는데, 우선은 편의상 자동으로 부여되도록 마시멜로우 이전 버전으로 바꿀 것이다.

(*** 마시멜로우 이후 버전에서 권한 부여하는법 - )

 

build.grade(Module:app) 에서 targetSdkVersion22로 낮춰주면 된다.(Sync now 버튼 클릭!)

 


 

이제 SmsReceiver.java의 코드를 살펴본다.

package x.x.mysmsreceiver;

import ...

public class SmsReceiver extends BroadcastReceiver { // BroadcastReceiver를 상속한다!!

    private static final String TAG = "SmsReceiver";
    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    @Override
    public void onReceive(Context context, Intent intent) {
        // sms가 오면 onReceive() 가 호출된다. 여기에 처리하는 코드 작성하면 된다.
        // Log.d(TAG, "onReceive() 호출됨.");

        Bundle bundle = intent.getExtras();
        // parseSmsMessage() 메서드의 코드들은 SMS문자의 내용을 뽑아내는 정형화된 코드이다.
        // 복잡해 보일 수 있으나 그냥 그대로 가져다 쓰면 된다.
        SmsMessage[] messages = parseSmsMessage(bundle);

        if(messages.length>0){
        	// 문자메세지에서 송신자와 관련된 내용을 뽑아낸다.
            String sender = messages[0].getOriginatingAddress();
            Log.d(TAG, "sender: "+sender);

			// 문자메세지 내용 추출
            String contents = messages[0].getMessageBody().toString();
            Log.d(TAG, "contents: "+contents);

			// 수신 날짜/시간 데이터 추출
            Date receivedDate = new Date(messages[0].getTimestampMillis());
            Log.d(TAG, "received date: "+receivedDate);

			// 해당 내용을 모두 합쳐서 액티비티로 보낸다.
            sendToActivity(context, sender+'\n'+contents+'\n'+format.format(receivedDate));
        }
    }

    private void sendToActivity(Context context, String str){
        Intent intent = new Intent(context, SmsActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra("string", str);
        context.startActivity(intent);
    }

	// 정형화된 코드. 그냥 가져다 쓰면 된다.
    private SmsMessage[] parseSmsMessage(Bundle bundle){
        Object[] objs = (Object[])bundle.get("pdus");
        SmsMessage[] messages = new SmsMessage[objs.length];

        for(int i=0;i<objs.length;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;
    }
}

 

위의 코드를 보면 알 수 있지만, SMS를 받으면 관련 내용을 string 형태로 뽑아내서 인텐트 객체에 담은 다음에,

startActivity(인텐트)를 통해서 SmsActivity에게 전달하며 액티비티를 시작시킨다.

 


 

이제 SmsActivity.java의 소스코드를 보자.

 

package x.x.mysmsreceiver;

import ...

public class SmsActivity extends AppCompatActivity {

    EditText editText;
    Button button;

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

        editText = (EditText)findViewById(R.id.editText);
        button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
		
        // (1) 리시버에 의해 해당 액티비티가 새롭게 실행된 경우
        Intent passedIntent = getIntent();
        processIntent(passedIntent);
    }

    /** 얘가 중요 **/
    private void processIntent(Intent intent){
        if(intent != null){
            // 인텐트에서 전달된 데이터를 추출하여, 활용한다.(여기서는 edittext를 통하여 내용을 화면에 뿌려주었다.)
            String string = intent.getStringExtra("string");
            editText.setText(string);
        }
    }

    // (2) 이미 실행된 상태였는데 리시버에 의해 다시 켜진 경우
    // (이러한 경우 onCreate()를 거치지 않기 때문에 이렇게 오버라이드 해주어야 모든 경우에 SMS문자가 처리된다!
    @Override
    protected void onNewIntent(Intent intent) {
        processIntent(intent);

        super.onNewIntent(intent);
    }
}

이렇게 하면, 어플이 켜져있는 상태든 꺼져있는 상태든

SMS문자가 수신되면 어플이 켜지고 해당 내용이 전달되게 된다.

 

(실행예시) (에뮬레이터에서는 '...' 버튼 -> phone 을 통해 자기자신에게 문자를 보낼 수 있다.)

메세지를 보내기 전의 상황. 'clear all'을 통해 켜져있는 어플을 모두 끈 상태이다. 이제 'SEND MESSAGE' 버튼을 통해 문자를 보낸다.

 

문자를 수신했다는 기본 안드로이드 알람이 위에 떠있는 것을 볼 수 있다.  그와 동시에 우리가 만든 어플이 실행되면서,  문자의 송신자/내용/시간정보 내용이 edittext를 통해 보여지는 것을 확인할 수 있다.

 

+ Recent posts