반응형
모든 내용은 Do it! 안드로이드 앱 프로그래밍을 바탕으로 정리한 것입니다.
브로드캐스트 수신자(Broadcast Receiver)
브로드캐스팅(Broadcasting) : 메시지를 여러 객체에 전달하는 것
→ 안드로이드는 여러 앱 구성 요소에 메시지를 전달할 때 브로드캐스팅을 사용함 (앱과 앱 사이, 앱과 시스템 사이의 이벤트 전달)
- 안드로이드 4대 앱 구성 요소 중 하나
- AndroidManifest 파일에 등록해야 시스템이 알 수 있고 화면도 없게 됨
- 매니페스트 등록 방식이 아닌 소스코드에서 registerReceiver() 메서드를 사용해서 시스템에 등록할 수 있음
브로드캐스트 수신자 등록하고 사용하기
<manifest...>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application
...>
<activity android:name=".SmsActivity"/>
<receiver
android:name=".SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
- 브로드캐스트 수신자는 <receiver> 태그 안에 <intent-filter> 태그를 넣어 어떤 인텐트를 받을 것인지 지정
- <intent-filter> 태그 안에 <action> 태그의 name 속성 값으로 android.provider.Telephony.SMS_RECEIVED
- SMS 메시지가 들어간 인텐트를 구분하기 위한 액션 정보임
- SMS을 수신하기 위해서는 RECEIVE_SMS 권한이 필요함
- <uses-permission> 태그를 추가하여 위험 권한을 추가함
- build.gradle(Module:app)의 dependencies에 간단하게 위험 권한을 추가할 수 있는 외부 라이브러리 (com.github.gedroSG94:AutoPermissions:1.0.3)와 maven url (https://jitpack.io)를 싱크함
MainActivity.java
- AutoPermissionsListener 인터페이스를 상속 받아 구현함
- AndroidManifest에서 필요한 권한들을 추가하면 최초 실행 시 자동으로 권한 요청을 띄우고 승인 결과를 알 수 있음
- onDenied → 거절, onGranted → 승인
public class MainActivity extends AppCompatActivity implements AutoPermissionsListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoPermissions.Companion.loadAllPermissions(this, 101);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
AutoPermissions.Companion.parsePermissions(this, requestCode, permissions, this);
}
@Override
public void onDenied(int i, String[] permissions) {
Toast.makeText(this, "permission denied : "+permissions.length, Toast.LENGTH_SHORT).show();
}
@Override
public void onGranted(int i, String[] permissions) {
Toast.makeText(this, "permission granted : "+permissions.length, Toast.LENGTH_SHORT).show();
}
}
SmsActivity.java
전달받은 메세지를 띄우는 액티비티
public class SmsActivity extends AppCompatActivity {
TextView textView1, textView2, textView3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sms);
textView1 = findViewById(R.id.edittext_sender);
textView2 = findViewById(R.id.edittext_content);
textView3 = findViewById(R.id.edittext_time);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
Intent passedIntent = getIntent();
processIntent(passedIntent);
}
@Override
protected void onNewIntent(Intent intent) {
processIntent(intent);
super.onNewIntent(intent);
}
private void processIntent(Intent intent) {
if (intent != null) {
String sender = intent.getStringExtra("sender");
String contents = intent.getStringExtra("contents");
String receivedDate = intent.getStringExtra("receivedDate");
textView1.setText(sender);
textView2.setText(contents);
textView3.setText(receivedDate);
}
}
}
SmsReceiver.java
- SMS를 받으면 onReceive() 메서드가 자동 호출됨
- 파라미터로 전달되는 인텐트(Intent) 객체 안에 SMS 데이터가 들어 있음
- 인텐트 객체 안에 번들(Bundle) 객체 안에 부가 데이터가 들어 있음
public class SmsReceiver extends BroadcastReceiver {
public 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.d(TAG, "onReceive() 메서드 호출됨.");
// 인텐트에서 Bundle 객체를 가져옴
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) {
// Bundle 객체의 부가 데이터 중에서 pdus 가져옴
Object[] objects = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[objects.length];
int smsCount = objects.length;
for(int i = 0; i < smsCount; i++) {
// OS 버전에 따라 다른 방식으로 호출
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String format = bundle.getString("format");
messages[i] = SmsMessage.createFromPdu((byte[]) objects[i], format);
} else {
messages[i] = SmsMessage.createFromPdu((byte[]) objects[i]);
}
}
return messages;
}
private void sendToActivity(Context context, String sender, String contents, Date receivedDate) {
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("sender", sender);
intent.putExtra("contents", contents);
intent.putExtra("receivedDate", format.format(receivedDate));
context.startActivity(intent);
}
}
- 받은 SMS 내용을 인텐트로 전달함 → sendToActivity()
- 브로드캐스트 수신자는 화면이 없기 때문에 인텐트의 플래그로 FLAG_ACTIVITY_NEW_TASK를 추가해야 함
- 이미 메모리에 만든 SmsActivity가 있을 때 액티비티를 중복 생성하지 않도록 FLAG_ACTIVITY_SINGLE_TOP을 추가함
- 매니페스트 파일에 <receiver> 태그로 등록하지 않고 registerReceiver() 메서드를 사용해 등록할 수 있음
- 소스 파일에서 등록하면 화면이 사용자에게 보일 때만 브로드캐스트 수신자에서 메시지를 받도록 할 수 있음
브로드캐스트 수신자 정리
- 단말에서 SMS 문자를 받았을 때, 텔레포니(Telephony) 모듈이 처리함
- 이렇게 처리된 정보는 인텐트에 담겨 브로드캐스팅 방식으로 다른 앱에 전달
- 인텐트를 전달 받았을 때 onReceive() 메서드가 자동 호출
- 위의 예제에서는 SmsReceiver 객체에서 인텐트 안의 데이터를 확인하고 SmsActivity로 인텐트를 전달
- 앱 A가 실행되어 있지 않아도 앱 A가 원하는 브로드캐스트 메세지가 도착하면 앱 B를 실행하고 있는 도중에 A가 실행될 수 있음
- 동일한 SMS 수신 앱 여러 개를 수정하여 만들어 설치하면 어느 앱에서 생긴 오류인지 찾기 어려움
- 새 개발 버전의 앱을 만들었을 경우에는 구 개발 버전의 앱을 삭제하는 것이 좋음
*인텐트(Intent)와 플래그(flag), 부가 데이터(Extra data)에 관한 내용은 아래 포스팅 참고!
반응형
'ANDROID > Android 앱 프로그래밍' 카테고리의 다른 글
[Android] 핸들러(Handler)로 실행 지연시키기 (0) | 2021.06.21 |
---|---|
[Android] 핸들러(Handler) (0) | 2021.06.17 |
[Android] 매니페스트(Manifest), 리소스(Resource) 그리고 그래들(Gradle) (0) | 2021.06.16 |
[Android] 위험 권한(Permission) 부여하기 (0) | 2021.06.15 |
[Android] 서비스(Service) (0) | 2021.06.09 |
[Android] 탭(Tab)과 바텀 내비게이션(Bottom Navigation) (0) | 2021.06.08 |
[Android] 프래그먼트(Fragment) (0) | 2021.05.31 |
[Android] 간단한 값 저장은 SharedPreferences (0) | 2021.05.27 |
댓글