* 우선 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) 에서 targetSdkVersion을 22로 낮춰주면 된다.(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 을 통해 자기자신에게 문자를 보낼 수 있다.)
'프로그래밍 > 안드로이드 앱 프로그래밍' 카테고리의 다른 글
[Android] ViewPager 화면 사라짐 현상 해결법! (1) | 2019.12.12 |
---|---|
[안드로이드] 위험권한 부여하기(마시멜로우(sdk23)이후) (0) | 2019.04.24 |
[안드로이드] Service 활용하기(백그라운드 실행) (2) | 2019.04.19 |
액티비티 수명주기 - SharedPreferences를 활용한 데이터 저장 및 복구(onPause/onResume) (0) | 2019.04.19 |
[Android] 버튼 선택여부에 따라 다른 drawable 설정, 이벤트 처리 (0) | 2019.02.08 |